diff options
author | Andreas Baumann <mail@andreasbaumann.cc> | 2015-01-03 13:58:15 +0100 |
---|---|---|
committer | Andreas Baumann <mail@andreasbaumann.cc> | 2015-01-03 13:58:15 +0100 |
commit | 4aca87515a5083ae0e31ce3177189fd43b6d05ac (patch) | |
tree | 7b1d9a31393ca090757dc6f0d3859b4fcd93f271 /release/src/linux/linux | |
parent | 008d0be72b2f160382c6e880765e96b64a050c65 (diff) | |
download | tomato-4aca87515a5083ae0e31ce3177189fd43b6d05ac.tar.gz tomato-4aca87515a5083ae0e31ce3177189fd43b6d05ac.tar.bz2 |
patch to Vanilla Tomato 1.28
Diffstat (limited to 'release/src/linux/linux')
368 files changed, 77757 insertions, 3476 deletions
diff --git a/release/src/linux/linux/.config b/release/src/linux/linux/.config index bae6dc5a..6334c2f4 100644 --- a/release/src/linux/linux/.config +++ b/release/src/linux/linux/.config @@ -1,5 +1,5 @@ # -# Automatically generated by make menuconfig: don't edit +# Automatically generated make config: don't edit # CONFIG_MIPS=y CONFIG_MIPS32=y @@ -152,6 +152,10 @@ CONFIG_MTD=y CONFIG_MTD_PARTITIONS=y # CONFIG_MTD_CONCAT is not set # CONFIG_MTD_REDBOOT_PARTS is not set + +# +# User Modules And Translation Layers +# CONFIG_MTD_CHAR=y # CONFIG_MTD_BLOCK is not set CONFIG_MTD_BLOCK_RO=y @@ -207,6 +211,10 @@ CONFIG_MTD_SFLASH=y # CONFIG_MTD_SLRAM is not set # CONFIG_MTD_MTDRAM is not set # CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# # CONFIG_MTD_DOC1000 is not set # CONFIG_MTD_DOC2000 is not set # CONFIG_MTD_DOC2001 is not set @@ -274,7 +282,8 @@ CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set # CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y CONFIG_IP_MROUTE=y # CONFIG_IP_PIMSM_V1 is not set # CONFIG_IP_PIMSM_V2 is not set @@ -286,71 +295,102 @@ CONFIG_SYN_COOKIES=y # IP: Netfilter Configuration # CONFIG_IP_NF_CONNTRACK=y -CONFIG_IP_NF_FTP=y +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_CONNTRACK_MARK=y +CONFIG_IP_NF_H323=m CONFIG_IP_NF_TFTP=y -CONFIG_IP_NF_H323=y # CONFIG_IP_NF_IRC is not set -CONFIG_IP_NF_RTSP=y +# CONFIG_IP_NF_CUSEEME is not set +# CONFIG_IP_NF_QUAKE3 is not set +CONFIG_IP_NF_RTSP=m # CONFIG_IP_NF_MMS is not set -CONFIG_IP_NF_SIP=y -CONFIG_IP_NF_CT_PROTO_GRE=y -CONFIG_IP_NF_PPTP=y -CONFIG_IP_NF_CT_PROTO_ESP=y +CONFIG_IP_NF_CT_PROTO_GRE=m +CONFIG_IP_NF_PPTP=m +CONFIG_IP_NF_SIP=m +# CONFIG_IP_NF_CT_PROTO_ESP is not set # CONFIG_IP_NF_QUEUE is not set CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_LIMIT=y +CONFIG_IP_NF_MATCH_IPP2P=m +# CONFIG_IP_NF_MATCH_GEOIP is not set +# CONFIG_IP_NF_MATCH_QUOTA is not set +CONFIG_IP_NF_MATCH_IPRANGE=y # CONFIG_IP_NF_POOL is not set CONFIG_IP_NF_MATCH_MAC=y # CONFIG_IP_NF_MATCH_PKTTYPE is not set CONFIG_IP_NF_MATCH_MARK=y -# CONFIG_IP_NF_MATCH_MULTIPORT is not set -# CONFIG_IP_NF_MATCH_MPORT is not set -CONFIG_IP_NF_MATCH_TOS=y -CONFIG_IP_NF_MATCH_TIME=y +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_MPORT=y +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +# CONFIG_IP_NF_MATCH_ACCOUNT is not set +CONFIG_IP_NF_MATCH_CONDITION=m +CONFIG_IP_NF_MATCH_TIME=m # CONFIG_IP_NF_MATCH_ECN is not set -# CONFIG_IP_NF_MATCH_DSCP is not set +CONFIG_IP_NF_MATCH_DSCP=m # CONFIG_IP_NF_MATCH_AH_ESP is not set -# CONFIG_IP_NF_MATCH_LENGTH is not set +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_U32=m # CONFIG_IP_NF_MATCH_TTL is not set CONFIG_IP_NF_MATCH_TCPMSS=y # CONFIG_IP_NF_MATCH_HELPER is not set CONFIG_IP_NF_MATCH_STATE=y +CONFIG_IP_NF_MATCH_CONNLIMIT=y +CONFIG_IP_NF_MATCH_CONNMARK=y # CONFIG_IP_NF_MATCH_CONNTRACK is not set # CONFIG_IP_NF_MATCH_UNCLEAN is not set -CONFIG_IP_NF_MATCH_WEBSTR=y +# CONFIG_IP_NF_MATCH_STRING is not set +# CONFIG_IP_NF_MATCH_WEBSTR is not set # CONFIG_IP_NF_MATCH_OWNER is not set +CONFIG_IP_NF_MATCH_LAYER7=m +# CONFIG_IP_NF_MATCH_LAYER7_DEBUG is not set +CONFIG_IP_NF_MATCH_WEB=m +CONFIG_IP_NF_TARGET_BCOUNT=y +CONFIG_IP_NF_MATCH_BCOUNT=y +# CONFIG_IP_NF_TARGET_MACSAVE is not set +# CONFIG_IP_NF_MATCH_MACSAVE is not set +# CONFIG_IP_NF_MATCH_EXP is not set CONFIG_IP_NF_FILTER=y CONFIG_IP_NF_TARGET_REJECT=y # CONFIG_IP_NF_TARGET_MIRROR is not set CONFIG_IP_NF_NAT=y CONFIG_IP_NF_NAT_NEEDED=y CONFIG_IP_NF_TARGET_MASQUERADE=y -CONFIG_IP_NF_TARGET_REDIRECT=y -CONFIG_IP_NF_AUTOFW=y +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_NAT_H323=m +# CONFIG_IP_NF_AUTOFW is not set CONFIG_IP_NF_TARGET_TRIGGER=y -CONFIG_IP_NF_NAT_H323=y -CONFIG_IP_NF_NAT_PPTP=y -CONFIG_IP_NF_NAT_SIP=y -CONFIG_IP_NF_NAT_PROTO_GRE=y +CONFIG_IP_NF_NAT_PPTP=m +CONFIG_IP_NF_NAT_SIP=m +CONFIG_IP_NF_NAT_PROTO_GRE=m # CONFIG_IP_NF_NAT_LOCAL is not set # CONFIG_IP_NF_NAT_SNMP_BASIC is not set -CONFIG_IP_NF_NAT_FTP=y +CONFIG_IP_NF_NAT_RTSP=m +CONFIG_IP_NF_NAT_FTP=m CONFIG_IP_NF_NAT_TFTP=y -CONFIG_IP_NF_NAT_RTSP=y -CONFIG_IP_NF_NAT_PROTO_ESP=y CONFIG_IP_NF_MANGLE=y -CONFIG_IP_NF_TARGET_TOS=y +CONFIG_IP_NF_TARGET_TOS=m # CONFIG_IP_NF_TARGET_ECN is not set -CONFIG_IP_NF_TARGET_DSCP=y +CONFIG_IP_NF_TARGET_DSCP=m CONFIG_IP_NF_TARGET_MARK=y +CONFIG_IP_NF_TARGET_ROUTE=m +CONFIG_IP_NF_TARGET_CLASSIFY=m +CONFIG_IP_NF_TARGET_IMQ=m CONFIG_IP_NF_TARGET_LOG=y +CONFIG_IP_NF_TARGET_CONNMARK=y +CONFIG_IP_NF_TARGET_TTL=m # CONFIG_IP_NF_TARGET_ULOG is not set CONFIG_IP_NF_TARGET_TCPMSS=y # CONFIG_IP_NF_ARPTABLES is not set +CONFIG_IP_NF_TOMATOCT=m # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set CONFIG_VLAN_8021Q=y + +# +# +# # CONFIG_IPX is not set # CONFIG_ATALK is not set @@ -393,27 +433,29 @@ CONFIG_BRIDGE=y # QoS and/or fair queueing # CONFIG_NET_SCHED=y -CONFIG_NET_SCH_CBQ=y +# CONFIG_NET_SCH_CBQ is not set CONFIG_NET_SCH_HTB=y # CONFIG_NET_SCH_CSZ is not set +CONFIG_NET_SCH_HFSC=m CONFIG_NET_SCH_PRIO=y # CONFIG_NET_SCH_RED is not set CONFIG_NET_SCH_SFQ=y +CONFIG_NET_SCH_ESFQ=m # CONFIG_NET_SCH_TEQL is not set -# CONFIG_NET_SCH_TBF is not set +CONFIG_NET_SCH_TBF=m # CONFIG_NET_SCH_GRED is not set # CONFIG_NET_SCH_DSMARK is not set -# CONFIG_NET_SCH_INGRESS is not set +CONFIG_NET_SCH_INGRESS=y CONFIG_NET_QOS=y CONFIG_NET_ESTIMATOR=y CONFIG_NET_CLS=y # CONFIG_NET_CLS_TCINDEX is not set # CONFIG_NET_CLS_ROUTE4 is not set -# CONFIG_NET_CLS_FW is not set +CONFIG_NET_CLS_FW=y CONFIG_NET_CLS_U32=y # CONFIG_NET_CLS_RSVP is not set # CONFIG_NET_CLS_RSVP6 is not set -# CONFIG_NET_CLS_POLICE is not set +CONFIG_NET_CLS_POLICE=y # # Network testing @@ -467,7 +509,7 @@ CONFIG_WL_AP="wlconfig_lx_router_ap" CONFIG_WL_STA="wlconfig_lx_router_sta" CONFIG_WL_APSTA="wlconfig_lx_router_apsta" CONFIG_WL_DNGL="wlconfig_lx_router_dongle" -CONFIG_WL_LINK="AP" +CONFIG_WL_LINK="APSTA" # # ARCnet devices @@ -476,7 +518,8 @@ CONFIG_WL_LINK="AP" # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set +CONFIG_IMQ=m +CONFIG_TUN=m # CONFIG_ETHERTAP is not set # @@ -610,6 +653,14 @@ CONFIG_UNIX98_PTY_COUNT=16 # Joysticks # # CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# # CONFIG_QIC02_TAPE is not set # @@ -655,9 +706,11 @@ CONFIG_UNIX98_PTY_COUNT=16 # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set # CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -CONFIG_CRAMFS=y +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_CRAMFS is not set CONFIG_SQUASHFS=y +# CONFIG_SQUASHFS_EMBEDDED is not set # CONFIG_TMPFS is not set CONFIG_RAMFS=y # CONFIG_ZLIB_FS_INFLATE is not set @@ -701,6 +754,9 @@ CONFIG_DEVFS_MOUNT=y # CONFIG_NFSD_TCP is not set # CONFIG_SUNRPC is not set # CONFIG_LOCKD is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_POSIX is not set # CONFIG_SMB_FS is not set # CONFIG_NCP_FS is not set # CONFIG_NCPFS_PACKET_SIGNING is not set @@ -729,7 +785,49 @@ CONFIG_PARTITION_ADVANCED=y # CONFIG_SUN_PARTITION is not set # CONFIG_EFI_PARTITION is not set # CONFIG_SMB_NLS is not set -# CONFIG_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set # # Multimedia devices @@ -771,5 +869,5 @@ CONFIG_MAGIC_SYSRQ=y # # Library routines # -CONFIG_ZLIB_INFLATE=y -# CONFIG_ZLIB_DEFLATE is not set +CONFIG_ZLIB_INFLATE=m +CONFIG_ZLIB_DEFLATE=m diff --git a/release/src/linux/linux/Documentation/Configure.help b/release/src/linux/linux/Documentation/Configure.help index 9d556610..1f6261d7 100644 --- a/release/src/linux/linux/Documentation/Configure.help +++ b/release/src/linux/linux/Documentation/Configure.help @@ -232,23 +232,23 @@ CONFIG_CRIS Unsynced TSC support CONFIG_X86_TSC_DISABLE - This option is used for getting Linux to run on a NUMA multi-node - boxes, laptops and other systems suffering from unsynced TSCs or - TSC drift, which can cause gettimeofday to return non-monotonic values. + This option is used for getting Linux to run on a NUMA multi-node + boxes, laptops and other systems suffering from unsynced TSCs or + TSC drift, which can cause gettimeofday to return non-monotonic values. Choosing this option will disable the CONFIG_X86_TSC optimization, - and allows you to then specify "notsc" as a boot option regardless of - which processor you have compiled for. - + and allows you to then specify "notsc" as a boot option regardless of + which processor you have compiled for. + NOTE: If your system hangs when init should run, you are probably - using a i686 compiled glibc which reads the TSC without checking for - availability. Boot without "notsc" and install a i386 compiled glibc + using a i686 compiled glibc which reads the TSC without checking for + availability. Boot without "notsc" and install a i386 compiled glibc to solve the problem. If unsure, say N. Multiquad support for NUMA systems CONFIG_MULTIQUAD - This option is used for getting Linux to run on a (IBM/Sequent) NUMA + This option is used for getting Linux to run on a (IBM/Sequent) NUMA multiquad box. This changes the way that processors are bootstrapped, and uses Clustered Logical APIC addressing mode instead of Flat Logical. You will need a new lynxer.elf file to flash your firmware with - send @@ -1428,8 +1428,8 @@ CONFIG_BLK_DEV_FALCON_IDE Amiga Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL) CONFIG_BLK_DEV_BUDDHA - This is the IDE driver for the IDE interfaces on the Buddha, - Catweasel and X-Surf expansion boards. It supports up to two interfaces + This is the IDE driver for the IDE interfaces on the Buddha, + Catweasel and X-Surf expansion boards. It supports up to two interfaces on the Buddha, three on the Catweasel and two on the X-Surf. Say Y if you have a Buddha or Catweasel expansion board and want to @@ -2145,7 +2145,7 @@ CONFIG_SIBYTE_CFE_CONSOLE configured. Support SWARM (BCM912500A) peripherals -CONFIG_SIBYTE_SWARM +CONFIG_SIBYTE_SWARM Indicates that the target is a SWARM board. Most devices (IDE, video decoder, audio codec, etc) still require additional configuration options under the appropriate sections. @@ -2280,7 +2280,7 @@ CONFIG_TC # Choice: galileo_clock 75 CONFIG_SYSCLK_75 - Configure the kernel for clock speed of your Galileo board. + Configure the kernel for clock speed of your Galileo board. The choices are 75MHz, 83.3MHz, and 100MHz. 83.3 @@ -2620,6 +2620,33 @@ CONFIG_IP_NF_IRC If you want to compile it as a module, say 'M' here and read Documentation/modules.txt. If unsure, say 'N'. +Per connection mark support +CONFIG_IP_NF_CONNTRACK_MARK + This option enables support for connection marks, used by the + `CONNMARK' target and `connmark' match. Similar to the mark value + of packets, but this mark value is kept in the conntrack session + instead of the individual packets. + +CONNMARK target support +CONFIG_IP_NF_TARGET_CONNMARK + This option adds a `CONNMARK' target, which allows one to manipulate + the connection mark value. Similar to the MARK target, but + affects the connection mark value rather than the packet mark value. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. The module will be called + ipt_CONNMARK.o. If unsure, say `N'. + +connmark match support +CONFIP_IP_NF_MATCH_CONNMARK + This option adds a `connmark' match, which allows you to match the + connection mark value previously set for the session by `CONNMARK'. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. The module will be called + ipt_connmark.o. If unsure, say `N'. + + FTP protocol support CONFIG_IP_NF_FTP Tracking FTP connections is problematic: special helpers are @@ -2629,6 +2656,16 @@ CONFIG_IP_NF_FTP If you want to compile it as a module, say M here and read <file:Documentation/modules.txt>. If unsure, say `Y'. +H.323 (netmeeting) support +CONFIG_IP_NF_H323 + H.323 is a standard signalling protocol used by teleconferencing + softwares like netmeeting. With the ip_conntrack_h323 and + the ip_nat_h323 modules you can support the protocol on a connection + tracking/NATing firewall. + + If you want to compile it as a module, say 'M' here and read + Documentation/modules.txt. If unsure, say 'N'. + User space queueing via NETLINK CONFIG_IP_NF_QUEUE Netfilter has the ability to queue packets to user space: the @@ -2641,19 +2678,22 @@ IP tables support (required for filtering/masq/NAT) CONFIG_IP_NF_IPTABLES iptables is a general, extensible packet identification framework. The packet filtering and full NAT (masquerading, port forwarding, - etc) subsystems now use this: say 'Y' or 'M' here if you want to use + etc) subsystems now use this: say `Y' or `M' here if you want to use either of those. If you want to compile it as a module, say M here and read <file:Documentation/modules.txt>. If unsure, say `N'. -RTSP protocol support -CONFIG_IP_NF_RTSP - Support the RTSP protocol. This allows UDP transports to be setup - properly, including RTP and RDT. +recent match support +CONFIG_IP_NF_MATCH_RECENT + This match is used for creating one or many lists of recently + used addresses and then matching against that/those list(s). - If you want to compile it as a module, say 'M' here and read - Documentation/modules.txt. If unsure, say 'Y'. + Short options are available by using 'iptables -m recent -h' + Official Website: <http://snowman.net/projects/ipt_recent/> + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. limit match support CONFIG_IP_NF_MATCH_LIMIT @@ -2664,14 +2704,21 @@ CONFIG_IP_NF_MATCH_LIMIT If you want to compile it as a module, say M here and read <file:Documentation/modules.txt>. If unsure, say `N'. +quota match support +CONFIG_IP_NF_MATCH_QUOTA + This match implements network quotas. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + skb->pkt_type packet match support CONFIG_IP_NF_MATCH_PKTTYPE This patch allows you to match packet in accrodance to its "class", eg. BROADCAST, MULTICAST, ... - + Typical usage: iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG - + If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. @@ -2701,6 +2748,14 @@ CONFIG_IP_NF_MATCH_MULTIPORT If you want to compile it as a module, say M here and read <file:Documentation/modules.txt>. If unsure, say `N'. +Multiple port with ranges match support +CONFIG_IP_NF_MATCH_MPORT + This is an enhanced multiport match which supports port + ranges as well as single ports. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + TTL match support CONFIG_IP_NF_MATCH_TTL This adds CONFIG_IP_NF_MATCH_TTL option, which enabled the user @@ -2709,6 +2764,18 @@ CONFIG_IP_NF_MATCH_TTL If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. +U32 patch support +CONFIG_IP_NF_MATCH_U32 + U32 allows you to extract quantities of up to 4 bytes from a packet, + AND them with specified masks, shift them by specified amounts and + test whether the results are in any of a set of specified ranges. + The specification of what to extract is general enough to skip over + headers with lengths stored in the packet, as in IP or TCP header + lengths. + + Details and examples are in the kernel module source. + + LENGTH match support CONFIG_IP_NF_MATCH_LENGTH This option allows you to match the length of a packet against a @@ -2717,6 +2784,18 @@ CONFIG_IP_NF_MATCH_LENGTH If you want to compile it as a module, say M here and read <file:Documentation/modules.txt>. If unsure, say `N'. +TIME patch support +CONFIG_IP_NF_MATCH_TIME + This option adds a `time' match, which allows you + to match based on the packet arrival time/date + (arrival time/date at the machine which netfilter is running on) or + departure time/date (for locally generated packets). + + If you say Y here, try iptables -m time --help for more information. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + AH/ESP match support CONFIG_IP_NF_MATCH_AH_ESP These two match extensions (`ah' and `esp') allow you to match a @@ -2735,7 +2814,7 @@ CONFIG_IP_NF_MATCH_DSCP If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. - + ECN match support CONFIG_IP_NF_MATCH_ECN @@ -2745,7 +2824,7 @@ CONFIG_IP_NF_MATCH_ECN If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. - + TOS match support CONFIG_IP_NF_MATCH_TOS @@ -2755,6 +2834,43 @@ CONFIG_IP_NF_MATCH_TOS If you want to compile it as a module, say M here and read <file:Documentation/modules.txt>. If unsure, say `N'. +IPP2P match support +CONFIG_IP_NF_MATCH_IPP2P + This option makes possible to match some P2P packets + therefore helps controlling such traffic. + + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. If unsure, say `N'. + +geoip match support +CONFIG_IP_NF_MATCH_GEOIP + This option allows you to match a packet by its source or + destination country. Basically, you need a country's + database containing all subnets and associated countries. + + For the complete procedure and understanding, read : + http://people.netfilter.org/peejix/geoip/howto/geoip-HOWTO.html + + + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. If unsure, say `N'. + +Condition variable match support +CONFIG_IP_NF_MATCH_CONDITION + This option allows you to match firewall rules against condition + variables stored in the /proc/net/ipt_condition directory. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + +iprange match support +CONFIG_IP_NF_MATCH_IPRANGE + This option makes possible to match IP addresses against + IP address ranges. + + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. If unsure, say `N'. + conntrack match support CONFIG_IP_NF_MATCH_CONNTRACK This is a general conntrack match module, a superset of the state match. @@ -2776,6 +2892,22 @@ CONFIG_IP_NF_MATCH_STATE If you want to compile it as a module, say M here and read <file:Documentation/modules.txt>. If unsure, say `N'. +Connections/IP limit match support +CONFIG_IP_NF_MATCH_CONNLIMIT + This match allows you to restrict the number of parallel TCP + connections to a server per client IP address (or address block). + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + +String match support (EXPERIMENTAL) +CONFIG_IP_NF_MATCH_STRING + String matching alows you to match packets which contain a + specified string of characters. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + Unclean match support CONFIG_IP_NF_MATCH_UNCLEAN Unclean packet matching matches any strange or invalid packets, by @@ -2820,7 +2952,7 @@ CONFIG_IP_NF_TARGET_MIRROR Local NAT support CONFIG_IP_NF_NAT_LOCAL - This option enables support for NAT of locally originated connections. + This option enables support for NAT of locally originated connections. Enable this if you need to use destination NAT on connections originating from local processes on the nat box itself. @@ -2897,12 +3029,12 @@ CONFIG_IP_NF_TARGET_DSCP If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. - + ECN target support CONFIG_IP_NF_TARGET_ECN This option adds a `ECN' target, which can be used in the iptables mangle - table. + table. You can use this target to remove the ECN bits from the IPv4 header of an IP packet. This is particularly useful, if you need to work around @@ -2912,7 +3044,7 @@ CONFIG_IP_NF_TARGET_ECN If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. - + TOS target support CONFIG_IP_NF_TARGET_TOS @@ -2923,6 +3055,22 @@ CONFIG_IP_NF_TARGET_TOS If you want to compile it as a module, say M here and read <file:Documentation/modules.txt>. If unsure, say `N'. +IMQ target support +CONFIG_IP_NF_TARGET_IMQ + This option adds a `IMQ' target which is used to specify if and + to which imq device packets should get enqueued/dequeued. + + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. If unsure, say `N'. + +IMQ target support +CONFIG_IP6_NF_TARGET_IMQ + This option adds a `IMQ' target which is used to specify if and + to which imq device packets should get enqueued/dequeued. + + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. If unsure, say `N'. + MARK target support CONFIG_IP_NF_TARGET_MARK This option adds a `MARK' target, which allows you to create rules @@ -2935,6 +3083,21 @@ CONFIG_IP_NF_TARGET_MARK If you want to compile it as a module, say M here and read <file:Documentation/modules.txt>. If unsure, say `N'. +ROUTE target support +CONFIG_IP_NF_TARGET_ROUTE + This option adds a `ROUTE' target, which enables you to setup unusual + routes. For example, the ROUTE lets you route a received packet through + an interface or towards a host, even if the regular destination of the + packet is the router itself. The ROUTE target is also able to change the + incoming interface of a packet. + + The target can be or not a final target. It has to be used inside the + mangle table. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. The module will be called ipt_ROUTE.o. + If unsure, say `N'. + TCPMSS target support CONFIG_IP_NF_TARGET_TCPMSS This option adds a `TCPMSS' target, which allows you to alter the @@ -2990,6 +3153,26 @@ CONFIG_IP_NF_TARGET_ULOG If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. +TTL target support +CONFIG_IP_NF_TARGET_TTL + This option adds a `TTL' target, which enables the user to set + the TTL value or increment / decrement the TTL value by a given + amount. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + +CLASSIFY target support +CONFIG_IP_NF_TARGET_CLASSIFY + This option adds a `CLASSIFY' target, which enables the user to set + the priority of a packet. Some qdiscs can use this value for classification, + among these are: + + atm, cbq, dsmark, pfifo_fast, htb, prio + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + LOG target support CONFIG_IP_NF_TARGET_LOG This option adds a `LOG' target, which allows you to create rules in @@ -3054,6 +3237,14 @@ CONFIG_IP6_NF_MATCH_MARK If you want to compile it as a module, say M here and read <file:Documentation/modules.txt>. If unsure, say `N'. +Condition variable match support +CONFIG_IP6_NF_MATCH_CONDITION + This option allows you to match firewall rules against condition + variables stored in the /proc/net/ipt_condition directory. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + Multiple port match support CONFIG_IP6_NF_MATCH_MULTIPORT Multiport matching allows you to match TCP or UDP packets based on @@ -3118,6 +3309,17 @@ CONFIG_IP6_NF_TARGET_MARK If you want to compile it as a module, say M here and read <file:Documentation/modules.txt>. If unsure, say `N'. +ROUTE target support +CONFIG_IP6_NF_TARGET_ROUTE + This option adds a `ROUTE' target, which enables you to setup unusual + routes. The ROUTE target is also able to change the incoming interface + of a packet. + + The target can be or not a final target. It has to be used inside the + mangle table. + + Not working as a module. + TCP Explicit Congestion Notification support CONFIG_INET_ECN Explicit Congestion Notification (ECN) allows routers to notify @@ -3527,7 +3729,7 @@ CONFIG_SGI_DS1286 Indy/I2 Hardware Watchdog CONFIG_INDYDOG Hardwaredriver for the Indy's/I2's watchdog. This is a - watchdog timer that will reboot the machine after a 60 second + watchdog timer that will reboot the machine after a 60 second timer expired and no process has written to /dev/watchdog during that time. @@ -3623,7 +3825,7 @@ CONFIG_AGP_I460 chipset, the first to support Intel Itanium processors, is new and this option is correspondingly a little experimental. - If you don't have a 460GX based machine (such as BigSur) with an AGP + If you don't have a 460GX based machine (such as BigSur) with an AGP slot then this option isn't going to do you much good. If you're dying to do Direct Rendering on IA-64, this is what you're looking for. @@ -3662,7 +3864,7 @@ CONFIG_AGP_SIS Serverworks LE/HE support CONFIG_AGP_SWORKS - Say Y here to support the Serverworks AGP card. See + Say Y here to support the Serverworks AGP card. See <http://www.serverworks.com/> for product descriptions and images. ALI chipset support @@ -4560,8 +4762,8 @@ CONFIG_FB_PMAG_BA PMAGB-B TURBOchannel framebuffer support CONFIG_FB_PMAGB_B Support for the PMAGB-B TURBOchannel framebuffer card used mainly - in the MIPS-based DECstation series. The card is currently only - supported in 1280x1024x8 mode. + in the MIPS-based DECstation series. The card is currently only + supported in 1280x1024x8 mode. FutureTV PCI card CONFIG_ARCH_FTVPCI @@ -4603,7 +4805,7 @@ CONFIG_FB_L7200 NeoMagic display support (EXPERIMENTAL) CONFIG_FB_NEOMAGIC This driver supports notebooks with NeoMagic PCI chips. - Say Y if you have such a graphics card. + Say Y if you have such a graphics card. The driver is also available as a module ( = code which can be inserted and removed from the running kernel whenever you want). The @@ -4817,7 +5019,7 @@ Matrox unified accelerated driver CONFIG_FB_MATROX Say Y here if you have a Matrox Millennium, Millennium II, Mystique, Mystique 220, Productiva G100, Mystique G200, Millennium G200, - Matrox G400, G450 or G550 card in your box. At this time, support for + Matrox G400, G450 or G550 card in your box. At this time, support for the G-series digital output is almost non-existant. This driver is also available as a module ( = code which can be @@ -4857,7 +5059,7 @@ CONFIG_FB_MATROX_G100 "I2C support" and "I2C bit-banging support" in the character devices section, and then to "Matrox I2C support" and "G400 second head support" here in the framebuffer section. - + If you have G550, you must also compile support for G450/G550 secondary head into kernel, otherwise picture will be shown only on the output you are probably not using... @@ -4953,10 +5155,10 @@ CONFIG_FB_MATROX_MULTIHEAD 3Dfx Voodoo Graphics / Voodoo2 frame buffer support CONFIG_FB_VOODOO1 - Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or + Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or Voodoo2 (cvg) based graphics card. - This driver is also available as a module ( = code which can be + This driver is also available as a module ( = code which can be inserted and removed from the running kernel whenever you want). The module will be called sstfb.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. @@ -5087,14 +5289,14 @@ CONFIG_FB_ATY_CT Sony Vaio Picturebook laptop LCD panel support CONFIG_FB_ATY_CT_VAIO_LCD - Say Y here if you want to use the full width of the Sony Vaio + Say Y here if you want to use the full width of the Sony Vaio Picturebook laptops LCD panels (you will get a 128x30 console). Note that you need to activate this mode using the 'vga=0x301' option from your boot loader (lilo or loadlin). See the documentation of your boot loader about how to pass options to the kernel. - + Mach64 GX support CONFIG_FB_ATY_GX Say Y here to support use of the ATI Mach64 Graphics Expression @@ -5143,6 +5345,15 @@ CONFIG_FBCON_ADVANCED If unsure, say N. +CONFIG_NET_SCH_HFSC + Say Y here if you want to use the Hierarchical Fair Service Curve + (HFSC) packet scheduling algorithm for some of your network devices. + + This code is also available as a module called sch_hfsc.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + Monochrome support CONFIG_FBCON_MFB This is the low level frame buffer console driver for monochrome @@ -5339,7 +5550,13711 @@ CONFIG_PARPORT_1284 want to use a device that uses enhanced parallel port transfer modes such as EPP and ECP, say Y here to enable advanced IEEE 1284 transfer modes. Also say Y if you want device ID information to - appear in /proc/sys/dev/parportYYDELETEMEYYmsr - Model-specific register support + appear in /proc/sys/dev/parport/*/autoprobe*. It is safe to say N. + +Enable loadable module support +CONFIG_MODULES + Kernel modules are small pieces of compiled code which can be + inserted in or removed from the running kernel, using the programs + insmod and rmmod. This is described in the file + <file:Documentation/modules.txt>, including the fact that you have + to say "make modules" in order to compile the modules that you chose + during kernel configuration. Modules can be device drivers, file + systems, binary executable formats, and so on. If you think that you + may want to make use of modules with this kernel in the future, then + say Y here. If unsure, say Y. + +Set version information on all symbols for modules +CONFIG_MODVERSIONS + Usually, modules have to be recompiled whenever you switch to a new + kernel. Saying Y here makes it possible, and safe, to use the + same modules even after compiling a new kernel; this requires the + program modprobe. All the software needed for module support is in + the modutils package (check the file <file:Documentation/Changes> + for location and latest version). NOTE: if you say Y here but don't + have the program genksyms (which is also contained in the above + mentioned modutils package), then the building of your kernel will + fail. If you are going to use modules that are generated from + non-kernel sources, you would benefit from this option. Otherwise + it's not that important. So, N ought to be a safe bet. + +Kernel module loader support +CONFIG_KMOD + Normally when you have selected some drivers and/or file systems to + be created as loadable modules, you also have the responsibility to + load the corresponding modules (using the programs insmod or + modprobe) before you can use them. If you say Y here however, the + kernel will be able to load modules for itself: when a part of the + kernel needs a module, it runs modprobe with the appropriate + arguments, thereby loading the module if it is available. (This is a + replacement for kerneld.) Say Y here and read about configuring it + in <file:Documentation/kmod.txt>. + +ARP daemon support +CONFIG_ARPD + Normally, the kernel maintains an internal cache which maps IP + addresses to hardware addresses on the local network, so that + Ethernet/Token Ring/ etc. frames are sent to the proper address on + the physical networking layer. For small networks having a few + hundred directly connected hosts or less, keeping this address + resolution (ARP) cache inside the kernel works well. However, + maintaining an internal ARP cache does not work well for very large + switched networks, and will use a lot of kernel memory if TCP/IP + connections are made to many machines on the network. + + If you say Y here, the kernel's internal ARP cache will never grow + to more than 256 entries (the oldest entries are expired in a LIFO + manner) and communication will be attempted with the user space ARP + daemon arpd. Arpd then answers the address resolution request either + from its own cache or by asking the net. + + This code is experimental and also obsolete. If you want to use it, + you need to find a version of the daemon arpd on the net somewhere, + and you should also say Y to "Kernel/User network link driver", + below. If unsure, say N. + +TCP/IP networking +CONFIG_INET + These are the protocols used on the Internet and on most local + Ethernets. It is highly recommended to say Y here (this will enlarge + your kernel by about 144 KB), since some programs (e.g. the X window + system) use TCP/IP even if your machine is not connected to any + other computer. You will get the so-called loopback device which + allows you to ping yourself (great fun, that!). + + For an excellent introduction to Linux networking, please read the + NET-3-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This option is also necessary if you want to use the full power of + term (term is a program which gives you almost full Internet + connectivity if you have a regular dial up shell account on some + Internet connected Unix computer; for more information, read + <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>). + + If you say Y here and also to "/proc file system support" and + "Sysctl support" below, you can change various aspects of the + behaviour of the TCP/IP code by writing to the (virtual) files in + /proc/sys/net/ipv4/*; the options are explained in the file + <file:Documentation/networking/ip-sysctl.txt>. + + Short answer: say Y. + +IP multicasting +CONFIG_IP_MULTICAST + This is code for addressing several networked computers at once, + enlarging your kernel by about 2 KB. You need multicasting if you + intend to participate in the MBONE, a high bandwidth network on top + of the Internet which carries audio and video broadcasts. More + information about the MBONE is on the WWW at + <http://www-itg.lbl.gov/mbone/>. Information about the multicast + capabilities of the various network cards is contained in + <file:Documentation/networking/multicast.txt>. For most people, it's + safe to say N. + +Advanced router +CONFIG_IP_ADVANCED_ROUTER + If you intend to run your Linux box mostly as a router, i.e. as a + computer that forwards and redistributes network packets, say Y; you + will then be presented with several options that allow more precise + control about the routing process. + + The answer to this question won't directly affect the kernel: + answering N will just cause the configurator to skip all the + questions about advanced routing. + + Note that your box can only act as a router if you enable IP + forwarding in your kernel; you can do that by saying Y to "/proc + file system support" and "Sysctl support" below and executing the + line + + echo "1" > /proc/sys/net/ipv4/ip_forward + + at boot time after the /proc file system has been mounted. + + If you turn on IP forwarding, you will also get the rp_filter, which + automatically rejects incoming packets if the routing table entry + for their source address doesn't match the network interface they're + arriving on. This has security advantages because it prevents the + so-called IP spoofing, however it can pose problems if you use + asymmetric routing (packets from you to a host take a different path + than packets from that host to you) or if you operate a non-routing + host which has several IP addresses on different interfaces. To turn + rp_filter off use: + + echo 0 > /proc/sys/net/ipv4/conf/<device>/rp_filter + or + echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter + + If unsure, say N here. + +Policy routing +CONFIG_IP_MULTIPLE_TABLES + Normally, a router decides what to do with a received packet based + solely on the packet's final destination address. If you say Y here, + the Linux router will also be able to take the packet's source + address into account. Furthermore, if you also say Y to "Use TOS + value as routing key" below, the TOS (Type-Of-Service) field of the + packet can be used for routing decisions as well. In addition, if + you say Y here and to "Fast network address translation" below, + the router will also be able to modify source and destination + addresses of forwarded packets. + + If you are interested in this, please see the preliminary + documentation at <http://www.compendium.com.ar/policy-routing.txt> + and <ftp://post.tepkom.ru/pub/vol2/Linux/docs/advanced-routing.tex>. + You will need supporting software from + <ftp://ftp.inr.ac.ru/ip-routing/>. + + If unsure, say N. + +Equal cost multipath +CONFIG_IP_ROUTE_MULTIPATH + Normally, the routing tables specify a single action to be taken in + a deterministic manner for a given packet. If you say Y here + however, it becomes possible to attach several actions to a packet + pattern, in effect specifying several alternative paths to travel + for those packets. The router considers all these paths to be of + equal "cost" and chooses one of them in a non-deterministic fashion + if a matching packet arrives. + +Use TOS value as routing key +CONFIG_IP_ROUTE_TOS + The header of every IP packet carries a TOS (Type Of Service) value + with which the packet requests a certain treatment, e.g. low + latency (for interactive traffic), high throughput, or high + reliability. If you say Y here, you will be able to specify + different routes for packets with different TOS values. + +Use netfilter MARK value as routing key +CONFIG_IP_ROUTE_FWMARK + If you say Y here, you will be able to specify different routes for + packets with different mark values (see iptables(8), MARK target). + +Verbose route monitoring +CONFIG_IP_ROUTE_VERBOSE + If you say Y here, which is recommended, then the kernel will print + verbose messages regarding the routing, for example warnings about + received packets which look strange and could be evidence of an + attack or a misconfigured system somewhere. The information is + handled by the klogd daemon which is responsible for kernel messages + ("man klogd"). + +Large routing tables +CONFIG_IP_ROUTE_LARGE_TABLES + If you have routing zones that grow to more than about 64 entries, + you may want to say Y here to speed up the routing process. + +Fast network address translation +CONFIG_IP_ROUTE_NAT + If you say Y here, your router will be able to modify source and + destination addresses of packets that pass through it, in a manner + you specify. General information about Network Address Translation + can be gotten from the document + <http://www.csn.tu-chemnitz.de/~mha/linux-ip-nat/diplom/nat.html>. + +Kernel level IP autoconfiguration +CONFIG_IP_PNP + This enables automatic configuration of IP addresses of devices and + of the routing table during kernel boot, based on either information + supplied on the kernel command line or by BOOTP or RARP protocols. + You need to say Y only for diskless machines requiring network + access to boot (in which case you want to say Y to "Root file system + on NFS" as well), because all other machines configure the network + in their startup scripts. + +BOOTP support +CONFIG_IP_PNP_BOOTP + 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 and you want the IP address of your computer to be + discovered automatically at boot time using the BOOTP protocol (a + special protocol designed for doing this job), say Y here. In case + the boot ROM of your network card was designed for booting Linux and + does BOOTP itself, providing all necessary information on the kernel + command line, you can say N here. If unsure, say Y. Note that if you + want to use BOOTP, a BOOTP server must be operating on your network. + Read <file:Documentation/nfsroot.txt> for details. + +DHCP support +CONFIG_IP_PNP_DHCP + 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 and you want the IP address of your computer to be + discovered automatically at boot time using the DHCP protocol (a + special protocol designed for doing this job), say Y here. In case + the boot ROM of your network card was designed for booting Linux and + does DHCP itself, providing all necessary information on the kernel + command line, you can say N here. + + If unsure, say Y. Note that if you want to use DHCP, a DHCP server + must be operating on your network. Read + <file:Documentation/nfsroot.txt> for details. + +RARP support +CONFIG_IP_PNP_RARP + 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 and you want the IP address of your computer to be + discovered automatically at boot time using the RARP protocol (an + older protocol which is being obsoleted by BOOTP and DHCP), say Y + here. Note that if you want to use RARP, a RARP server must be + operating on your network. Read <file:Documentation/nfsroot.txt> for + details. + +IP tunneling +CONFIG_NET_IPIP + Tunneling means encapsulating data of one protocol type within + another protocol and sending it over a channel that understands the + encapsulating protocol. This particular tunneling driver implements + encapsulation of IP within IP, which sounds kind of pointless, but + can be useful if you want to make your (or some other) machine + appear on a different network than it physically is, or to use + mobile-IP facilities (allowing laptops to seamlessly move between + networks without changing their IP addresses; check out + <http://anchor.cs.binghamton.edu/~mobileip/LJ/index.html>). + + Saying Y to this option will produce two modules ( = code which can + be inserted in and removed from the running kernel whenever you + want). Most people won't need this and can say N. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + ipip.o + +GRE tunnels over IP +CONFIG_NET_IPGRE + Tunneling means encapsulating data of one protocol type within + another protocol and sending it over a channel that understands the + encapsulating protocol. This particular tunneling driver implements + GRE (Generic Routing Encapsulation) and at this time allows + encapsulating of IPv4 or IPv6 over existing IPv4 infrastructure. + This driver is useful if the other endpoint is a Cisco router: Cisco + likes GRE much better than the other Linux tunneling driver ("IP + tunneling" above). In addition, GRE allows multicast redistribution + through the tunnel. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + ip_gre.o + +Broadcast GRE over IP +CONFIG_NET_IPGRE_BROADCAST + One application of GRE/IP is to construct a broadcast WAN (Wide Area + Network), which looks like a normal Ethernet LAN (Local Area + Network), but can be distributed all over the Internet. If you want + to do that, say Y here and to "IP multicast routing" below. + +IP multicast routing +CONFIG_IP_MROUTE + This is used if you want your machine to act as a router for IP + packets that have several destination addresses. It is needed on the + MBONE, a high bandwidth network on top of the Internet which carries + audio and video broadcasts. In order to do that, you would most + likely run the program mrouted. Information about the multicast + capabilities of the various network cards is contained in + <file:Documentation/networking/multicast.txt>. If you haven't heard + about it, you don't need it. + +PIM-SM version 1 support +CONFIG_IP_PIMSM_V1 + Kernel side support for Sparse Mode PIM (Protocol Independent + Multicast) version 1. This multicast routing protocol is used widely + because Cisco supports it. You need special software to use it + (pimd-v1). Please see <http://netweb.usc.edu/pim/> for more + information about PIM. + + Say Y if you want to use PIM-SM v1. Note that you can say N here if + you just want to use Dense Mode PIM. + +PIM-SM version 2 support +CONFIG_IP_PIMSM_V2 + Kernel side support for Sparse Mode PIM version 2. In order to use + this, you need an experimental routing daemon supporting it (pimd or + gated-5). This routing protocol is not used widely, so say N unless + you want to play with it. + +Unix domain sockets +CONFIG_UNIX + If you say Y here, you will include support for Unix domain sockets; + sockets are the standard Unix mechanism for establishing and + accessing network connections. Many commonly used programs such as + the X Window system and syslog use these sockets even if your + machine is not connected to any network. Unless you are working on + an embedded system or something similar, you therefore definitely + want to say Y here. + + However, the socket support is also available as a module ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. The module will be + called unix.o. If you try building this as a module and you have + said Y to "Kernel module loader support" above, be sure to add + 'alias net-pf-1 unix' to your /etc/modules.conf file. Note that + several important services won't work correctly if you say M here + and then neglect to load the module. + + Say Y unless you know what you are doing. + +The IPv6 protocol +CONFIG_IPV6 + This is experimental support for the next version of the Internet + Protocol: IP version 6 (also called IPng "IP next generation"). + Features of this new protocol include: expanded address space, + authentication and privacy, and seamless interoperability with the + current version of IP (IP version 4). For general information about + IPv6, see <http://playground.sun.com/pub/ipng/html/ipng-main.html>; + for specific information about IPv6 under Linux read the HOWTO at + <http://www.bieringer.de/linux/IPv6/> and the file net/ipv6/README + in the kernel source. + + If you want to use IPv6, please upgrade to the newest net-tools as + given in <file:Documentation/Changes>. You will still be able to do + regular IPv4 networking as well. + + This protocol support is also available as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want). The module will be called ipv6.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + + It is safe to say N here for now. + +Kernel httpd acceleration +CONFIG_KHTTPD + The kernel httpd acceleration daemon (kHTTPd) is a (limited) web + server built into the kernel. It is limited since it can only serve + files from the file system and cannot deal with executable content + such as CGI scripts. Serving files is sped up if you use kHTTPd. + If kHTTPd is not able to fulfill a request, it can transparently + pass it through to a user space web server such as apache. + + Saying "M" here builds the kHTTPd module; this is NOT enough to have + a working kHTTPd. For safety reasons, the module has to be activated + by doing a "echo 1 > /proc/sys/net/khttpd/start" after inserting the + module. + + Before using this, read the README in net/khttpd ! + + The kHTTPd is experimental. Be careful when using it on a production + machine. Also note that kHTTPd doesn't support virtual servers yet. + +The IPX protocol +CONFIG_IPX + This is support for the Novell networking protocol, IPX, commonly + used for local networks of Windows machines. You need it if you + want to access Novell NetWare file or print servers using the Linux + Novell client ncpfs (available from + <ftp://platan.vc.cvut.cz/pub/linux/ncpfs/>) or from + within the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, + available from <http://www.tldp.org/docs.html#howto>). In order + to do the former, you'll also have to say Y to "NCP file system + support", below. + + IPX is similar in scope to IP, while SPX, which runs on top of IPX, + is similar to TCP. There is also experimental support for SPX in + Linux (see "SPX networking", below). + + To turn your Linux box into a fully featured NetWare file server and + IPX router, say Y here and fetch either lwared from + <ftp://ibiblio.org/pub/Linux/system/network/daemons/> or + mars_nwe from <ftp://www.compu-art.de/mars_nwe/>. For more + information, read the IPX-HOWTO available from + <http://www.tldp.org/docs.html#howto>. + + General information about how to connect Linux, Windows machines and + Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>. + + The IPX driver would enlarge your kernel by about 16 KB. This driver + is also available as a module ( = code which can be inserted in and + removed from the running kernel whenever you want). The module will + be called ipx.o. If you want to compile it as a module, say M here + and read <file:Documentation/modules.txt>. Unless you want to + integrate your Linux box with a local Novell network, say N. + +Full internal IPX network +CONFIG_IPX_INTERN + Every IPX network has an address that identifies it. Sometimes it is + useful to give an IPX "network" address to your Linux box as well + (for example if your box is acting as a file server for different + IPX networks: it will then be accessible from everywhere using the + same address). The way this is done is to create a virtual internal + "network" inside your box and to assign an IPX address to this + network. Say Y here if you want to do this; read the IPX-HOWTO at + <http://www.tldp.org/docs.html#howto> for details. + + The full internal IPX network enables you to allocate sockets on + different virtual nodes of the internal network. This is done by + evaluating the field sipx_node of the socket address given to the + bind call. So applications should always initialize the node field + to 0 when binding a socket on the primary network. In this case the + socket is assigned the default node that has been given to the + kernel when the internal network was created. By enabling the full + internal IPX network the cross-forwarding of packets targeted at + 'special' sockets to sockets listening on the primary network is + disabled. This might break existing applications, especially RIP/SAP + daemons. A RIP/SAP daemon that works well with the full internal net + can be found on <ftp://ftp.gwdg.de/pub/linux/misc/ncpfs/>. + + If you don't know what you are doing, say N. + +#(We're told this will come back someday) + +SPX networking +CONFIG_SPX + * Orphaned entry retained 20 April 2001 by Petr Vandrovec * + * If you read this note from the configurator, please contact * + * the Configure.help maintainers. * + The Sequenced Packet eXchange protocol is a transport layer protocol + built on top of IPX. It is used in Novell NetWare systems for + client-server applications and is similar to TCP (which runs on top + of IP). + + Note that Novell NetWare file sharing does not use SPX; it uses a + protocol called NCP, for which separate Linux support is available + ("NCP file system support" below for the client side, and the user + space programs lwared or mars_nwe for the server side). + + Say Y here if you have use for SPX; read the IPX-HOWTO at + <http://www.tldp.org/docs.html#howto> for details. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called af_spx.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +DECnet networking +CONFIG_DECNET + The DECnet networking protocol was used in many products made by + Digital (now Compaq). It provides reliable stream and sequenced + packet communications over which run a variety of services similar + to those which run over TCP/IP. + + To find some tools to use with the kernel layer support, please + look at Patrick Caulfield's web site: + <http://linux.dreamtime.org/decnet/>. + + More detailed documentation is available in + <file:Documentation/networking/decnet.txt>. + + Be sure to say Y to "/proc file system support" and "Sysctl support" + below when using DECnet, since you will need sysctl support to aid + in configuration at run time. + + The DECnet code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called decnet.o. + +DECnet SIOCFIGCONF support +CONFIG_DECNET_SIOCGIFCONF + This option should only be turned on if you are really sure that + you know what you are doing. It can break other applications which + use this system call and the proper way to get the information + provided by this call is to use rtnetlink. + + If unsure, say N. + +DECnet router support +CONFIG_DECNET_ROUTER + Add support for turning your DECnet Endnode into a level 1 or 2 + router. This is an unfinished option for developers only. If you + do say Y here, then make sure that you also say Y to "Kernel/User + network link driver", "Routing messages" and "Network packet + filtering". The first two are required to allow configuration via + rtnetlink (currently you need Alexey Kuznetsov's iproute2 package + from <ftp://ftp.inr.ac.ru/>). The "Network packet filtering" option + will be required for the forthcoming routing daemon to work. + + See <file:Documentation/networking/decnet.txt> for more information. + +Use FWMARK value as DECnet routing key +CONFIG_DECNET_ROUTE_FWMARK + If you say Y here, you will be able to specify different routes for + packets with different FWMARK ("firewalling mark") values + (see ipchains(8), "-m" argument). + +AppleTalk interfaces support +CONFIG_DEV_APPLETALK + AppleTalk is the protocol that Apple computers can use to communicate + on a network. If your Linux box is connected to such a network, and wish + to do IP over it, or you have a LocalTalk card and wish to use it to + connect to the AppleTalk network, say Y. + +AppleTalk protocol support +CONFIG_ATALK + AppleTalk is the protocol that Apple computers can use to communicate + on a network. If your Linux box is connected to such a network and you + wish to connect to it, say Y. You will need to use the netatalk package + so that your Linux box can act as a print and file server for Macs as + well as access AppleTalk printers. Check out + <http://www.zettabyte.net/netatalk/> on the WWW for details. + EtherTalk is the name used for AppleTalk over Ethernet and the + cheaper and slower LocalTalk is AppleTalk over a proprietary Apple + network using serial links. EtherTalk and LocalTalk are fully + supported by Linux. + + General information about how to connect Linux, Windows machines and + Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>. The + NET-3-HOWTO, available from + <http://www.tldp.org/docs.html#howto>, contains valuable + information as well. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called appletalk.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. You + almost certainly want to compile it as a module so you can restart + your AppleTalk stack without rebooting your machine. I hear that + the GNU boycott of Apple is over, so even politically correct people + are allowed to say Y here. + +AppleTalk-IP driver support +CONFIG_IPDDP + This allows IP networking for users who only have AppleTalk + networking available. This feature is experimental. With this + driver, you can encapsulate IP inside AppleTalk (e.g. if your Linux + box is stuck on an AppleTalk only network) or decapsulate (e.g. if + you want your Linux box to act as an Internet gateway for a zoo of + AppleTalk connected Macs). Please see the file + <file:Documentation/networking/ipddp.txt> for more information. + + If you say Y here, the AppleTalk-IP support will be compiled into + the kernel. In this case, you can either use encapsulation or + decapsulation, but not both. With the following two questions, you + decide which one you want. + + If you say M here, the AppleTalk-IP support will be compiled as a + module ( = code which can be inserted in and removed from the + running kernel whenever you want, read + <file:Documentation/modules.txt>). The module is called ipddp.o. + In this case, you will be able to use both encapsulation and + decapsulation simultaneously, by loading two copies of the module + and specifying different values for the module option ipddp_mode. + +IP to AppleTalk-IP Encapsulation support +CONFIG_IPDDP_ENCAP + If you say Y here, the AppleTalk-IP code will be able to encapsulate + IP packets inside AppleTalk frames; this is useful if your Linux box + is stuck on an AppleTalk network (which hopefully contains a + decapsulator somewhere). Please see + <file:Documentation/networking/ipddp.txt> for more information. If + you said Y to "AppleTalk-IP driver support" above and you say Y + here, then you cannot say Y to "AppleTalk-IP to IP Decapsulation + support", below. + +AppleTalk-IP to IP Decapsulation support +CONFIG_IPDDP_DECAP + If you say Y here, the AppleTalk-IP code will be able to decapsulate + AppleTalk-IP frames to IP packets; this is useful if you want your + Linux box to act as an Internet gateway for an AppleTalk network. + Please see <file:Documentation/networking/ipddp.txt> for more + information. If you said Y to "AppleTalk-IP driver support" above + and you say Y here, then you cannot say Y to "IP to AppleTalk-IP + Encapsulation support", above. + +Apple/Farallon LocalTalk PC card support +CONFIG_LTPC + This allows you to use the AppleTalk PC card to connect to LocalTalk + networks. The card is also known as the Farallon PhoneNet PC card. + If you are in doubt, this card is the one with the 65C02 chip on it. + You also need version 1.3.3 or later of the netatalk package. + This driver is experimental, which means that it may not work. + See the file <file:Documentation/networking/ltpc.txt>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + ltpc.o + +COPS LocalTalk PC card support +CONFIG_COPS + This allows you to use COPS AppleTalk cards to connect to LocalTalk + networks. You also need version 1.3.3 or later of the netatalk + package. This driver is experimental, which means that it may not + work. This driver will only work if you choose "AppleTalk DDP" + networking support, above. + Please read the file <file:Documentation/networking/cops.txt>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + cops.o + +Dayna firmware support +CONFIG_COPS_DAYNA + Support COPS compatible cards with Dayna style firmware (Dayna + DL2000/ Daynatalk/PC (half length), COPS LT-95, Farallon PhoneNET PC + III, Farallon PhoneNET PC II). + +Tangent firmware support +CONFIG_COPS_TANGENT + Support COPS compatible cards with Tangent style firmware (Tangent + ATB_II, Novell NL-1000, Daystar Digital LT-200. + +Amateur Radio support +CONFIG_HAMRADIO + If you want to connect your Linux box to an amateur radio, answer Y + here. You want to read <http://www.tapr.org/tapr/html/pkthome.html> and + the AX25-HOWTO, available from <http://www.tldp.org/docs.html#howto>. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about amateur radio. + +Amateur Radio AX.25 Level 2 protocol +CONFIG_AX25 + This is the protocol used for computer communication over amateur + radio. It is either used by itself for point-to-point links, or to + carry other protocols such as tcp/ip. To use it, you need a device + that connects your Linux box to your amateur radio. You can either + use a low speed TNC (a Terminal Node Controller acts as a kind of + modem connecting your computer's serial port to your radio's + microphone input and speaker output) supporting the KISS protocol or + one of the various SCC cards that are supported by the generic Z8530 + or the DMA SCC driver. Another option are the Baycom modem serial + and parallel port hacks or the sound card modem (supported by their + own drivers). If you say Y here, you also have to say Y to one of + those drivers. + + Information about where to get supporting software for Linux amateur + radio as well as information about how to configure an AX.25 port is + contained in the AX25-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. You might also want to + check out the file <file:Documentation/networking/ax25.txt> in the + kernel source. More information about digital amateur radio in + general is on the WWW at + <http://www.tapr.org/tapr/html/pkthome.html>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ax25.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +AX.25 DAMA Slave support +CONFIG_AX25_DAMA_SLAVE + DAMA is a mechanism to prevent collisions when doing AX.25 + networking. A DAMA server (called "master") accepts incoming traffic + from clients (called "slaves") and redistributes it to other slaves. + If you say Y here, your Linux box will act as a DAMA slave; this is + transparent in that you don't have to do any special DAMA + configuration. (Linux cannot yet act as a DAMA server.) If unsure, + say N. + +AX.25 DAMA Master support +CONFIG_AX25_DAMA_MASTER + DAMA is a mechanism to prevent collisions when doing AX.25 + networking. A DAMA server (called "master") accepts incoming traffic + from clients (called "slaves") and redistributes it to other + slaves. If you say Y here, your Linux box will act as a DAMA server. + If unsure, say N. + +Amateur Radio NET/ROM support +CONFIG_NETROM + NET/ROM is a network layer protocol on top of AX.25 useful for + routing. + + A comprehensive listing of all the software for Linux amateur radio + users as well as information about how to configure an AX.25 port is + contained in the AX25-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. You also might want to + check out the file <file:Documentation/networking/ax25.txt>. More + information about digital amateur radio in general is on the WWW at + <http://www.tapr.org/tapr/html/pkthome.html>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called netrom.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Amateur Radio X.25 PLP (Rose) +CONFIG_ROSE + The Packet Layer Protocol (PLP) is a way to route packets over X.25 + connections in general and amateur radio AX.25 connections in + particular, essentially an alternative to NET/ROM. + + A comprehensive listing of all the software for Linux amateur radio + users as well as information about how to configure an AX.25 port is + contained in the AX25-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. You also might want to + check out the file <file:Documentation/networking/ax25.txt>. More + information about digital amateur radio in general is on the WWW at + <http://www.tapr.org/tapr/html/pkthome.html>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called rose.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Serial port KISS driver for AX.25 +CONFIG_MKISS + KISS is a protocol used for the exchange of data between a computer + and a Terminal Node Controller (a small embedded system commonly + used for networking over AX.25 amateur radio connections; it + connects the computer's serial port with the radio's microphone + input and speaker output). + + Although KISS is less advanced than the 6pack protocol, it has + the advantage that it is already supported by most modern TNCs + without the need for a firmware upgrade. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called mkiss.o. + +Serial port 6PACK driver for AX.25 +CONFIG_6PACK + 6pack is a transmission protocol for the data exchange between your + PC and your TNC (the Terminal Node Controller acts as a kind of + modem connecting your computer's serial port to your radio's + microphone input and speaker output). This protocol can be used as + an alternative to KISS for networking over AX.25 amateur radio + connections, but it has some extended functionality. + + Note that this driver is still experimental and might cause + problems. For details about the features and the usage of the + driver, read <file:Documentation/networking/6pack.txt>. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called 6pack.o. + +BPQ Ethernet driver +CONFIG_BPQETHER + AX.25 is the protocol used for computer communication over amateur + radio. If you say Y here, you will be able to send and receive AX.25 + traffic over Ethernet (also called "BPQ AX.25"), which could be + useful if some other computer on your local network has a direct + amateur radio connection. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called bpqether.o. + +High-speed (DMA) SCC driver for AX.25 +CONFIG_DMASCC + This is a driver for high-speed SCC boards, i.e. those supporting + DMA on one port. You usually use those boards to connect your + computer to an amateur radio modem (such as the WA4DSY 56kbps + modem), in order to send and receive AX.25 packet radio network + traffic. + + Currently, this driver supports Ottawa PI/PI2, Paccomm/Gracilis + PackeTwin, and S5SCC/DMA boards. They are detected automatically. + If you have one of these cards, say Y here and read the AX25-HOWTO, + available from <http://www.tldp.org/docs.html#howto>. + + This driver can operate multiple boards simultaneously. If you + compile it as a module (by saying M instead of Y), it will be called + dmascc.o. If you don't pass any parameter to the driver, all + possible I/O addresses are probed. This could irritate other devices + that are currently not in use. You may specify the list of addresses + to be probed by "dmascc=addr1,addr2,..." (when compiled into the + kernel image) or "io=addr1,addr2,..." (when loaded as a module). The + network interfaces will be called dmascc0 and dmascc1 for the board + detected first, dmascc2 and dmascc3 for the second one, and so on. + + Before you configure each interface with ifconfig, you MUST set + certain parameters, such as channel access timing, clock mode, and + DMA channel. This is accomplished with a small utility program, + dmascc_cfg, available at + <http://www.nt.tuwien.ac.at/~kkudielk/Linux/>. Please be sure to get + at least version 1.27 of dmascc_cfg, as older versions will not + work with the current driver. + +Z8530 SCC driver for AX.25 +CONFIG_SCC + These cards are used to connect your Linux box to an amateur radio + in order to communicate with other computers. If you want to use + this, read <file:Documentation/networking/z8530drv.txt> and the + AX25-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. Also make sure to say Y + to "Amateur Radio AX.25 Level 2" support. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called scc.o. + +Support for TRX that feedback the tx signal to rx +CONFIG_SCC_TRXECHO + Some transmitters feed the transmitted signal back to the receive + line. Say Y here to foil this by explicitly disabling the receiver + during data transmission. If in doubt, say Y. + +Additional delay for PA0HZP OptoSCC compatible boards +CONFIG_SCC_DELAY + Say Y here if you experience problems with the SCC driver not + working properly; please read + <file:Documentation/networking/z8530drv.txt> for details. If unsure, + say N. + +YAM driver for AX.25 +CONFIG_YAM + The YAM is a modem for packet radio which connects to the serial + port and includes some of the functions of a Terminal Node + Controller. If you have one of those, say Y here. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called yam.o. + +BAYCOM picpar and par96 driver for AX.25 +CONFIG_BAYCOM_PAR + This is a driver for Baycom style simple amateur radio modems that + connect to a parallel interface. The driver supports the picpar and + par96 designs. To configure the driver, use the sethdlc utility + available in the standard ax25 utilities package. For information on + the modems, see <http://www.baycom.de/> and the file + <file:Documentation/networking/baycom.txt>. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. This is + recommended. The module will be called baycom_par.o. + +BAYCOM EPP driver for AX.25 +CONFIG_BAYCOM_EPP + This is a driver for Baycom style simple amateur radio modems that + connect to a parallel interface. The driver supports the EPP + designs. To configure the driver, use the sethdlc utility available + in the standard ax25 utilities package. For information on the + modems, see <http://www.baycom.de/> and the file + <file:Documentation/networking/baycom.txt>. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. This is + recommended. The module will be called baycom_par.o. + +BAYCOM ser12 full-duplex driver for AX.25 +CONFIG_BAYCOM_SER_FDX + This is one of two drivers for Baycom style simple amateur radio + modems that connect to a serial interface. The driver supports the + ser12 design in full-duplex mode. In addition, it allows the + baudrate to be set between 300 and 4800 baud (however not all modems + support all baudrates). This is the preferred driver. The next + driver, "BAYCOM ser12 half-duplex driver for AX.25" is the old + driver and still provided in case this driver does not work with + your serial interface chip. To configure the driver, use the sethdlc + utility available in the standard ax25 utilities package. For + information on the modems, see <http://www.baycom.de/> and + <file:Documentation/networking/baycom.txt>. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. This is + recommended. The module will be called baycom_ser_fdx.o. + +BAYCOM ser12 half-duplex driver for AX.25 +CONFIG_BAYCOM_SER_HDX + This is one of two drivers for Baycom style simple amateur radio + modems that connect to a serial interface. The driver supports the + ser12 design in full-duplex mode. This is the old driver. It is + still provided in case your serial interface chip does not work with + the full-duplex driver. This driver is depreciated. To configure + the driver, use the sethdlc utility available in the standard ax25 + utilities package. For information on the modems, see + <http://www.baycom.de/> and + <file:Documentation/networking/baycom.txt>. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. This is + recommended. The module will be called baycom_ser_hdx.o. + +Sound card modem driver for AX.25 +CONFIG_SOUNDMODEM + This experimental driver allows a standard Sound Blaster or + WindowsSoundSystem compatible sound card to be used as a packet + radio modem (NOT as a telephone modem!), to send digital traffic + over amateur radio. + + To configure the driver, use the sethdlc, smdiag and smmixer + utilities available in the standard ax25 utilities package. For + information on how to key the transmitter, see + <http://www.ife.ee.ethz.ch/~sailer/pcf/ptt_circ/ptt.html> and + <file:Documentation/networking/soundmodem.txt>. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. This is + recommended. The module will be called soundmodem.o. + +Sound card modem support for Sound Blaster and compatible cards +CONFIG_SOUNDMODEM_SBC + This option enables the soundmodem driver to use Sound Blaster and + compatible cards. If you have a dual mode card (i.e. a WSS cards + with a Sound Blaster emulation) you should say N here and Y to + "Sound card modem support for WSS and Crystal cards", below, because + this usually results in better performance. This option also + supports SB16/32/64 in full-duplex mode. + +Sound card modem support for WSS and Crystal cards +CONFIG_SOUNDMODEM_WSS + This option enables the soundmodem driver to use WindowsSoundSystem + compatible cards. These cards feature a codec chip from either + Analog Devices (such as AD1848, AD1845, AD1812) or Crystal + Semiconductors (such as CS4248, CS423x). This option also supports + the WSS full-duplex operation which currently works with Crystal + CS423x chips. If you don't need full-duplex operation, do not enable + it to save performance. + +Sound card modem support for 1200 baud AFSK modulation +CONFIG_SOUNDMODEM_AFSK1200 + This option enables the soundmodem driver 1200 baud AFSK modem, + compatible to popular modems using TCM3105 or AM7911. The + demodulator requires about 12% of the CPU power of a Pentium 75 CPU + per channel. + +Sound card modem support for 2400 baud AFSK modulation (7.3728MHz crystal) +CONFIG_SOUNDMODEM_AFSK2400_7 + This option enables the soundmodem driver 2400 baud AFSK modem, + compatible to TCM3105 modems (over-)clocked with a 7.3728MHz + crystal. Note that the availability of this driver does _not_ imply + that I recommend building such links. It is only here since users + especially in eastern Europe have asked me to do so. In fact this + modulation scheme has many disadvantages, mainly its incompatibility + with many transceiver designs and the fact that the TCM3105 (if + used) is operated widely outside its specifications. + +Sound card modem support for 2400 baud AFSK modulation (8MHz crystal) +CONFIG_SOUNDMODEM_AFSK2400_8 + This option enables the soundmodem driver 2400 baud AFSK modem, + compatible to TCM3105 modems (over-)clocked with an 8MHz crystal. + Note that the availability of this driver does _not_ imply that I + recommend building such links. It is only here since users + especially in eastern Europe have asked me to do so. In fact this + modulation scheme has many disadvantages, mainly its incompatibility + with many transceiver designs and the fact that the TCM3105 (if + used) is operated widely outside its specifications. + +Sound card modem support for 2666 baud AFSK modulation +CONFIG_SOUNDMODEM_AFSK2666 + This option enables the soundmodem driver 2666 baud AFSK modem. + This modem is experimental, and not compatible to anything + else I know of. + +Sound card modem support for 4800 baud 8PSK modulation +CONFIG_SOUNDMODEM_PSK4800 + This option enables the soundmodem driver 4800 baud 8PSK modem. + This modem is experimental, and not compatible to anything + else I know of. + +Sound card modem support for 4800 baud HAPN-1 modulation +CONFIG_SOUNDMODEM_HAPN4800 + This option enables the soundmodem driver 4800 baud HAPN-1 + compatible modem. This modulation seems to be widely used 'down + under' and in the Netherlands. Here, nobody uses it, so I could not + test if it works. It is compatible to itself, however :-) + +Sound card modem support for 9600 baud FSK G3RUH modulation +CONFIG_SOUNDMODEM_FSK9600 + This option enables the soundmodem driver 9600 baud FSK modem, + compatible to the G3RUH standard. The demodulator requires about 4% + of the CPU power of a Pentium 75 CPU per channel. You can say Y to + both 1200 baud AFSK and 9600 baud FSK if you want (but obviously you + can only use one protocol at a time, depending on what the other end + can understand). + +CCITT X.25 Packet Layer +CONFIG_X25 + X.25 is a set of standardized network protocols, similar in scope to + frame relay; the one physical line from your box to the X.25 network + entry point can carry several logical point-to-point connections + (called "virtual circuits") to other computers connected to the X.25 + network. Governments, banks, and other organizations tend to use it + to connect to each other or to form Wide Area Networks (WANs). Many + countries have public X.25 networks. X.25 consists of two + protocols: the higher level Packet Layer Protocol (PLP) (say Y here + if you want that) and the lower level data link layer protocol LAPB + (say Y to "LAPB Data Link Driver" below if you want that). + + You can read more about X.25 at <http://www.sangoma.com/x25.htm> and + <http://www.cisco.com/univercd/data/doc/software/11_0/rpcg/cx25.htm>. + Information about X.25 for Linux is contained in the files + <file:Documentation/networking/x25.txt> and + <file:Documentation/networking/x25-iface.txt>. + + One connects to an X.25 network either with a dedicated network card + using the X.21 protocol (not yet supported by Linux) or one can do + X.25 over a standard telephone line using an ordinary modem (say Y + to "X.25 async driver" below) or over Ethernet using an ordinary + Ethernet card and either the 802.2 LLC protocol (say Y to "802.2 + LLC" below) or LAPB over Ethernet (say Y to "LAPB Data Link Driver" + and "LAPB over Ethernet driver" below). + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called x25.o. If unsure, say N. + +LAPB Data Link Driver +CONFIG_LAPB + Link Access Procedure, Balanced (LAPB) is the data link layer (i.e. + the lower) part of the X.25 protocol. It offers a reliable + connection service to exchange data frames with one other host, and + it is used to transport higher level protocols (mostly X.25 Packet + Layer, the higher part of X.25, but others are possible as well). + Usually, LAPB is used with specialized X.21 network cards, but Linux + currently supports LAPB only over Ethernet connections. If you want + to use LAPB connections over Ethernet, say Y here and to "LAPB over + Ethernet driver" below. Read + <file:Documentation/networking/lapb-module.txt> for technical + details. + + If you want to compile this driver as a module though ( = code which + can be inserted in and removed from the running kernel whenever you + want), say M here and read <file:Documentation/modules.txt>. The + module will be called lapb.o. If unsure, say N. + +802.2 LLC +CONFIG_LLC + This is a Logical Link Layer protocol used for X.25 connections over + Ethernet, using ordinary Ethernet cards. + +Frame Diverter +CONFIG_NET_DIVERT + The Frame Diverter allows you to divert packets from the + network, that are not aimed at the interface receiving it (in + promisc. mode). Typically, a Linux box setup as an Ethernet bridge + with the Frames Diverter on, can do some *really* transparent www + caching using a Squid proxy for example. + + This is very useful when you don't want to change your router's + config (or if you simply don't have access to it). + + The other possible usages of diverting Ethernet Frames are + numberous: + - reroute smtp traffic to another interface + - traffic-shape certain network streams + - transparently proxy smtp connections + - etc... + + For more informations, please refer to: + <http://diverter.sourceforge.net/> + <http://perso.wanadoo.fr/magpie/EtherDivert.html> + + If unsure, say N. + +802.1d Ethernet Bridging +CONFIG_BRIDGE + If you say Y here, then your Linux box will be able to act as an + Ethernet bridge, which means that the different Ethernet segments it + is connected to will appear as one Ethernet to the participants. + Several such bridges can work together to create even larger + networks of Ethernets using the IEEE 802.1 spanning tree algorithm. + As this is a standard, Linux bridges will cooperate properly with + other third party bridge products. + + In order to use the Ethernet bridge, you'll need the bridge + configuration tools; see <file:Documentation/networking/bridge.txt> + for location. Please read the Bridge mini-HOWTO for more + information. + + Note that if your box acts as a bridge, it probably contains several + Ethernet devices, but the kernel is not able to recognize more than + one at boot time without help; for details read the Ethernet-HOWTO, + available from in <http://www.tldp.org/docs.html#howto>. + + If you want to compile this code as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called bridge.o. + + If unsure, say N. + +Packet socket +CONFIG_PACKET + The Packet protocol is used by applications which communicate + directly with network devices without an intermediate network + protocol implemented in the kernel, e.g. tcpdump. If you want them + to work, choose Y. + + This driver is also available as a module called af_packet.o ( = + code which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>; if you use modprobe + or kmod, you may also want to add "alias net-pf-17 af_packet" to + /etc/modules.conf. + + If unsure, say Y. + +Packet socket: mmapped IO +CONFIG_PACKET_MMAP + If you say Y here, the Packet protocol driver will use an IO + mechanism that results in faster communication. + + If unsure, say N. + +Netlink device emulation +CONFIG_NETLINK_DEV + This option will be removed soon. Any programs that want to use + character special nodes like /dev/tap0 or /dev/route (all with major + number 36) need this option, and need to be rewritten soon to use + the real netlink socket. + This is a backward compatibility option, choose Y for now. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + netlink_dev.o + +Asynchronous Transfer Mode (ATM) +CONFIG_ATM + ATM is a high-speed networking technology for Local Area Networks + and Wide Area Networks. It uses a fixed packet size and is + connection oriented, allowing for the negotiation of minimum + bandwidth requirements. + + In order to participate in an ATM network, your Linux box needs an + ATM networking card. If you have that, say Y here and to the driver + of your ATM card below. + + Note that you need a set of user-space programs to actually make use + of ATM. See the file <file:Documentation/networking/atm.txt> for + further details. + +Classical IP over ATM +CONFIG_ATM_CLIP + Classical IP over ATM for PVCs and SVCs, supporting InARP and + ATMARP. If you want to communication with other IP hosts on your ATM + network, you will typically either say Y here or to "LAN Emulation + (LANE)" below. + +Do NOT send ICMP if no neighbour +CONFIG_ATM_CLIP_NO_ICMP + Normally, an "ICMP host unreachable" message is sent if a neighbour + cannot be reached because there is no VC to it in the kernel's + ATMARP table. This may cause problems when ATMARP table entries are + briefly removed during revalidation. If you say Y here, packets to + such neighbours are silently discarded instead. + +RFC1483/2684 Bridged protocols +CONFIG_ATM_BR2684 + ATM PVCs can carry ethernet PDUs according to rfc2684 (formerly 1483) + This device will act like an ethernet from the kernels point of view, + with the traffic being carried by ATM PVCs (currently 1 PVC/device). + This is sometimes used over DSL lines. If in doubt, say N. + +Per-VC IP filter kludge +CONFIG_ATM_BR2684_IPFILTER + This is an experimental mechanism for users who need to terminating a + large number of IP-only vcc's. Do not enable this unless you are sure + you know what you are doing. + +LAN Emulation (LANE) support +CONFIG_ATM_LANE + LAN Emulation emulates services of existing LANs across an ATM + network. Besides operating as a normal ATM end station client, Linux + LANE client can also act as an proxy client bridging packets between + ELAN and Ethernet segments. You need LANE if you want to try MPOA. + +Multi-Protocol Over ATM (MPOA) support +CONFIG_ATM_MPOA + Multi-Protocol Over ATM allows ATM edge devices such as routers, + bridges and ATM attached hosts establish direct ATM VCs across + subnetwork boundaries. These shortcut connections bypass routers + enhancing overall network performance. + +ATM over TCP +CONFIG_ATM_TCP + ATM over TCP driver. Useful mainly for development and for + experiments. If unsure, say N. + +Efficient Networks ENI155P +CONFIG_ATM_ENI + Driver for the Efficient Networks ENI155p series and SMC ATM + Power155 155 Mbps ATM adapters. Both, the versions with 512KB and + 2MB on-board RAM (Efficient calls them "C" and "S", respectively), + and the FPGA and the ASIC Tonga versions of the board are supported. + The driver works with MMF (-MF or ...F) and UTP-5 (-U5 or ...D) + adapters. + + This driver is also available as a module. If you want to compile + it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called eni.o. + +Enable extended debugging +CONFIG_ATM_ENI_DEBUG + Extended debugging records various events and displays that list + when an inconsistency is detected. This mechanism is faster than + generally using printks, but still has some impact on performance. + Note that extended debugging may create certain race conditions + itself. Enable this ONLY if you suspect problems with the driver. + +Fine-tune burst settings +CONFIG_ATM_ENI_TUNE_BURST + In order to obtain good throughput, the ENI NIC can transfer + multiple words of data per PCI bus access cycle. Such a multi-word + transfer is called a burst. + + The default settings for the burst sizes are suitable for most PCI + chipsets. However, in some cases, large bursts may overrun buffers + in the PCI chipset and cause data corruption. In such cases, large + bursts must be disabled and only (slower) small bursts can be used. + The burst sizes can be set independently in the send (TX) and + receive (RX) direction. + + Note that enabling many different burst sizes in the same direction + may increase the cost of setting up a transfer such that the + resulting throughput is lower than when using only the largest + available burst size. + + Also, sometimes larger bursts lead to lower throughput, e.g. on an + Intel 440FX board, a drop from 135 Mbps to 103 Mbps was observed + when going from 8W to 16W bursts. + +Enable 16W TX bursts (discouraged) +CONFIG_ATM_ENI_BURST_TX_16W + Burst sixteen words at once in the send direction. This may work + with recent PCI chipsets, but is known to fail with older chipsets. + +Enable 8W TX bursts (recommended) +CONFIG_ATM_ENI_BURST_TX_8W + Burst eight words at once in the send direction. This is the default + setting. + +Enable 4W TX bursts (optional) +CONFIG_ATM_ENI_BURST_TX_4W + Burst four words at once in the send direction. You may want to try + this if you have disabled 8W bursts. Enabling 4W if 8W is also set + may or may not improve throughput. + +Enable 2W TX bursts (optional) +CONFIG_ATM_ENI_BURST_TX_2W + Burst two words at once in the send direction. You may want to try + this if you have disabled 4W and 8W bursts. Enabling 2W if 4W or 8W + are also set may or may not improve throughput. + +Enable 16W RX bursts (discouraged) +CONFIG_ATM_ENI_BURST_RX_16W + Burst sixteen words at once in the receive direction. This may work + with recent PCI chipsets, but is known to fail with older chipsets. + +Enable 8W RX bursts (discouraged) +CONFIG_ATM_ENI_BURST_RX_8W + Burst eight words at once in the receive direction. This may work + with recent PCI chipsets, but is known to fail with older chipsets, + such as the Intel Neptune series. + +Enable 4W RX bursts (recommended) +CONFIG_ATM_ENI_BURST_RX_4W + Burst four words at once in the receive direction. This is the + default setting. Enabling 4W if 8W is also set may or may not + improve throughput. + +Enable 2W RX bursts (optional) +CONFIG_ATM_ENI_BURST_RX_2W + Burst two words at once in the receive direction. You may want to + try this if you have disabled 4W and 8W bursts. Enabling 2W if 4W or + 8W are also set may or may not improve throughput. + +ZeitNet ZN1221/ZN1225 +CONFIG_ATM_ZATM + Driver for the ZeitNet ZN1221 (MMF) and ZN1225 (UTP-5) 155 Mbps ATM + adapters. + + This driver is also available as a module. If you want to compile + it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called zatm.o. + +Enable extended debugging +CONFIG_ATM_ZATM_DEBUG + Extended debugging records various events and displays that list + when an inconsistency is detected. This mechanism is faster than + generally using printks, but still has some impact on performance. + Note that extended debugging may create certain race conditions + itself. Enable this ONLY if you suspect problems with the driver. + +Fujitsu FireStream (FS50/FS155) +CONFIG_ATM_FIRESTREAM + Driver for the Fujitsu FireStream 155 (MB86697) and + FireStream 50 (MB86695) ATM PCI chips. + + This driver is also available as a module. If you want to compile + it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + firestream.o. + +Enable usec resolution timestamps +CONFIG_ATM_ZATM_EXACT_TS + The uPD98401 SAR chip supports a high-resolution timer (approx. 30 + MHz) that is used for very accurate reception timestamps. Because + that timer overflows after 140 seconds, and also to avoid timer + drift, time measurements need to be periodically synchronized with + the normal system time. Enabling this feature will add some general + overhead for timer synchronization and also per-packet overhead for + time conversion. + +IDT 77201/11 (NICStAR) (ForeRunnerLE) +CONFIG_ATM_NICSTAR + The NICStAR chipset family is used in a large number of ATM NICs for + 25 and for 155 Mbps, including IDT cards and the Fore ForeRunnerLE + series. Say Y if you have one of those. + + This driver is also available as a module. If you want to compile + it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + nicstar.o. + +Use suni PHY driver (155Mbps) +CONFIG_ATM_NICSTAR_USE_SUNI + Support for the S-UNI and compatible PHYsical layer chips. These are + found in most 155Mbps NICStAR based ATM cards, namely in the + ForeRunner LE155 cards. This driver provides detection of cable~ + removal and reinsertion and provides some statistics. This driver + doesn't have removal capability when compiled as a module, so if you + need that capability don't include S-UNI support (it's not needed to + make the card work). + +Use IDT77015 PHY driver (25Mbps) +CONFIG_ATM_NICSTAR_USE_IDT77105 + Support for the PHYsical layer chip in ForeRunner LE25 cards. In + addition to cable removal/reinsertion detection, this driver allows + you to control the loopback mode of the chip via a dedicated IOCTL. + This driver is required for proper handling of temporary carrier + loss, so if you have a 25Mbps NICStAR based ATM card you must say Y. + +IDT 77252 (NICStAR II) +CONFIG_ATM_IDT77252 + Driver for the IDT 77252 ATM PCI chips. + + This driver is also available as a module. If you want to compile + it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called idt77252.o + +Enable debugging messages +CONFIG_ATM_IDT77252_DEBUG + Somewhat useful debugging messages are available. The choice of + messages is controlled by a bitmap. This may be specified as a + module argument. See the file <file:drivers/atm/idt77252.h> for + the meanings of the bits in the mask. + + When active, these messages can have a significant impact on the + speed of the driver, and the size of your syslog files! When + inactive, they will have only a modest impact on performance. + +Receive ALL cells in raw queue +CONFIG_ATM_IDT77252_RCV_ALL + Enable receiving of all cells on the ATM link, that do not match + an open connection in the raw cell queue of the driver. Useful + for debugging or special applications only, so the safe answer is N. + +Madge Ambassador (Collage PCI 155 Server) +CONFIG_ATM_AMBASSADOR + This is a driver for ATMizer based ATM card produced by Madge + Networks Ltd. Say Y (or M to compile as a module named ambassador.o) + here if you have one of these cards. + +Enable debugging messages +CONFIG_ATM_AMBASSADOR_DEBUG + Somewhat useful debugging messages are available. The choice of + messages is controlled by a bitmap. This may be specified as a + module argument (kernel command line argument as well?), changed + dynamically using an ioctl (not yet) or changed by sending the + string "Dxxxx" to VCI 1023 (where x is a hex digit). See the file + <file:drivers/atm/ambassador.h> for the meanings of the bits in the + mask. + + When active, these messages can have a significant impact on the + speed of the driver, and the size of your syslog files! When + inactive, they will have only a modest impact on performance. + +Madge Horizon [Ultra] (Collage PCI 25 and Collage PCI 155 Client) +CONFIG_ATM_HORIZON + This is a driver for the Horizon chipset ATM adapter cards once + produced by Madge Networks Ltd. Say Y (or M to compile as a module + named horizon.o) here if you have one of these cards. + +Enable debugging messages +CONFIG_ATM_HORIZON_DEBUG + Somewhat useful debugging messages are available. The choice of + messages is controlled by a bitmap. This may be specified as a + module argument (kernel command line argument as well?), changed + dynamically using an ioctl (not yet) or changed by sending the + string "Dxxxx" to VCI 1023 (where x is a hex digit). See the file + <file:drivers/atm/horizon.h> for the meanings of the bits in the + mask. + + When active, these messages can have a significant impact on the + speed of the driver, and the size of your syslog files! When + inactive, they will have only a modest impact on performance. + +Interphase ATM PCI x575/x525/x531 +CONFIG_ATM_IA + This is a driver for the Interphase (i)ChipSAR adapter cards + which include a variety of variants in term of the size of the + control memory (128K-1KVC, 512K-4KVC), the size of the packet + memory (128K, 512K, 1M), and the PHY type (Single/Multi mode OC3, + UTP155, UTP25, DS3 and E3). Go to: + <http://www.iphase.com/products/ClassSheet.cfm?ClassID=ATM> + for more info about the cards. Say Y (or M to compile as a module + named iphase.o) here if you have one of these cards. + + See the file <file:Documentation/networking/iphase.txt> for further + details. + +Enable debugging messages +CONFIG_ATM_IA_DEBUG + Somewhat useful debugging messages are available. The choice of + messages is controlled by a bitmap. This may be specified as a + module argument (kernel command line argument as well?), changed + dynamically using an ioctl (Get the debug utility, iadbg, from + <ftp://ftp.iphase.com/pub/atm/pci/>). + + See the file <file:drivers/atm/iphase.h> for the meanings of the + bits in the mask. + + When active, these messages can have a significant impact on the + speed of the driver, and the size of your syslog files! When + inactive, they will have only a modest impact on performance. + +Efficient Networks Speedstream 3010 +CONFIG_ATM_LANAI + Supports ATM cards based on the Efficient Networks "Lanai" + chipset such as the Speedstream 3010 and the ENI-25p. The + Speedstream 3060 is currently not supported since we don't + have the code to drive the on-board Alcatel DSL chipset (yet). + +Linux telephony support +CONFIG_PHONE + Say Y here if you have a telephony card, which for example allows + you to use a regular phone for voice-over-IP applications. + + Note: this has nothing to do with modems. You do not need to say Y + here in order to be able to use a modem under Linux. + + This support is also available as a module. If you want to compile + it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + phonedev.o. + +Compaq Smart Array support +CONFIG_BLK_CPQ_CISS_DA + This is the driver for Compaq Smart Array 5xxx controllers. + Everyone using these boards should say Y here. + See <file:Documentation/cciss.txt> for the current list of + boards supported by this driver, and for further information + on the use of this driver. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + cciss.o + +SCSI tape drive support for Smart Array 5xxx +CONFIG_CISS_SCSI_TAPE + When enabled (Y), this option allows SCSI tape drives and SCSI medium + changers (tape robots) to be accessed via a Compaq 5xxx array + controller. (See Documentation/cciss.txt for more details.) + + "SCSI support" and "SCSI tape support" must also be enabled for this + option to work. + + When this option is disabled (N), the SCSI portion of the driver + is not compiled. + +QuickNet Internet LineJack/PhoneJack support +CONFIG_PHONE_IXJ + Say M if you have a telephony card manufactured by Quicknet + Technologies, Inc. These include the Internet PhoneJACK and + Internet LineJACK Telephony Cards. You will get a module called + ixj.o. + + For the ISA versions of these products, you can configure the + cards using the isapnp tools (pnpdump/isapnp) or you can use the + isapnp support. Please read <file:Documentation/telephony/ixj.txt>. + + For more information on these cards, see Quicknet's web site at: + <http://www.quicknet.net/>. + + If you do not have any Quicknet telephony cards, you can safely + say N here. + +QuickNet Internet LineJack/PhoneJack PCMCIA support +CONFIG_PHONE_IXJ_PCMCIA + Say Y here to configure in PCMCIA service support for the Quicknet + cards manufactured by Quicknet Technologies, Inc. This builds an + additional support module for the PCMCIA version of the card. + +FORE Systems 200E-series +CONFIG_ATM_FORE200E_MAYBE + This is a driver for the FORE Systems 200E-series ATM adapter + cards. It simultaneously supports PCA-200E and SBA-200E models + on PCI and SBUS hosts. Say Y (or M to compile as a module + named fore_200e.o) here if you have one of these ATM adapters. + + Note that the driver will actually be compiled only if you + additionally enable the support for PCA-200E and/or SBA-200E + cards. + + See the file <file:Documentation/networking/fore200e.txt> for + further details. + +Enable PCA-200E card support on PCI-based hosts +CONFIG_ATM_FORE200E_PCA + Say Y here if you want your PCA-200E cards to be probed. + +Use default PCA-200E firmware +CONFIG_ATM_FORE200E_PCA_DEFAULT_FW + Use the default PCA-200E firmware data shipped with the driver. + + Normal users do not have to deal with the firmware stuff, so + they should say Y here. + +Pathname of user-supplied binary firmware +CONFIG_ATM_FORE200E_PCA_FW + This defines the pathname of an alternative PCA-200E binary + firmware image supplied by the user. This pathname may be + absolute or relative to the drivers/atm directory. + + The driver comes with an adequate firmware image, so normal users do + not have to supply an alternative one. They just say Y to "Use + default PCA-200E firmware" instead. + +Enable SBA-200E card support on SBUS-based hosts +CONFIG_ATM_FORE200E_SBA + Say Y here if you want your SBA-200E cards to be probed. + +Use default SBA-200E firmware +CONFIG_ATM_FORE200E_SBA_DEFAULT_FW + Use the default SBA-200E firmware data shipped with the driver. + + Normal users do not have to deal with the firmware stuff, so + they should say Y here. + +Pathname of user-supplied binary firmware +CONFIG_ATM_FORE200E_SBA_FW + This defines the pathname of an alternative SBA-200E binary + firmware image supplied by the user. This pathname may be + absolute or relative to the drivers/atm directory. + + The driver comes with an adequate firmware image, so normal users do + not have to supply an alternative one. They just say Y to "Use + default SBA-200E firmware", above. + +Maximum number of tx retries +CONFIG_ATM_FORE200E_TX_RETRY + Specifies the number of times the driver attempts to transmit + a message before giving up, if the transmit queue of the ATM card + is transiently saturated. + + Saturation of the transmit queue may occur only under extreme + conditions, e.g. when a fast host continuously submits very small + frames (<64 bytes) or raw AAL0 cells (48 bytes) to the ATM adapter. + + Note that under common conditions, it is unlikely that you encounter + a saturation of the transmit queue, so the retry mechanism never + comes into play. + +Debugging level (0-3) +CONFIG_ATM_FORE200E_DEBUG + Specifies the level of debugging messages issued by the driver. + The verbosity of the driver increases with the value of this + parameter. + + When active, these messages can have a significant impact on + the performances of the driver, and the size of your syslog files! + Keep the debugging level to 0 during normal operations. + +PPP over ATM +CONFIG_PPPOATM + Support PPP (Point to Point Protocol) encapsulated in ATM frames. + This implementation does not yet comply with section 8 of RFC2364, + which can lead to bad results idf the ATM peer loses state and + changes its encapsulation unilaterally. + +Fusion MPT device support +CONFIG_FUSION + LSI Logic Fusion(TM) Message Passing Technology (MPT) device support + provides high performance SCSI host initiator, and LAN [1] interface + services to a host system. The Fusion architecture is capable of + duplexing these protocols on high-speed Fibre Channel + (up to 2 GHz x 2 ports = 4 GHz) and parallel SCSI (up to Ultra-320) + physical medium. + + [1] LAN is not supported on parallel SCSI medium. + + These drivers require a Fusion MPT compatible PCI adapter installed + in the host system. MPT adapters contain specialized I/O processors + to handle I/O workload, and more importantly to offload this work + from the host CPU(s). + + If you have Fusion MPT hardware and want to use it, you can say + Y or M here to add MPT (base + ScsiHost) drivers. + <Y> = build lib (fusion.o), and link [static] into the kernel [2] + proper + <M> = compiled as [dynamic] modules [3] named: (mptbase.o, + mptscsih.o) + + [2] In order enable capability to boot the linux kernel + natively from a Fusion MPT target device, you MUST + answer Y here! (currently requires CONFIG_BLK_DEV_SD) + [3] This support is also available as a module ( = code + which can be inserted in and removed from the running + kernel whenever you want). If you want to compile as + modules, say M here and read + <file:Documentation/modules.txt>. + + If unsure, say N. + + If you say Y or M here you will get a choice of these + additional protocol and support module options: Module Name: + <M> Enhanced SCSI error reporting (isense.o) + <M> Fusion MPT misc device (ioctl) driver (mptctl.o) + <M> Fusion MPT LAN driver (mptlan.o) + + --- + Fusion MPT is trademark of LSI Logic Corporation, and its + architecture is based on LSI Logic's Message Passing Interface (MPI) + specification. + +Fusion MPT enhanced SCSI error reporting [optional] module +CONFIG_FUSION_ISENSE + The isense module (roughly stands for Interpret SENSE data) is + completely optional. It simply provides extra English readable + strings in SCSI Error Report(s) that might be generated from the + Fusion MPT SCSI Host driver, for example when a target device + returns a SCSI check condition on a I/O. Without this module + loaded you might see: + + SCSI Error Report =-=-= (ioc0,scsi5:0) + SCSI_Status=02h (CHECK_CONDITION) + Original_CDB[]: 2A 00 00 00 00 41 00 00 02 00 + SenseData[12h]: 70 00 02 00 00 00 00 0A 00 00 00 00 04 02 02 00 00 00 + SenseKey=2h (NOT READY); FRU=02h + ASC/ASCQ=29h/00h + + Where otherwise, if this module had been loaded, you would see: + + SCSI Error Report =-=-= (ioc0,scsi5:0) + SCSI_Status=02h (CHECK_CONDITION) + Original_CDB[]: 2A 00 00 00 00 41 00 00 02 00 - "WRITE(10)" + SenseData[12h]: 70 00 02 00 00 00 00 0A 00 00 00 00 04 02 02 00 00 00 + SenseKey=2h (NOT READY); FRU=02h + ASC/ASCQ=29h/00h "LOGICAL UNIT NOT READY, INITIALIZING CMD. REQUIRED" + + Say M for "Enhanced SCSI error reporting" to compile this optional module, + creating a driver named: isense.o. + + NOTE: Support for building this feature into the kernel is not + available, due to kernel size considerations. + +Fusion MPT misc device (ioctl) driver [optional] module +CONFIG_FUSION_CTL + The Fusion MPT misc device driver provides specialized control + of MPT adapters via system ioctl calls. Use of ioctl calls to + the MPT driver requires that you create and use a misc device + node ala: + mknod /dev/mptctl c 10 240 + + One use of this ioctl interface is to perform an upgrade (reflash) + of the MPT adapter firmware. Refer to readme file(s) distributed + with the Fusion MPT linux driver for additional details. + + If enabled by saying M to this, a driver named: mptctl.o + will be compiled. + + If unsure whether you really want or need this, say N. + +Fusion MPT LAN driver [optional] +CONFIG_FUSION_LAN + This module supports LAN IP traffic over Fibre Channel port(s) + on Fusion MPT compatible hardware (LSIFC9xx chips). + The physical interface used is defined in RFC 2625. + Please refer to that document for details. + + Installing this driver requires the knowledge to configure and + activate a new network interface, "fc0", using standard Linux tools. + + If enabled by saying M to this, a driver named: mptlan.o + will be compiled. + + If unsure whether you really want or need this, say N. + + NOTES: This feature is NOT available nor supported for linux-2.2.x + kernels. You must be building a linux-2.3.x or linux-2.4.x kernel + in order to configure this option. + Support for building this feature into the linux kernel is not + yet available. + +SCSI support +CONFIG_SCSI + If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or + any other SCSI device under Linux, say Y and make sure that you know + the name of your SCSI host adapter (the card inside your computer + that "speaks" the SCSI protocol, also called SCSI controller), + because you will be asked for it. + + You also need to say Y here if you want support for the parallel + port version of the 100 MB IOMEGA ZIP drive. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called scsi_mod.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt> and + <file:Documentation/scsi.txt>. However, do not compile this as a + module if your root file system (the one containing the directory /) + is located on a SCSI device. + +SCSI disk support +CONFIG_BLK_DEV_SD + If you want to use a SCSI hard disk or the SCSI or parallel port + version of the IOMEGA ZIP drive under Linux, say Y and read the + SCSI-HOWTO, the Disk-HOWTO and the Multi-Disk-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. This is NOT for SCSI + CD-ROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called sd_mod.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> and + <file:Documentation/scsi.txt>. Do not compile this driver as a + module if your root file system (the one containing the directory /) + is located on a SCSI disk. In this case, do not compile the driver + for your SCSI host adapter (below) as a module either. + +Maximum number of SCSI disks that can be loaded as modules +CONFIG_SD_EXTRA_DEVS + This controls the amount of additional space allocated in tables for + drivers that are loaded as modules after the kernel is booted. In + the event that the SCSI core itself was loaded as a module, this + value is the number of additional disks that can be loaded after the + first host driver is loaded. + + Admittedly this isn't pretty, but there are tons of race conditions + involved with resizing the internal arrays on the fly. Someday this + flag will go away, and everything will work automatically. + + If you don't understand what's going on, go with the default. + +Maximum number of SCSI tapes that can be loaded as modules +CONFIG_ST_EXTRA_DEVS + This controls the amount of additional space allocated in tables for + drivers that are loaded as modules after the kernel is booted. In + the event that the SCSI core itself was loaded as a module, this + value is the number of additional tapes that can be loaded after the + first host driver is loaded. + + Admittedly this isn't pretty, but there are tons of race conditions + involved with resizing the internal arrays on the fly. Someday this + flag will go away, and everything will work automatically. + + If you don't understand what's going on, go with the default. + +SCSI tape support +CONFIG_CHR_DEV_ST + If you want to use a SCSI tape drive under Linux, say Y and read the + SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>, and + <file:drivers/scsi/README.st> in the kernel source. This is NOT for + SCSI CD-ROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called st.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> and + <file:Documentation/scsi.txt>. + +OnStream SC-x0 SCSI tape support +CONFIG_CHR_DEV_OSST + The OnStream SC-x0 SCSI tape drives can not be driven by the + standard st driver, but instead need this special osst driver and + use the /dev/osstX char device nodes (major 206). Via usb-storage + and ide-scsi, you may be able to drive the USB-x0 and DI-x0 drives + as well. Note that there is also a second generation of OnStream + tape drives (ADR-x0) that supports the standard SCSI-2 commands for + tapes (QIC-157) and can be driven by the standard driver st. + For more information, you may have a look at the SCSI-HOWTO + <http://www.tldp.org/docs.html#howto> and + <file:drivers/scsi/README.osst> in the kernel source. + More info on the OnStream driver may be found on + <http://linux1.onstream.nl/test/> + Please also have a look at the standard st docu, as most of it + applies to osst as well. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called osst.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> and + <file:Documentation/scsi.txt>. + +SCSI CD-ROM support +CONFIG_BLK_DEV_SR + If you want to use a SCSI CD-ROM under Linux, say Y and read the + SCSI-HOWTO and the CD-ROM-HOWTO at + <http://www.tldp.org/docs.html#howto>. Also make sure to say Y + or M to "ISO 9660 CD-ROM file system support" later. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called sr_mod.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> and + <file:Documentation/scsi.txt>. + +Maximum number of CD-ROM devices that can be loaded as modules +CONFIG_SR_EXTRA_DEVS + This controls the amount of additional space allocated in tables for + drivers that are loaded as modules after the kernel is booted. In + the event that the SCSI core itself was loaded as a module, this + value is the number of additional CD-ROMs that can be loaded after + the first host driver is loaded. + + Admittedly this isn't pretty, but there are tons of race conditions + involved with resizing the internal arrays on the fly. Someday this + flag will go away, and everything will work automatically. + + If you don't understand what's going on, go with the default. + +Enable vendor-specific extensions (for SCSI CD-ROM) +CONFIG_BLK_DEV_SR_VENDOR + This enables the usage of vendor specific SCSI commands. This is + required to support multisession CDs with old NEC/TOSHIBA cdrom + drives (and HP Writers). If you have such a drive and get the first + session only, try saying Y here; everybody else says N. + +SCSI generic support +CONFIG_CHR_DEV_SG + If you want to use SCSI scanners, synthesizers or CD-writers or just + about anything having "SCSI" in its name other than hard disks, + CD-ROMs or tapes, say Y here. These won't be supported by the kernel + directly, so you need some additional software which knows how to + talk to these devices using the SCSI protocol: + + For scanners, look at SANE (<http://www.mostang.com/sane/>). For CD + writer software look at Cdrtools + (<http://www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private/cdrecord.html>) + and for burning a "disk at once": CDRDAO + (<http://cdrdao.sourceforge.net/>). Cdparanoia is a high + quality digital reader of audio CDs (<http://www.xiph.org/paranoia/>). + For other devices, it's possible that you'll have to write the + driver software yourself. Please read the file + <file:Documentation/scsi-generic.txt> for more information. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt> and + <file:Documentation/scsi.txt>. The module will be called sg.o. If unsure, + say N. + +Probe all LUNs on each SCSI device +CONFIG_SCSI_MULTI_LUN + If you have a SCSI device that supports more than one LUN (Logical + Unit Number), e.g. a CD jukebox, and only one LUN is detected, you + can say Y here to force the SCSI driver to probe for multiple LUNs. + A SCSI device with multiple LUNs acts logically like multiple SCSI + devices. The vast majority of SCSI devices have only one LUN, and + so most people can say N here and should in fact do so, because it + is safer. + +Verbose SCSI error reporting (kernel size +=12K) +CONFIG_SCSI_CONSTANTS + The error messages regarding your SCSI hardware will be easier to + understand if you say Y here; it will enlarge your kernel by about + 12 KB. If in doubt, say Y. + +SCSI logging facility +CONFIG_SCSI_LOGGING + This turns on a logging facility that can be used to debug a number + of SCSI related problems. + + If you say Y here, no logging output will appear by default, but you + can enable logging by saying Y to "/proc file system support" and + "Sysctl support" below and executing the command + + echo "scsi log token [level]" > /proc/scsi/scsi + + at boot time after the /proc file system has been mounted. + + There are a number of things that can be used for 'token' (you can + find them in the source: <file:drivers/scsi/scsi.c>), and this + allows you to select the types of information you want, and the + level allows you to select the level of verbosity. + + If you say N here, it may be harder to track down some types of SCSI + problems. If you say Y here your kernel will be somewhat larger, but + there should be no noticeable performance impact as long as you have + logging turned off. + +SGI WD93C93 SCSI Driver +CONFIG_SCSI_SGIWD93 + Say Y here to support the on-board WD93C93 SCSI controller found (a) + on the Indigo2 and other MIPS-based SGI machines, and (b) on ARCS + ARM-based machines. + +DEC NCR53C94 SCSI Driver +CONFIG_SCSI_DECNCR + Say Y here to support the NCR53C94 SCSI controller chips on IOASIC + based TURBOchannel DECstations and TURBOchannel PMAZ-A cards. + +AdvanSys SCSI support +CONFIG_SCSI_ADVANSYS + This is a driver for all SCSI host adapters manufactured by + AdvanSys. It is documented in the kernel source in + <file:drivers/scsi/advansys.c>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + advansys.o. + +Adaptec AHA152X/2825 support +CONFIG_SCSI_AHA152X + This is a driver for the AHA-1510, AHA-1520, AHA-1522, and AHA-2825 + SCSI host adapters. It also works for the AVA-1505, but the IRQ etc. + must be manually specified in this case. + + It is explained in section 3.3 of the SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. You might also want to + read the file <file:drivers/scsi/README.aha152x>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called aha152x.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Adaptec AHA1542 support +CONFIG_SCSI_AHA1542 + This is support for a SCSI host adapter. It is explained in section + 3.4 of the SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. Note that Trantor was + purchased by Adaptec, and some former Trantor products are being + sold under the Adaptec name. If it doesn't work out of the box, you + may have to change some settings in <file:drivers/scsi/aha1542.h>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called aha1542.o. + +Adaptec AHA1740 support +CONFIG_SCSI_AHA1740 + This is support for a SCSI host adapter. It is explained in section + 3.5 of the SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. If it doesn't work out + of the box, you may have to change some settings in + <file:drivers/scsi/aha1740.h>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called aha1740.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Adaptec AIC7xxx support +CONFIG_SCSI_AIC7XXX + This driver supports all of Adaptec's PCI based SCSI controllers + (not the hardware RAID controllers though) as well as the aic7770 + based EISA and VLB SCSI controllers (the 274x and 284x series). + This is an Adaptec sponsored driver written by Justin Gibbs. It is + intended to replace the previous aic7xxx driver maintained by Doug + Ledford since Doug is no longer maintaining that driver. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called aic7xxx.o. + +Adaptec I2O RAID support +CONFIG_SCSI_DPT_I2O + This driver supports all of Adaptec's I2O based RAID controllers as + well as the DPT SmartRaid V cards. This is an Adaptec maintained + driver by Deanna Bonds. See <file:drivers/scsi/README.dpti>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + dpt_i2o.o. + +Default number of TCQ commands per device +CONFIG_AIC7XXX_CMDS_PER_DEVICE + Specify the number of commands you would like to allocate per SCSI + device when Tagged Command Queueing (TCQ) is enabled on that device. + + This is an upper bound value for the number of tagged transactions + to be used for any device. The aic7xxx driver will automatically + vary this number based on device behaviour. For devices with a + fixed maximum, the driver will eventually lock to this maximum + and display a console message indicating this value. + + Note: Unless you experience some type of device failure, the default + value, no enforced limit, should work for you. + + Default: 253 + +Delay in seconds after SCSI bus reset +CONFIG_AIC7XXX_RESET_DELAY_MS + The number of milliseconds to delay after an initial bus reset. + The bus settle delay following all error recovery actions is + dictated by the SCSI layer and is not affected by this value. + + Default: 15000 (15 seconds) + +Build Adapter Firmware with Kernel Build +CONFIG_AIC7XXX_BUILD_FIRMWARE + This option should only be enabled if you are modifying the firmware + source to the aic7xxx driver and wish to have the generated firmware + include files updated during a normal kernel build. The assembler + for the firmware requires lex and yacc or their equivalents, as well + as the db v1 library. You may have to install additional packages + or modify the assembler make file or the files it includes if your + build environment is different than that of the author. + +Old Adaptec AIC7xxx support +CONFIG_SCSI_AIC7XXX_OLD + WARNING This driver is an older aic7xxx driver and is no longer + under active development. Adaptec, Inc. is writing a new driver to + take the place of this one, and it is recommended that whenever + possible, people should use the new Adaptec written driver instead + of this one. This driver will eventually be phased out entirely. + + This is support for the various aic7xxx based Adaptec SCSI + controllers. These include the 274x EISA cards; 284x VLB cards; + 2902, 2910, 293x, 294x, 394x, 3985 and several other PCI and + motherboard based SCSI controllers from Adaptec. It does not support + the AAA-13x RAID controllers from Adaptec, nor will it likely ever + support them. It does not support the 2920 cards from Adaptec that + use the Future Domain SCSI controller chip. For those cards, you + need the "Future Domain 16xx SCSI support" driver. + + In general, if the controller is based on an Adaptec SCSI controller + chip from the aic777x series or the aic78xx series, this driver + should work. The only exception is the 7810 which is specifically + not supported (that's the RAID controller chip on the AAA-13x + cards). + + Note that the AHA2920 SCSI host adapter is *not* supported by this + driver; choose "Future Domain 16xx SCSI support" instead if you have + one of those. + + Information on the configuration options for this controller can be + found by checking the help file for each of the available + configuration options. You should read + <file:drivers/scsi/aic7xxx_old/README.aic7xxx> at a minimum before + contacting the maintainer with any questions. The SCSI-HOWTO, + available from <http://www.tldp.org/docs.html#howto>, can also + be of great help. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called aic7xxx_old.o. + +Enable tagged command queueing (TCQ) by default +CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT + This option causes the aic7xxx driver to attempt to use Tagged + Command Queueing (TCQ) on all devices that claim to support it. + + TCQ is a feature of SCSI-2 which improves performance: the host + adapter can send several SCSI commands to a device's queue even if + previous commands haven't finished yet. Because the device is + intelligent, it can optimize its operations (like head positioning) + based on its own request queue. Not all devices implement this + correctly. + + If you say Y here, you can still turn off TCQ on troublesome devices + with the use of the tag_info boot parameter. See the file + <file:drivers/scsi/README.aic7xxx> for more information on that and + other aic7xxx setup commands. If this option is turned off, you may + still enable TCQ on known good devices by use of the tag_info boot + parameter. + + If you are unsure about your devices then it is safest to say N + here. + + However, TCQ can increase performance on some hard drives by as much + as 50% or more, so it is recommended that if you say N here, you + should at least read the <file:drivers/scsi/README.aic7xxx> file so + you will know how to enable this option manually should your drives + prove to be safe in regards to TCQ. + + Conversely, certain drives are known to lock up or cause bus resets + when TCQ is enabled on them. If you have a Western Digital + Enterprise SCSI drive for instance, then don't even bother to enable + TCQ on it as the drive will become unreliable, and it will actually + reduce performance. + +Default number of TCQ commands per device +CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE + Specify the number of commands you would like to allocate per SCSI + device when Tagged Command Queueing (TCQ) is enabled on that device. + + Reasonable figures are in the range of 8 to 24 commands per device, + but depending on hardware could be increased or decreased from that + figure. If the number is too high for any particular device, the + driver will automatically compensate usually after only 10 minutes + of uptime. It will not hinder performance if some of your devices + eventually have their command depth reduced, but is a waste of + memory if all of your devices end up reducing this number down to a + more reasonable figure. + + NOTE: Certain very broken drives are known to lock up when given + more commands than they like to deal with. Quantum Fireball drives + are the most common in this category. For the Quantum Fireball + drives it is suggested to use no more than 8 commands per device. + + Default: 8 + +Collect statistics to report in /proc +CONFIG_AIC7XXX_OLD_PROC_STATS + This option tells the driver to keep track of how many commands have + been sent to each particular device and report that information to + the user via the /proc/scsi/aic7xxx/n file, where n is the number of + the aic7xxx controller you want the information on. This adds a + small amount of overhead to each and every SCSI command the aic7xxx + driver handles, so if you aren't really interested in this + information, it is best to leave it disabled. This will only work if + you also say Y to "/proc file system support", below. + + If unsure, say N. + +IBM ServeRAID support +CONFIG_SCSI_IPS + This is support for the IBM ServeRAID hardware RAID controllers. + See <http://www.developer.ibm.com/welcome/netfinity/serveraid.html> + for more information. If this driver does not work correctly + without modification please contact the author by email at + ipslinux@us.ibm.com. + + You can build this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + but only a single instance may be loaded. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + The module will be called ips.o. + +BusLogic SCSI support +CONFIG_SCSI_BUSLOGIC + This is support for BusLogic MultiMaster and FlashPoint SCSI Host + Adapters. Consult the SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>, and the files + <file:drivers/scsi/README.BusLogic> and + <file:drivers/scsi/README.FlashPoint> for more information. If this + driver does not work correctly without modification, please contact + the author, Leonard N. Zubkoff, by email to lnz@dandelion.com. + + You can also build this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + but only a single instance may be loaded. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + The module will be called BusLogic.o. + +Omit BusLogic SCSI FlashPoint support +CONFIG_SCSI_OMIT_FLASHPOINT + This option allows you to omit the FlashPoint support from the + BusLogic SCSI driver. The FlashPoint SCCB Manager code is + substantial, so users of MultiMaster Host Adapters may wish to omit + it. + +Compaq Fibre Channel 64-bit/66Mhz HBA support +CONFIG_SCSI_CPQFCTS + Say Y here to compile in support for the Compaq StorageWorks Fibre + Channel 64-bit/66Mhz Host Bus Adapter. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called cpqfc.o. + +DMX3191D SCSI support +CONFIG_SCSI_DMX3191D + This is support for Domex DMX3191D SCSI Host Adapters. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called dmx3191d.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +DTC3180/3280 SCSI support +CONFIG_SCSI_DTC3280 + This is support for DTC 3180/3280 SCSI Host Adapters. Please read + the SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>, and the file + <file:drivers/scsi/README.dtc3x80>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called dtc.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +EATA-DMA [Obsolete] (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support +CONFIG_SCSI_EATA_DMA + This is support for the EATA-DMA protocol compliant SCSI Host + Adapters like the SmartCache III/IV, SmartRAID controller families + and the DPT PM2011B and PM2012B controllers. + + Note that this driver is obsolete; if you have one of the above + SCSI Host Adapters, you should normally say N here and Y to "EATA + ISA/EISA/PCI support", below. Please read the SCSI-HOWTO, available + from <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called eata_dma.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +EATA-PIO (old DPT PM2001, PM2012A) support +CONFIG_SCSI_EATA_PIO + This driver supports all EATA-PIO protocol compliant SCSI Host + Adapters like the DPT PM2001 and the PM2012A. EATA-DMA compliant + host adapters could also use this driver but are discouraged from + doing so, since this driver only supports hard disks and lacks + numerous features. You might want to have a look at the SCSI-HOWTO, + available from <http://www.tldp.org/docs.html#howto>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called eata_pio.o. + +UltraStor 14F/34F support +CONFIG_SCSI_U14_34F + This is support for the UltraStor 14F and 34F SCSI-2 host adapters. + The source at <file:drivers/scsi/u14-34f.c> contains some + information about this hardware. If the driver doesn't work out of + the box, you may have to change some settings in + <file: drivers/scsi/u14-34f.c>. Read the SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. Note that there is also + another driver for the same hardware: "UltraStor SCSI support", + below. You should say Y to both only if you want 24F support as + well. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called u14-34f.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +enable elevator sorting +CONFIG_SCSI_U14_34F_LINKED_COMMANDS + This option enables elevator sorting for all probed SCSI disks and + CD-ROMs. It definitely reduces the average seek distance when doing + random seeks, but this does not necessarily result in a noticeable + performance improvement: your mileage may vary... + + The safe answer is N. + +maximum number of queued commands +CONFIG_SCSI_U14_34F_MAX_TAGS + This specifies how many SCSI commands can be maximally queued for + each probed SCSI device. You should reduce the default value of 8 + only if you have disks with buggy or limited tagged command support. + Minimum is 2 and maximum is 14. This value is also the window size + used by the elevator sorting option above. The effective value used + by the driver for each probed SCSI device is reported at boot time. + +Future Domain 16xx SCSI/AHA-2920A support +CONFIG_SCSI_FUTURE_DOMAIN + This is support for Future Domain's 16-bit SCSI host adapters + (TMC-1660/1680, TMC-1650/1670, TMC-3260, TMC-1610M/MER/MEX) and + other adapters based on the Future Domain chipsets (Quantum + ISA-200S, ISA-250MG; Adaptec AHA-2920A; and at least one IBM board). + It is explained in section 3.7 of the SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + NOTE: Newer Adaptec AHA-2920C boards use the Adaptec AIC-7850 chip + and should use the aic7xxx driver ("Adaptec AIC7xxx chipset SCSI + controller support"). This Future Domain driver works with the older + Adaptec AHA-2920A boards with a Future Domain chip on them. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called fdomain.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Future Domain MCS-600/700 SCSI support +CONFIG_SCSI_FD_MCS + This is support for Future Domain MCS 600/700 MCA SCSI adapters. + Some PS/2 computers are equipped with IBM Fast SCSI Adapter/A which + is identical to the MCS 700 and hence also supported by this driver. + This driver also supports the Reply SB16/SCSI card (the SCSI part). + It supports multiple adapters in the same system. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called fd_mcs.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Generic NCR5380/53c400 SCSI support +CONFIG_SCSI_GENERIC_NCR5380 + This is the generic NCR family of SCSI controllers, not to be + confused with the NCR 53c7 or 8xx controllers. It is explained in + section 3.8 of the SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. If it doesn't work out + of the box, you may have to change some settings in + <file:drivers/scsi/g_NCR5380.h>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called g_NCR5380.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +Enable NCR53c400 extensions +CONFIG_SCSI_GENERIC_NCR53C400 + This enables certain optimizations for the NCR53c400 SCSI cards. + You might as well try it out. Note that this driver will only probe + for the Trantor T130B in its default configuration; you might have + to pass a command line option to the kernel at boot time if it does + not detect your card. See the file + <file:drivers/scsi/README.g_NCR5380> for details. + +# Choice: ncr5380 +NCR5380/53c400 mapping method (use Port for T130B) +CONFIG_SCSI_G_NCR5380_PORT + The NCR5380 and NCR53c400 SCSI controllers come in two varieties: + port or memory mapped. You should know what you have. The most + common card, Trantor T130B, uses port mapped mode. + +NCR Dual 700 MCA SCSI support +CONFIG_SCSI_NCR_D700 + This is a driver for the MicroChannel Dual 700 card produced by + NCR and commonly used in 345x/35xx/4100 class machines. It always + tries to negotiate sync and uses tag command queueing. + + Unless you have an NCR manufactured machine, the chances are that + you do not have this SCSI card, so say N. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called NCR_D700.o. + +HP LASI SCSI support for 53c700/710 +CONFIG_SCSI_LASI700 + This is a driver for the lasi baseboard in some parisc machines + which is based on the 53c700 chip. Will also support LASI subsystems + based on the 710 chip using 700 emulation mode. + + Unless you know you have a 53c700 or 53c710 based lasi, say N here + +NCR53c7,8xx SCSI support +CONFIG_SCSI_NCR53C7xx + This is a driver for the 53c7 and 8xx NCR family of SCSI + controllers, not to be confused with the NCR 5380 controllers. It + is explained in section 3.8 of the SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. If it doesn't work out + of the box, you may have to change some settings in + <file:drivers/scsi/53c7,8xx.h>. Please read + <file:drivers/scsi/README.ncr53c7xx> for the available boot time + command line options. + + Note: there is another driver for the 53c8xx family of controllers + ("NCR53C8XX SCSI support" below). If you want to use them both, you + need to say M to both and build them as modules, but only one may be + active at a time. If you have a 53c8xx board, it's better to use the + other driver. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called 53c7,8xx.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +Always negotiate synchronous transfers +CONFIG_SCSI_NCR53C7xx_sync + In general, this is good; however, it is a bit dangerous since there + are some broken SCSI devices out there. Take your chances. Safe bet + is N. + +Allow FAST-SCSI [10MHz] +CONFIG_SCSI_NCR53C7xx_FAST + This will enable 10MHz FAST-SCSI transfers with your host + adapter. Some systems have problems with that speed, so it's safest + to say N here. + +Allow DISCONNECT +CONFIG_SCSI_NCR53C7xx_DISCONNECT + This enables the disconnect/reconnect feature of the NCR SCSI + controller. When you say Y here, a slow SCSI device will not lock + the SCSI bus while processing a request, allowing simultaneous use + of e.g. a SCSI hard disk and SCSI tape or CD-ROM drive, and + providing much better performance when using slow and fast SCSI + devices at the same time. Some devices, however, do not operate + properly with this option enabled, and will cause your SCSI system + to hang, which might cause a system crash. The safe answer + therefore is to say N. + +SYM53C8XX Version 2 SCSI support +CONFIG_SCSI_SYM53C8XX_2 + This driver supports the whole NCR53C8XX/SYM53C8XX family of + PCI-SCSI controllers. It also supports the subset of LSI53C10XX + Ultra-160 controllers that are based on the SYM53C8XX SCRIPTS + language. It does not support LSI53C10XX Ultra-320 PCI-X SCSI + controllers. + + If your system has problems using this new major version of the + SYM53C8XX driver, you may switch back to driver version 1. + + Please read <file:drivers/scsi/sym53c8xx_2/Documentation.txt> for more + information. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called sym53c8xx.o. + +PCI DMA addressing mode +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE + This option only applies to PCI-SCSI chip that are PCI DAC capable + (875A, 895A, 896, 1010-33, 1010-66, 1000). + + When set to 0, only PCI 32 bit DMA addressing (SAC) will be performed. + When set to 1, 40 bit DMA addressing (with upper 24 bits of address + set to zero) is supported. The addressable range is here 1 TB. + When set to 2, full 64 bits of address for DMA are supported, but only + 16 segments of 4 GB can be addressed. The addressable range is so + limited to 64 GB. + + The safest value is 0 (32 bit DMA addressing) that is guessed to still + fit most of real machines. + + The preferred value 1 (40 bit DMA addressing) should make happy + properly engineered PCI DAC capable host bridges. You may configure + this option for Intel platforms with more than 4 GB of memory. + + The still experimental value 2 (64 bit DMA addressing with 16 x 4GB + segments limitation) can be used on systems that require PCI address + bits past bit 39 to be set for the addressing of memory using PCI + DAC cycles. + +use normal IO +CONFIG_SCSI_SYM53C8XX_IOMAPPED + If you say Y here, the driver will preferently use normal IO rather than + memory mapped IO. + +maximum number of queued commands +CONFIG_SCSI_SYM53C8XX_MAX_TAGS + This option allows you to specify the maximum number of commands + that can be queued to any device, when tagged command queuing is + possible. The driver supports up to 256 queued commands per device. + This value is used as a compiled-in hard limit. + +default tagged command queue depth +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS + This is the default value of the command queue depth the driver will + announce to the generic SCSI layer for devices that support tagged + command queueing. This value can be changed from the boot command line. + This is a soft limit that cannot exceed CONFIG_SCSI_SYM53C8XX_MAX_TAGS. + +NCR53C8XX SCSI support +CONFIG_SCSI_NCR53C8XX + This is the BSD ncr driver adapted to Linux for the NCR53C8XX family + of PCI-SCSI controllers. This driver supports parity checking, + tagged command queuing and fast synchronous data transfers up to 80 + MB/s with wide FAST-40 LVD devices and controllers. + + Recent versions of the 53C8XX chips are better supported by the + option "SYM53C8XX SCSI support", below. + + Note: there is yet another driver for the 53c8xx family of + controllers ("NCR53c7,8xx SCSI support" above). If you want to use + them both, you need to say M to both and build them as modules, but + only one may be active at a time. If you have a 53c8xx board, you + probably do not want to use the "NCR53c7,8xx SCSI support". + + Please read <file:drivers/scsi/README.ncr53c8xx> for more + information. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called ncr53c8xx.o. + +SYM53C8XX Version 1 SCSI support +CONFIG_SCSI_SYM53C8XX + This driver supports all the features of recent 53C8XX chips (used + in PCI SCSI controllers), notably the hardware phase mismatch + feature of the SYM53C896. + + Older versions of the 53C8XX chips are not supported by this + driver. If your system uses either a 810 rev. < 16, a 815, or a 825 + rev. < 16 PCI SCSI processor, you must use the generic NCR53C8XX + driver ("NCR53C8XX SCSI support" above) or configure both the + NCR53C8XX and this SYM53C8XX drivers either as module or linked to + the kernel image. + + When both drivers are linked into the kernel, the SYM53C8XX driver + is called first at initialization and you can use the 'excl=ioaddr' + driver boot option to exclude attachment of adapters by the + SYM53C8XX driver. For example, entering + 'sym53c8xx=excl:0xb400,excl=0xc000' at the lilo prompt prevents + adapters at io address 0xb400 and 0xc000 from being attached by the + SYM53C8XX driver, thus allowing the NCR53C8XX driver to attach them. + The 'excl' option is also supported by the NCR53C8XX driver. + + Please read <file:drivers/scsi/README.ncr53c8xx> for more + information. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called sym53c8xx.o. + +Synchronous transfer frequency in MHz +CONFIG_SCSI_NCR53C8XX_SYNC + The SCSI Parallel Interface-2 Standard defines 5 classes of transfer + rates: FAST-5, FAST-10, FAST-20, FAST-40 and FAST-80. The numbers + are respectively the maximum data transfer rates in mega-transfers + per second for each class. For example, a FAST-20 Wide 16 device is + able to transfer data at 20 million 16 bit packets per second for a + total rate of 40 MB/s. + + You may specify 0 if you want to only use asynchronous data + transfers. This is the safest and slowest option. Otherwise, specify + a value between 5 and 80, depending on the capability of your SCSI + controller. The higher the number, the faster the data transfer. + Note that 80 should normally be ok since the driver decreases the + value automatically according to the controller's capabilities. + + Your answer to this question is ignored for controllers with NVRAM, + since the driver will get this information from the user set-up. It + also can be overridden using a boot setup option, as follows + (example): 'ncr53c8xx=sync:12' will allow the driver to negotiate + for FAST-20 synchronous data transfer (20 mega-transfers per + second). + + The normal answer therefore is not to go with the default but to + select the maximum value 80 allowing the driver to use the maximum + value supported by each controller. If this causes problems with + your SCSI devices, you should come back and decrease the value. + + There is no safe option other than using good cabling, right + terminations and SCSI conformant devices. + +Use normal IO +CONFIG_SCSI_NCR53C8XX_IOMAPPED + If you say Y here, the driver will use normal IO, as opposed to + memory mapped IO. Memory mapped IO has less latency than normal IO + and works for most Intel-based hardware. Under Linux/Alpha only + normal IO is currently supported by the driver and so, this option + has no effect on those systems. + + The normal answer therefore is N; try Y only if you encounter SCSI + related problems. + +Not allow targets to disconnect +CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT + This option is only provided for safety if you suspect some SCSI + device of yours to not support properly the target-disconnect + feature. In that case, you would say Y here. In general however, to + not allow targets to disconnect is not reasonable if there is more + than 1 device on a SCSI bus. The normal answer therefore is N. + +Default tagged command queue depth +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS + "Tagged command queuing" is a feature of SCSI-2 which improves + performance: the host adapter can send several SCSI commands to a + device's queue even if previous commands haven't finished yet. + Because the device is intelligent, it can optimize its operations + (like head positioning) based on its own request queue. Some SCSI + devices don't implement this properly; if you want to disable this + feature, enter 0 or 1 here (it doesn't matter which). + + The default value is 8 and should be supported by most hard disks. + This value can be overridden from the boot command line using the + 'tags' option as follows (example): + 'ncr53c8xx=tags:4/t2t3q16/t0u2q10' will set default queue depth to + 4, set queue depth to 16 for target 2 and target 3 on controller 0 + and set queue depth to 10 for target 0 / lun 2 on controller 1. + + The normal answer therefore is to go with the default 8 and to use + a boot command line option for devices that need to use a different + command queue depth. + + There is no safe option other than using good SCSI devices. + +Maximum number of queued commands +CONFIG_SCSI_NCR53C8XX_MAX_TAGS + This option allows you to specify the maximum number of commands + that can be queued to any device, when tagged command queuing is + possible. The default value is 32. Minimum is 2, maximum is 64. + Modern hard disks are able to support 64 tags and even more, but + do not seem to be faster when more than 32 tags are being used. + + So, the normal answer here is to go with the default value 32 unless + you are using very large hard disks with large cache (>= 1 MB) that + are able to take advantage of more than 32 tagged commands. + + There is no safe option and the default answer is recommended. + +Assume boards are SYMBIOS compatible +CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT + This option allows you to enable some features depending on GPIO + wiring. These General Purpose Input/Output pins can be used for + vendor specific features or implementation of the standard SYMBIOS + features. Genuine SYMBIOS controllers use GPIO0 in output for + controller LED and GPIO3 bit as a flag indicating + singled-ended/differential interface. The Tekram DC-390U/F boards + uses a different GPIO wiring. + + Your answer to this question is ignored if all your controllers have + NVRAM, since the driver is able to detect the board type from the + NVRAM format. + + If all the controllers in your system are genuine SYMBIOS boards or + use BIOS and drivers from SYMBIOS, you would want to say Y here, + otherwise N. N is the safe answer. + +Enable traffic profiling +CONFIG_SCSI_NCR53C8XX_PROFILE + This option allows you to enable profiling information gathering. + These statistics are not very accurate due to the low frequency + of the kernel clock (100 Hz on i386) and have performance impact + on systems that use very fast devices. + + The normal answer therefore is N. + +Include support for the NCR PQS/PDS SCSI card +CONFIG_SCSI_NCR53C8XX_PQS_PDS + Say Y here if you have a special SCSI adapter produced by NCR + corporation called a PCI Quad SCSI or PCI Dual SCSI. You do not need + this if you do not have one of these adapters. However, since this + device is detected as a specific PCI device, this option is quite + safe. + + The common answer here is N, but answering Y is safe. + +IBMMCA SCSI support +CONFIG_SCSI_IBMMCA + This is support for the IBM SCSI adapter found in many of the PS/2 + series computers. These machines have an MCA bus, so you need to + answer Y to "MCA support" as well and read + <file:Documentation/mca.txt>. + + If the adapter isn't found during boot (a common problem for models + 56, 57, 76, and 77) you'll need to use the 'ibmmcascsi=<pun>' kernel + option, where <pun> is the id of the SCSI subsystem (usually 7, but + if that doesn't work check your reference diskette). Owners of + model 95 with a LED-matrix-display can in addition activate some + activity info like under OS/2, but more informative, by setting + 'ibmmcascsi=display' as an additional kernel parameter. Try "man + bootparam" or see the documentation of your boot loader about how to + pass options to the kernel. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called ibmmca.o. + +Standard SCSI-order +CONFIG_IBMMCA_SCSI_ORDER_STANDARD + In the PC-world and in most modern SCSI-BIOS-setups, SCSI-hard disks + are assigned to the drive letters, starting with the lowest SCSI-id + (physical number -- pun) to be drive C:, as seen from DOS and + similar operating systems. When looking into papers describing the + ANSI-SCSI-standard, this assignment of drives appears to be wrong. + The SCSI-standard follows a hardware-hierarchy which says that id 7 + has the highest priority and id 0 the lowest. Therefore, the host + adapters are still today everywhere placed as SCSI-id 7 by default. + In the SCSI-standard, the drive letters express the priority of the + disk. C: should be the hard disk, or a partition on it, with the + highest priority. This must therefore be the disk with the highest + SCSI-id (e.g. 6) and not the one with the lowest! IBM-BIOS kept the + original definition of the SCSI-standard as also industrial- and + process-control-machines, like VME-CPUs running under realtime-OSes + (e.g. LynxOS, OS9) do. + + If you like to run Linux on your MCA-machine with the same + assignment of hard disks as seen from e.g. DOS or OS/2 on your + machine, which is in addition conformant to the SCSI-standard, you + must say Y here. This is also necessary for MCA-Linux users who want + to keep downward compatibility to older releases of the + IBM-MCA-SCSI-driver (older than driver-release 2.00 and older than + June 1997). + + If you like to have the lowest SCSI-id assigned as drive C:, as + modern SCSI-BIOSes do, which does not conform to the standard, but + is widespread and common in the PC-world of today, you must say N + here. If unsure, say Y. + +Reset SCSI-devices at boot time +CONFIG_IBMMCA_SCSI_DEV_RESET + By default, SCSI-devices are reset when the machine is powered on. + However, some devices exist, like special-control-devices, + SCSI-CNC-machines, SCSI-printer or scanners of older type, that do + not reset when switched on. If you say Y here, each device connected + to your SCSI-bus will be issued a reset-command after it has been + probed, while the kernel is booting. This may cause problems with + more modern devices, like hard disks, which do not appreciate these + reset commands, and can cause your system to hang. So say Y only if + you know that one of your older devices needs it; N is the safe + answer. + +NCR MCA 53C9x SCSI support +CONFIG_SCSI_MCA_53C9X + Some MicroChannel machines, notably the NCR 35xx line, use a SCSI + controller based on the NCR 53C94. This driver will allow use of + the controller on the 3550, and very possibly others. + + If you want to compile this as a module (= code which can be + inserted and removed from the running kernel whenever you want), say + M here and read <file:Documentation/modules.txt>. The module will + be called mca_53c9x.o. + +Always IN2000 SCSI support +CONFIG_SCSI_IN2000 + This is support for an ISA bus SCSI host adapter. You'll find more + information in <file:drivers/scsi/README.in2000>. If it doesn't work + out of the box, you may have to change the jumpers for IRQ or + address selection. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called in2000.o. + +Initio 91XXU(W) SCSI support +CONFIG_SCSI_INITIO + This is support for the Initio 91XXU(W) SCSI host adapter. Please + read the SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called initio.o. + +PAS16 SCSI support +CONFIG_SCSI_PAS16 + This is support for a SCSI host adapter. It is explained in section + 3.10 of the SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. If it doesn't work out + of the box, you may have to change some settings in + <file:drivers/scsi/pas16.h>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called pas16.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Initio INI-A100U2W SCSI support +CONFIG_SCSI_INIA100 + This is support for the Initio INI-A100U2W SCSI host adapter. + Please read the SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called a100u2w.o. + +PCI2000 support +CONFIG_SCSI_PCI2000 + This is support for the PCI2000I EIDE interface card which acts as a + SCSI host adapter. Please read the SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module called pci2000.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +PCI2220i support +CONFIG_SCSI_PCI2220I + This is support for the PCI2220i EIDE interface card which acts as a + SCSI host adapter. Please read the SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module called pci2220i.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +PSI240i support +CONFIG_SCSI_PSI240I + This is support for the PSI240i EIDE interface card which acts as a + SCSI host adapter. Please read the SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module called psi240i.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +Qlogic FAS SCSI support +CONFIG_SCSI_QLOGIC_FAS + This is a driver for the ISA, VLB, and PCMCIA versions of the Qlogic + FastSCSI! cards as well as any other card based on the FASXX chip + (including the Control Concepts SCSI/IDE/SIO/PIO/FDC cards). + + This driver does NOT support the PCI versions of these cards. The + PCI versions are supported by the Qlogic ISP driver ("Qlogic ISP + SCSI support"), below. + + Information about this driver is contained in + <file:drivers/scsi/README.qlogicfas>. You should also read the + SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called qlogicfas.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +Qlogic ISP SCSI support +CONFIG_SCSI_QLOGIC_ISP + This driver works for all QLogic PCI SCSI host adapters (IQ-PCI, + IQ-PCI-10, IQ_PCI-D) except for the PCI-basic card. (This latter + card is supported by the "AM53/79C974 PCI SCSI" driver.) + + If you say Y here, make sure to choose "BIOS" at the question "PCI + access mode". + + Please read the file <file:drivers/scsi/README.qlogicisp>. You + should also read the SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called qlogicisp.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +Qlogic ISP FC SCSI support +CONFIG_SCSI_QLOGIC_FC + This is a driver for the QLogic ISP2100 SCSI-FCP host adapter. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called qlogicfc.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +Include loadable firmware in driver +CONFIG_SCSI_QLOGIC_FC_FIRMWARE + Say Y to include ISP2100 Fabric Initiator/Target Firmware, with + expanded LUN addressing and FcTape (FCP-2) support, in the + Qlogic QLA 1280 driver. This is required on some platforms. + +Qlogic QLA 1280 SCSI support +CONFIG_SCSI_QLOGIC_1280 + Say Y if you have a QLogic ISP1x80/1x160 SCSI host adapter. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called qla1280.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +Seagate ST-02 and Future Domain TMC-8xx SCSI support +CONFIG_SCSI_SEAGATE + These are 8-bit SCSI controllers; the ST-01 is also supported by + this driver. It is explained in section 3.9 of the SCSI-HOWTO, + available from <http://www.tldp.org/docs.html#howto>. If it + doesn't work out of the box, you may have to change some settings in + <file:drivers/scsi/seagate.h>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called seagate.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Trantor T128/T128F/T228 SCSI support +CONFIG_SCSI_T128 + This is support for a SCSI host adapter. It is explained in section + 3.11 of the SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. If it doesn't work out + of the box, you may have to change some settings in + <file:drivers/scsi/t128.h>. Note that Trantor was purchased by + Adaptec, and some former Trantor products are being sold under the + Adaptec name. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called t128.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +UltraStor SCSI support +CONFIG_SCSI_ULTRASTOR + This is support for the UltraStor 14F, 24F and 34F SCSI-2 host + adapter family. This driver is explained in section 3.12 of the + SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. If it doesn't work out + of the box, you may have to change some settings in + <file:drivers/scsi/ultrastor.h>. + + Note that there is also another driver for the same hardware: + "UltraStor 14F/34F support", above. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called ultrastor.o. + +7000FASST SCSI support +CONFIG_SCSI_7000FASST + This driver supports the Western Digital 7000 SCSI host adapter + family. Some information is in the source: + <file:drivers/scsi/wd7000.c>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called wd7000.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +ACARD SCSI support +CONFIG_SCSI_ACARD + This driver supports the ACARD 870U/W SCSI host adapter. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called atp870u.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support +CONFIG_SCSI_EATA + This driver supports all EATA/DMA-compliant SCSI host adapters. DPT + ISA and all EISA I/O addresses are probed looking for the "EATA" + signature. If you chose "BIOS" at the question "PCI access mode", + the addresses of all the PCI SCSI controllers reported by the PCI + subsystem are probed as well. + + You want to read the start of <file:drivers/scsi/eata.c> and the + SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + Note that there is also another driver for the same hardware + available: "EATA-DMA [Obsolete] (DPT, NEC, AT&T, SNI, AST, Olivetti, + Alphatronix) support". You should say Y to only one of them. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called eata.o. + +enable tagged command queueing +CONFIG_SCSI_EATA_TAGGED_QUEUE + This is a feature of SCSI-2 which improves performance: the host + adapter can send several SCSI commands to a device's queue even if + previous commands haven't finished yet. Most EATA adapters negotiate + this feature automatically with the device, even if your answer is + N. The safe answer is N. + +enable elevator sorting +CONFIG_SCSI_EATA_LINKED_COMMANDS + This option enables elevator sorting for all probed SCSI disks and + CD-ROMs. It definitely reduces the average seek distance when doing + random seeks, but this does not necessarily result in a noticeable + performance improvement: your mileage may vary... + The safe answer is N. + +maximum number of queued commands +CONFIG_SCSI_EATA_MAX_TAGS + This specifies how many SCSI commands can be maximally queued for + each probed SCSI device. You should reduce the default value of 16 + only if you have disks with buggy or limited tagged command support. + Minimum is 2 and maximum is 62. This value is also the window size + used by the elevator sorting option above. The effective value used + by the driver for each probed SCSI device is reported at boot time. + +NCR53c406a SCSI support +CONFIG_SCSI_NCR53C406A + This is support for the NCR53c406a SCSI host adapter. For user + configurable parameters, check out <file:drivers/scsi/NCR53c406a.c> + in the kernel source. Also read the SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called NCR53c406.o. + +Symbios 53c416 SCSI support +CONFIG_SCSI_SYM53C416 + This is support for the sym53c416 SCSI host adapter, the SCSI + adapter that comes with some HP scanners. This driver requires that + the sym53c416 is configured first using some sort of PnP + configuration program (e.g. isapnp) or by a PnP aware BIOS. If you + are using isapnp then you need to compile this driver as a module + and then load it using insmod after isapnp has run. The parameters + of the configured card(s) should be passed to the driver. The format + is: + + insmod sym53c416 sym53c416=<base>,<irq> [sym53c416_1=<base>,<irq>] + + There is support for up to four adapters. If you want to compile + this driver as a module ( = code which can be inserted in and + removed from the running kernel whenever you want), say M here and + read <file:Documentation/modules.txt>. The module will be called + sym53c416.o. + +Simple 53c710 SCSI support (Compaq, NCR machines) +CONFIG_SCSI_SIM710 + This is a simple driver for NCR53c710 based SCSI host adapters. + + More complex drivers for this chip are available ("NCR53c7,8xx SCSI + support", above), but they require that the scsi chip be able to do + DMA block moves between memory and on-chip registers, which can + cause problems under certain conditions. This driver is designed to + avoid these problems and is intended to work with any Intel machines + using 53c710 chips, including various Compaq and NCR machines. + + Please read the comments at the top of the file + <file:drivers/scsi/sim710.c> for more information. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called sim710.o. + +Tekram DC390(T) and Am53/79C974 SCSI support +CONFIG_SCSI_DC390T + This driver supports PCI SCSI host adapters based on the Am53C974A + chip, e.g. Tekram DC390(T), DawiControl 2974 and some onboard + PCscsi/PCnet (Am53/79C974) solutions. + + Documentation can be found in <file:drivers/scsi/README.tmscsim>. + + Note that this driver does NOT support Tekram DC390W/U/F, which are + based on NCR/Symbios chips. Use "NCR53C8XX SCSI support" for those. + Also note that there is another generic Am53C974 driver, + "AM53/79C974 PCI SCSI support" below. You can pick either one. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called tmscsim.o. + +Omit support for other Am53/79C974 based SCSI adapters +CONFIG_SCSI_DC390T_NOGENSUPP + If you say N here, the DC390(T) SCSI driver relies on the DC390 + EEPROM to get initial values for its settings, such as speed, + termination, etc. If it can't find this EEPROM, it will use + defaults or the user supplied boot/module parameters. For details + on driver configuration see <file:drivers/scsi/README.tmscsim>. + + If you say Y here and if no EEPROM is found, the driver gives up and + thus only supports Tekram DC390(T) adapters. This can be useful if + you have a DC390(T) and another Am53C974 based adapter, which, for + some reason, you want to drive with the other AM53C974 driver. + + If unsure, say N. + +AM53/79C974 PCI SCSI support +CONFIG_SCSI_AM53C974 + This is support for the AM53/79C974 SCSI host adapters. Please read + <file:drivers/scsi/README.AM53C974> for details. Also, the + SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>, is for you. + + Note that there is another driver for AM53C974 based adapters: + "Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support", above. You + can pick either one. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called AM53C974.o. + +AMI MegaRAID support +CONFIG_SCSI_MEGARAID + This driver supports the AMI MegaRAID 418, 428, 438, 466, 762, 490 + and 467 SCSI host adapters. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called megaraid.o. + +Intel/ICP (former GDT SCSI Disk Array) RAID Controller support +CONFIG_SCSI_GDTH + Formerly called GDT SCSI Disk Array Controller Support. + + This is a driver for RAID/SCSI Disk Array Controllers (EISA/ISA/PCI) + manufactured by Intel/ICP vortex (an Intel Company). It is documented + in the kernel source in <file:drivers/scsi/gdth.c> and + <file:drivers/scsi/gdth.h.> + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called gdth.o. + +IOMEGA parallel port (ppa - older drives) +CONFIG_SCSI_PPA + This driver supports older versions of IOMEGA's parallel port ZIP + drive (a 100 MB removable media device). + + Note that you can say N here if you have the SCSI version of the ZIP + drive: it will be supported automatically if you said Y to the + generic "SCSI disk support", above. + + If you have the ZIP Plus drive or a more recent parallel port ZIP + drive (if the supplied cable with the drive is labeled "AutoDetect") + then you should say N here and Y to "IOMEGA parallel port (imm - + newer drives)", below. + + For more information about this driver and how to use it you should + read the file <file:drivers/scsi/README.ppa>. You should also read + the SCSI-HOWTO, which is available from + <http://www.tldp.org/docs.html#howto>. If you use this driver, + you will still be able to use the parallel port for other tasks, + such as a printer; it is safe to compile both drivers into the + kernel. + + This driver is also available as a module which can be inserted in + and removed from the running kernel whenever you want. To compile + this driver as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called ppa.o. + +IOMEGA parallel port (imm - newer drives) +CONFIG_SCSI_IMM + This driver supports newer versions of IOMEGA's parallel port ZIP + drive (a 100 MB removable media device). + + Note that you can say N here if you have the SCSI version of the ZIP + drive: it will be supported automatically if you said Y to the + generic "SCSI disk support", above. + + If you have the ZIP Plus drive or a more recent parallel port ZIP + drive (if the supplied cable with the drive is labeled "AutoDetect") + then you should say Y here; if you have an older ZIP drive, say N + here and Y to "IOMEGA Parallel Port (ppa - older drives)", above. + + For more information about this driver and how to use it you should + read the file <file:drivers/scsi/README.ppa>. You should also read + the SCSI-HOWTO, which is available from + <http://www.tldp.org/docs.html#howto>. If you use this driver, + you will still be able to use the parallel port for other tasks, + such as a printer; it is safe to compile both drivers into the + kernel. + + This driver is also available as a module which can be inserted in + and removed from the running kernel whenever you want. To compile + this driver as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called imm.o. + +Force the Iomega ZIP drivers to use EPP-16 +CONFIG_SCSI_IZIP_EPP16 + EPP (Enhanced Parallel Port) is a standard for parallel ports which + allows them to act as expansion buses that can handle up to 64 + peripheral devices. + + Some parallel port chipsets are slower than their motherboard, and + so we have to control the state of the chipset's FIFO queue every + now and then to avoid data loss. This will be done if you say Y + here. + + Generally, saying Y is the safe option and slows things down a bit. + +Assume slow parallel port control register +CONFIG_SCSI_IZIP_SLOW_CTR + Some parallel ports are known to have excessive delays between + changing the parallel port control register and good data being + available on the parallel port data/status register. This option + forces a small delay (1.0 usec to be exact) after changing the + control register to let things settle out. Enabling this option may + result in a big drop in performance but some very old parallel ports + (found in 386 vintage machines) will not work properly. + + Generally, saying N is fine. + +SCSI debugging host simulator +CONFIG_SCSI_DEBUG + This is a host adapter simulator that can be programmed to simulate + a large number of conditions that could occur on a real bus. The + advantage is that many hard to reproduce problems can be tested in a + controlled environment where there is reduced risk of losing + important data. This is primarily of use to people trying to debug + the middle and upper layers of the SCSI subsystem. If unsure, say N. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called scsi_debug.o. + +Fibre Channel and FC4 SCSI support +CONFIG_FC4 + Fibre Channel is a high speed serial protocol mainly used to + connect large storage devices to the computer; it is compatible with + and intended to replace SCSI. + + This is an experimental support for storage arrays connected to your + computer using optical fibre cables and the "X3.269-199X Fibre + Channel Protocol for SCSI" specification. If you want to use this, + you need to say Y here and to "SCSI support" as well as to the + drivers for the storage array itself and for the interface adapter + such as SOC or SOC+. This subsystem could even serve for IP + networking, with some code extensions. + + If unsure, say N. + +Sun SOC/Sbus +CONFIG_FC4_SOC + Serial Optical Channel is an interface card with one or two Fibre + Optic ports, each of which can be connected to a disk array. Note + that if you have older firmware in the card, you'll need the + microcode from the Solaris driver to make it work. + + This support is also available as a module called soc.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +Sun SOC+ (aka SOCAL) +CONFIG_FC4_SOCAL + Serial Optical Channel Plus is an interface card with up to two + Fibre Optic ports. This card supports FC Arbitrated Loop (usually + A5000 or internal FC disks in E[3-6]000 machines through the + Interface Board). You'll probably need the microcode from the + Solaris driver to make it work. + + This support is also available as a module called socal.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +SparcSTORAGE Array 100 and 200 series +CONFIG_SCSI_PLUTO + If you never bought a disk array made by Sun, go with N. + + This support is also available as a module called pluto.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +Sun Enterprise Network Array (A5000 and EX500) +CONFIG_SCSI_FCAL + This driver drives FC-AL disks connected through a Fibre Channel + card using the drivers/fc4 layer (currently only SOCAL). The most + common is either A5000 array or internal disks in E[3-6]000 + machines. + + This support is also available as a module called fcal.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. If unsure, say N. + +Acorn SCSI card (aka30) support +CONFIG_SCSI_ACORNSCSI_3 + This enables support for the Acorn SCSI card (aka30). If you have an + Acorn system with one of these, say Y. If unsure, say N. + +Support SCSI 2 Tagged queueing +CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE + Say Y here to enable tagged queuing support on the Acorn SCSI card. + + This is a feature of SCSI-2 which improves performance: the host + adapter can send several SCSI commands to a device's queue even if + previous commands haven't finished yet. Some SCSI devices don't + implement this properly, so the safe answer is N. + +Support SCSI 2 Synchronous Transfers +CONFIG_SCSI_ACORNSCSI_SYNC + Say Y here to enable synchronous transfer negotiation with all + targets on the Acorn SCSI card. + + In general, this improves performance; however some SCSI devices + don't implement it properly, so the safe answer is N. + +ARXE SCSI support +CONFIG_SCSI_ARXESCSI + Around 1991, Arxe Systems Limited released a high density floppy + disc interface for the Acorn Archimedes range, to allow the use of + HD discs from the then new A5000 on earlier models. This interface + was either sold on its own or with an integral SCSI controller. + Technical details on this NCR53c94-based device are available at + <http://www.cryton.demon.co.uk/acornbits/scsi_arxe.html> + Say Y here to compile in support for the SCSI controller. + +Oak SCSI support +CONFIG_SCSI_OAK1 + This enables support for the Oak SCSI card. If you have an Acorn + system with one of these, say Y. If unsure, say N. + +Cumana SCSI I support +CONFIG_SCSI_CUMANA_1 + This enables support for the Cumana SCSI I card. If you have an + Acorn system with one of these, say Y. If unsure, say N. + +Cumana SCSI II support +CONFIG_SCSI_CUMANA_2 + This enables support for the Cumana SCSI II card. If you have an + Acorn system with one of these, say Y. If unsure, say N. + +EcoSCSI support +CONFIG_SCSI_ECOSCSI + This enables support for the EcoSCSI card -- a small card that sits + in the Econet socket. If you have an Acorn system with one of these, + say Y. If unsure, say N. + +EESOX SCSI support +CONFIG_SCSI_EESOXSCSI + This enables support for the EESOX SCSI card. If you have an Acorn + system with one of these, say Y, otherwise say N. + +PowerTec SCSI support +CONFIG_SCSI_POWERTECSCSI + This enables support for the Powertec SCSI card on Acorn systems. If + you have one of these, say Y. If unsure, say N. + +IEEE 1394 (FireWire) support +CONFIG_IEEE1394 + IEEE 1394 describes a high performance serial bus, which is also + known as FireWire(tm) or i.Link(tm) and is used for connecting all + sorts of devices (most notably digital video cameras) to your + computer. + + If you have FireWire hardware and want to use it, say Y here. This + is the core support only, you will also need to select a driver for + your IEEE 1394 adapter. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called ieee1394.o. + +Texas Instruments PCILynx support +CONFIG_IEEE1394_PCILYNX + Say Y here if you have an IEEE-1394 controller with the Texas + Instruments PCILynx chip. Note: this driver is written for revision + 2 of this chip and may not work with revision 0. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called pcilynx.o. + +Use local RAM on PCILynx board +CONFIG_IEEE1394_PCILYNX_LOCALRAM + This option makes the PCILynx driver use local RAM available on some + PCILynx setups for Packet Control Lists. Local RAM is random access + memory which resides on the PCILynx board as opposed to on your + computer's motherboard. Local RAM may speed up command processing + because no PCI transfers are necessary during use of the Packet + Control Lists. + + Note that there are no known PCILynx systems providing local RAM + except for the evaluation boards by Texas Instruments and that the + PCILynx does not reliably report missing RAM. This means that it is + dangerous to say Y here if you are not absolutely sure that your + board provides 64KB of local RAM. + + If unsure, say N. + +Support for non-IEEE1394 local ports +CONFIG_IEEE1394_PCILYNX_PORTS + This option enables driver code to access the RAM, ROM and AUX ports + of the PCILynx through character devices in /dev. If you don't know + what this is about then you won't need it. + + If unsure, say N. + +#Adaptec AIC-5800 IEEE 1394 support +#CONFIG_IEEE1394_AIC5800 +# Say Y here if you have a IEEE 1394 controller using the Adaptec +# AIC-5800 chip. All Adaptec host adapters (89xx series) use this +# chip, as well as miro's DV boards. +# +# If you want to compile this as a module ( = code which can be +# inserted in and removed from the running kernel whenever you want), +# say M here and read <file:Documentation/modules.txt>. The module +# will be called aic5800.o. +# +OHCI-1394 (Open Host Controller Interface) support +CONFIG_IEEE1394_OHCI1394 + Enable this driver if you have an IEEE 1394 controller based on the + OHCI-1394 specification. The current driver is only tested with OHCI + chipsets made by Texas Instruments and NEC. Most third-party vendors + use one of these chipsets. It should work with any OHCI-1394 + compliant card, however. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called ohci1394.o. + +OHCI-1394 Video support +CONFIG_IEEE1394_VIDEO1394 + This option enables video device usage for OHCI-1394 cards. Enable + this option only if you have an IEEE 1394 video device connected to + an OHCI-1394 card. + +SBP-2 support (Harddisks etc.) +CONFIG_IEEE1394_SBP2 + This option enables you to use SBP-2 devices connected to your IEEE + 1394 bus. SBP-2 devices include harddrives and DVD devices. + +Raw IEEE 1394 I/O support +CONFIG_IEEE1394_RAWIO + Say Y here if you want support for the raw device. This is generally + a good idea, so you should say Y here. The raw device enables + direct communication of user programs with the IEEE 1394 bus and + thus with the attached peripherals. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called raw1394.o. + +Excessive debugging output +CONFIG_IEEE1394_VERBOSEDEBUG + If you say Y here, you will get very verbose debugging logs from the + subsystem which includes a dump of the header of every sent and + received packet. This can amount to a high amount of data collected + in a very short time which is usually also saved to disk by the + system logging daemons. + + Say Y if you really want or need the debugging output, everyone else + says N. + +Network device support +CONFIG_NETDEVICES + You can say N here if you don't intend to connect your Linux box to + any other computer at all or if all your connections will be over a + telephone line with a modem either via UUCP (UUCP is a protocol to + forward mail and news between unix hosts over telephone lines; read + the UUCP-HOWTO, available from + <http://www.tldp.org/docs.html#howto>) or dialing up a shell + account or a BBS, even using term (term is a program which gives you + almost full Internet connectivity if you have a regular dial up + shell account on some Internet connected Unix computer. Read + <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>). + + You'll have to say Y if your computer contains a network card that + you want to use under Linux (make sure you know its name because you + will be asked for it and read the Ethernet-HOWTO (especially if you + plan to use more than one network card under Linux)) or if you want + to use SLIP (Serial Line Internet Protocol is the protocol used to + send Internet traffic over telephone lines or null modem cables) or + CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better + and newer replacement for SLIP) or PLIP (Parallel Line Internet + Protocol is mainly used to create a mini network by connecting the + parallel ports of two local machines) or AX.25/KISS (protocol for + sending Internet traffic over amateur radio links). + + Make sure to read the NET-3-HOWTO. Eventually, you will have to read + Olaf Kirch's excellent and free book "Network Administrator's + Guide", to be found in <http://www.tldp.org/docs.html#guide>. If + unsure, say Y. + +Dummy net driver support +CONFIG_DUMMY + This is essentially a bit-bucket device (i.e. traffic you send to + this device is consigned into oblivion) with a configurable IP + address. It is most commonly used in order to make your currently + inactive SLIP address seem like a real address for local programs. + If you use SLIP or PPP, you might want to say Y here. Since this + thing often comes in handy, the default is Y. It won't enlarge your + kernel either. What a deal. Read about it in the Network + Administrator's Guide, available from + <http://www.tldp.org/docs.html#guide>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called dummy.o. If you want to use more than one dummy + device at a time, you need to compile this driver as a module. + Instead of 'dummy', the devices will then be called 'dummy0', + 'dummy1' etc. + +Bonding driver support +CONFIG_BONDING + Say 'Y' or 'M' if you wish to be able to 'bond' multiple Ethernet + Channels together. This is called 'Etherchannel' by Cisco, + 'Trunking' by Sun, and 'Bonding' in Linux. + + If you have two Ethernet connections to some other computer, you can + make them behave like one double speed connection using this driver. + Naturally, this has to be supported at the other end as well, either + with a similar Bonding Linux driver, a Cisco 5500 switch or a + SunTrunking SunSoft driver. + + This is similar to the EQL driver, but it merges Ethernet segments + instead of serial lines. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called bonding.o. + +Intermediate queueing device support +CONFIG_IMQ + The imq device(s) is used as placeholder for QoS queueing disciplines. + Every packet entering/leaving the ip stack can be directed through + the imq device where it's enqueued/dequeued to the attached qdisc. + This allows you to treat network devices as classes and distribute + bandwidth among them. Iptables is used to specify through which imq + device, if any, packets travel. + + If you want to compile this as a module ( = code which ca be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called imq.o + +SLIP (serial line) support +CONFIG_SLIP + Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to + connect to your Internet service provider or to connect to some + other local Unix box or if you want to configure your Linux box as a + Slip/CSlip server for other people to dial in. SLIP (Serial Line + Internet Protocol) is a protocol used to send Internet traffic over + serial connections such as telephone lines or null modem cables; + nowadays, the protocol PPP is more commonly used for this same + purpose. + + Normally, your access provider has to support SLIP in order for you + to be able to use it, but there is now a SLIP emulator called SLiRP + around (available from + <ftp://ibiblio.org/pub/Linux/system/network/serial/>) which + allows you to use SLIP over a regular dial up shell connection. If + you plan to use SLiRP, make sure to say Y to CSLIP, below. The + NET-3-HOWTO, available from + <http://www.tldp.org/docs.html#howto>, explains how to + configure SLIP. Note that you don't need this option if you just + want to run term (term is a program which gives you almost full + Internet connectivity if you have a regular dial up shell account on + some Internet connected Unix computer. Read + <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>). SLIP + support will enlarge your kernel by about 4 KB. If unsure, say N. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt> as well as + <file:Documentation/networking/net-modules.txt>. The module will be + called slip.o. + +CSLIP compressed headers +CONFIG_SLIP_COMPRESSED + This protocol is faster than SLIP because it uses compression on the + TCP/IP headers (not on the data itself), but it has to be supported + on both ends. Ask your access provider if you are not sure and + answer Y, just in case. You will still be able to use plain SLIP. If + you plan to use SLiRP, the SLIP emulator (available from + <ftp://ibiblio.org/pub/Linux/system/network/serial/>) which + allows you to use SLIP over a regular dial up shell connection, you + definitely want to say Y here. The NET-3-HOWTO, available from + <http://www.tldp.org/docs.html#howto>, explains how to configure + CSLIP. This won't enlarge your kernel. + +Keepalive and linefill +CONFIG_SLIP_SMART + Adds additional capabilities to the SLIP driver to support the + RELCOM line fill and keepalive monitoring. Ideal on poor quality + analogue lines. + +Six bit SLIP encapsulation +CONFIG_SLIP_MODE_SLIP6 + Just occasionally you may need to run IP over hostile serial + networks that don't pass all control characters or are only seven + bit. Saying Y here adds an extra mode you can use with SLIP: + "slip6". In this mode, SLIP will only send normal ASCII symbols over + the serial device. Naturally, this has to be supported at the other + end of the link as well. It's good enough, for example, to run IP + over the async ports of a Camtec JNT Pad. If unsure, say N. + +PPP (point-to-point protocol) support +CONFIG_PPP + PPP (Point to Point Protocol) is a newer and better SLIP. It serves + the same purpose: sending Internet traffic over telephone (and other + serial) lines. Ask your access provider if they support it, because + otherwise you can't use it; most Internet access providers these + days support PPP rather than SLIP. + + To use PPP, you need an additional program called pppd as described + in the PPP-HOWTO, available at + <http://www.tldp.org/docs.html#howto>. Make sure that you have + the version of pppd recommended in <file:Documentation/Changes>. + The PPP option enlarges your kernel by about 16 KB. + + There are actually two versions of PPP: the traditional PPP for + asynchronous lines, such as regular analog phone lines, and + synchronous PPP which can be used over digital ISDN lines for + example. If you want to use PPP over phone lines or other + asynchronous serial lines, you need to say Y (or M) here and also to + the next option, "PPP support for async serial ports". For PPP over + synchronous lines, you should say Y (or M) here and to "Support + synchronous PPP", below. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you said Y to "Version information on all symbols" above, then + you cannot compile the PPP driver into the kernel; you can then only + compile it as a module. The module will be called ppp_generic.o. + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt> as well as + <file:Documentation/networking/net-modules.txt>. + +PPP multilink support +CONFIG_PPP_MULTILINK + PPP multilink is a protocol (defined in RFC 1990) which allows you + to combine several (logical or physical) lines into one logical PPP + connection, so that you can utilize your full bandwidth. + + This has to be supported at the other end as well and you need a + version of the pppd daemon which understands the multilink protocol. + + If unsure, say N. + +PPP filtering +CONFIG_PPP_FILTER + Say Y here if you want to be able to filter the packets passing over + PPP interfaces. This allows you to control which packets count as + activity (i.e. which packets will reset the idle timer or bring up + a demand-dialled link) and which packets are to be dropped entirely. + You need to say Y here if you wish to use the pass-filter and + active-filter options to pppd. + + If unsure, say N. + +PPP support for async serial ports +CONFIG_PPP_ASYNC + Say Y (or M) here if you want to be able to use PPP over standard + asynchronous serial ports, such as COM1 or COM2 on a PC. If you use + a modem (not a synchronous or ISDN modem) to contact your ISP, you + need this option. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called ppp_async.o. + + If unsure, say Y. + +PPP support for sync tty ports +CONFIG_PPP_SYNC_TTY + Say Y (or M) here if you want to be able to use PPP over synchronous + (HDLC) tty devices, such as the SyncLink adapter. These devices + are often used for high-speed leased lines like T1/E1. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called ppp_synctty.o. + +PPP Deflate compression +CONFIG_PPP_DEFLATE + Support for the Deflate compression method for PPP, which uses the + Deflate algorithm (the same algorithm that gzip uses) to compress + each PPP packet before it is sent over the wire. The machine at the + other end of the PPP link (usually your ISP) has to support the + Deflate compression method as well for this to be useful. Even if + they don't support it, it is safe to say Y here. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called ppp_deflate.o. + +PPP BSD-Compress compression +CONFIG_PPP_BSDCOMP + Support for the BSD-Compress compression method for PPP, which uses + the LZW compression method to compress each PPP packet before it is + sent over the wire. The machine at the other end of the PPP link + (usually your ISP) has to support the BSD-Compress compression + method as well for this to be useful. Even if they don't support it, + it is safe to say Y here. + + The PPP Deflate compression method ("PPP Deflate compression", + above) is preferable to BSD-Compress, because it compresses better + and is patent-free. + + Note that the BSD compression code will always be compiled as a + module; it is called bsd_comp.o and will show up in the directory + modules once you have said "make modules". If unsure, say N. + +PPP over Ethernet +CONFIG_PPPOE + Support for PPP over Ethernet. + + This driver requires the current pppd from the "ppp" CVS repository + on cvs.samba.org. The required support will be present in the next + ppp release (2.4.2). + +Wireless LAN (non-hamradio) +CONFIG_NET_RADIO + Support for wireless LANs and everything having to do with radio, + but not with amateur radio or FM broadcasting. + + Saying Y here also enables the Wireless Extensions (creates + /proc/net/wireless and enables ifconfig access). The Wireless + Extension is a generic API allowing a driver to expose to the user + space configuration and statistics specific to common Wireless LANs. + The beauty of it is that a single set of tool can support all the + variations of Wireless LANs, regardless of their type (as long as + the driver supports Wireless Extension). Another advantage is that + these parameters may be changed on the fly without restarting the + driver (or Linux). If you wish to use Wireless Extensions with + wireless PCMCIA (PC-) cards, you need to say Y here; you can fetch + the tools from + <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. + + Some user-level drivers for scarab devices which don't require + special kernel support are available from + <ftp://shadow.cabi.net/pub/Linux/>. + +STRIP (Metricom Starmode radio IP) +CONFIG_STRIP + Say Y if you have a Metricom radio and intend to use Starmode Radio + IP. STRIP is a radio protocol developed for the MosquitoNet project + (on the WWW at <http://mosquitonet.stanford.edu/>) to send Internet + traffic using Metricom radios. Metricom radios are small, battery + powered, 100kbit/sec packet radio transceivers, about the size and + weight of a cellular telephone. (You may also have heard them called + "Metricom modems" but we avoid the term "modem" because it misleads + many people into thinking that you can plug a Metricom modem into a + phone line and use it as a modem.) + + You can use STRIP on any Linux machine with a serial port, although + it is obviously most useful for people with laptop computers. If you + think you might get a Metricom radio in the future, there is no harm + in saying Y to STRIP now, except that it makes the kernel a bit + bigger. + + You can also compile this as a module ( = code which can be inserted + in and removed from the running kernel whenever you want), say M + here and read <file:Documentation/modules.txt>. The module will be + called strip.o. + +AT&T WaveLAN & DEC RoamAbout DS support +CONFIG_WAVELAN + The Lucent WaveLAN (formerly NCR and AT&T; or DEC RoamAbout DS) is + a Radio LAN (wireless Ethernet-like Local Area Network) using the + radio frequencies 900 MHz and 2.4 GHz. + + This driver support the ISA version of the WaveLAN card. A separate + driver for the PCMCIA (PC-card) hardware is available in David + Hinds' pcmcia-cs package (see the file <file:Documentation/Changes> + for location). + + If you want to use an ISA WaveLAN card under Linux, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. Some more specific + information is contained in + <file:Documentation/networking/wavelan.txt> and in the source code + <file:drivers/net/wavelan.p.h>. + + You will also need the wireless tools package available from + <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. + Please read the man pages contained therein. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called wavelan.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +Aironet Arlan 655 & IC2200 DS support +CONFIG_ARLAN + Aironet makes Arlan, a class of wireless LAN adapters. These use the + www.Telxon.com chip, which is also used on several similar cards. + This driver is tested on the 655 and IC2200 series cards. Look at + <http://www.ylenurme.ee/~elmer/655/> for the latest information. + + The driver is built as two modules, arlan and arlan-proc. The latter + is the /proc interface and is not needed most of time. + + On some computers the card ends up in non-valid state after some + time. Use a ping-reset script to clear it. + +Aironet 4500/4800 series adapters +CONFIG_AIRONET4500 + www.aironet.com (recently bought by Cisco) makes these 802.11 DS + adapters. Driver by Elmer Joandi (elmer@ylenurme.ee). + + Say Y here if you have such an adapter, and then say Y below to + the option that applies to your particular type of card (PCI, ISA, + or PCMCIA). + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called aironet4500_core.o. If you want to + compile it as a module, say M here and read + <file:Documentation/modules.txt> as well as + <file:Documentation/networking/net-modules.txt>. + + quick config parameters: + SSID=tsunami - "The Password" + adhoc=1 there are no Access Points around + master=1 Adhoc master (the one who creates network + sync) + slave=1 Adhoc slave (btw, it is still forming own net + sometimes, and has problems with firmware... + change IbssJoinNetTimeout from /proc...) + channel=1..? meaningful in adhoc mode + + If you have problems with screwing up card, both_bap_lock=1 is a + conservative value (performance hit 15%). + + All other parameters can be set via the proc interface. + +Aironet 4500/4800 ISA/PCI/PNP/365 support +CONFIG_AIRONET4500_NONCS + If you have an ISA, PCI or PCMCIA Aironet 4500/4800 wireless LAN + card, say Y here, and then also to the options below that apply + to you. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called aironet4500_card.o. If you want to + compile it as a module, say M here and read + <file:Documentation/modules.txt>. + +Aironet 4500/4800 PNP support +CONFIG_AIRONET4500_PNP + If you have an ISA Aironet 4500/4800 card which you want to use in + PnP (Plug and Play) mode, say Y here. This is the recommended mode + for ISA cards. Remember however to enable the PnP jumper on the + board if you say Y here. + +Aironet 4500/4800 PCI support +CONFIG_AIRONET4500_PCI + If you have an PCI Aironet 4500/4800 card, say Y here. + +Aironet 4500/4800 ISA broken support +CONFIG_AIRONET4500_ISA + If you have an ISA Aironet 4500/4800 card which you want to run in + non-PnP mode, say Y here. This is not recommended and does not work + correctly at this point. Say N. + +Aironet 4500/4800 I365 broken support +CONFIG_AIRONET4500_I365 + If you have a PCMCIA Aironet 4500/4800 card which you want to use + without the standard PCMCIA cardservices provided by the pcmcia-cs + package, say Y here. This is not recommended, so say N. + +Aironet 4500/4800 PCMCIA support +CONFIG_AIRONET4500_CS + Say Y here if you have a PCMCIA Aironet 4500/4800 card which you + want to use with the standard PCMCIA cardservices provided by the + pcmcia-cs package. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called aironet4500_cs.o. If you want to + compile it as a module, say M here and read + <file:Documentation/modules.txt>. + +Aironet 4500/4800 PROC interface +CONFIG_AIRONET4500_PROC + If you say Y here (and to the "/proc file system" below), you will + be able to configure your Aironet card via the + /proc/sys/aironet4500 interface. + + Additional info: look in <file:drivers/net/aironet4500_rid.c>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called aironet4500_proc.o. If you want to + compile it as a module, say M here and read + <file:Documentation/modules.txt>. + + NOTE: the proc interface uses a lot of memory, so it is recommended + to compile it as a module and remove the module after + configuration. + +LAPB over Ethernet driver +CONFIG_LAPBETHER + This is a driver for a pseudo device (typically called /dev/lapb0) + which allows you to open an LAPB point-to-point connection to some + other computer on your Ethernet network. In order to do this, you + need to say Y or M to the driver for your Ethernet card as well as + to "LAPB Data Link Driver". + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called lapbether.o. If unsure, say N. + +X.25 async driver +CONFIG_X25_ASY + This is a driver for sending and receiving X.25 frames over regular + asynchronous serial lines such as telephone lines equipped with + ordinary modems. Experts should note that this driver doesn't + currently comply with the asynchronous HDLS framing protocols in + CCITT recommendation X.25. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called x25_asy.o. If unsure, say N. + +PCMCIA network device support +CONFIG_NET_PCMCIA + Say Y if you would like to include support for any PCMCIA or CardBus + network adapters, then say Y to the driver for your particular card + below. PCMCIA- or PC-cards are credit-card size devices often used + with laptops computers; CardBus is the newer and faster version of + PCMCIA. + + To use your PC-cards, you will need supporting software from David + Hinds' pcmcia-cs package (see the file <file:Documentation/Changes> + for location). You also want to check out the PCMCIA-HOWTO, + available from <http://www.tldp.org/docs.html#howto>. + + If unsure, say N. + +3Com 3c589 PCMCIA support +CONFIG_PCMCIA_3C589 + Say Y here if you intend to attach a 3Com 3c589 or compatible PCMCIA + (PC-card) Ethernet card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called 3c589_cs.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. If + unsure, say N. + +3Com 3c574 PCMCIA support +CONFIG_PCMCIA_3C574 + Say Y here if you intend to attach a 3Com 3c574 or compatible PCMCIA + (PC-card) Fast Ethernet card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called 3c574_cs.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. If + unsure, say N. + +Fujitsu FMV-J18x PCMCIA support +CONFIG_PCMCIA_FMVJ18X + Say Y here if you intend to attach a Fujitsu FMV-J18x or compatible + PCMCIA (PC-card) Ethernet card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called fmvj18x_cs.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + If unsure, say N. + +NE2000 compatible PCMCIA support +CONFIG_PCMCIA_PCNET + Say Y here if you intend to attach an NE2000 compatible PCMCIA + (PC-card) Ethernet or Fast Ethernet card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called pcnet_cs.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. If + unsure, say N. + +Asix AX88190 PCMCIA support +CONFIG_PCMCIA_AXNET + Say Y here if you intend to attach an Asix AX88190-based PCMCIA + (PC-card) Fast Ethernet card to your computer. These cards are + nearly NE2000 compatible but need a separate driver due to a few + misfeatures. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called axnet_cs.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. If + unsure, say N. + +New Media PCMCIA support +CONFIG_PCMCIA_NMCLAN + Say Y here if you intend to attach a New Media Ethernet or LiveWire + PCMCIA (PC-card) Ethernet card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called nmclan_cs.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. If + unsure, say N. + +SMC 91Cxx PCMCIA support +CONFIG_PCMCIA_SMC91C92 + Say Y here if you intend to attach an SMC 91Cxx compatible PCMCIA + (PC-card) Ethernet or Fast Ethernet card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called smc91c92_cs.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + If unsure, say N. + +Xircom 16-bit PCMCIA support +CONFIG_PCMCIA_XIRC2PS + Say Y here if you intend to attach a Xircom 16-bit PCMCIA (PC-card) + Ethernet or Fast Ethernet card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called xirc2ps_cs.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + If unsure, say N. + +COM20020 ARCnet PCMCIA support +CONFIG_ARCNET_COM20020_CS + Say Y here if you intend to attach this type of ARCnet PCMCIA card + to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called com20020_cs.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + If unsure, say N. + +IBM PCMCIA Token Ring adapter support +CONFIG_PCMCIA_IBMTR + Say Y here if you intend to attach this type of Token Ring PCMCIA + card to your computer. You then also need to say Y to "Token Ring + driver support". + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ibmtr_cs.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +Xircom Tulip-like CardBus support (old driver) +CONFIG_PCMCIA_XIRTULIP + This driver is for the Digital "Tulip" Ethernet CardBus adapters. + It should work with most DEC 21*4*-based chips/ethercards, as well + as with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and + ASIX. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called xircom_tulip_cb.o. If you want to compile + it as a module, say M here and read + <file:Documentation/modules.txt>. If unsure, say N. + +Xircom CardBus support (new driver) +CONFIG_PCMCIA_XIRCOM + This driver is for the Digital "Tulip" Ethernet CardBus adapters. + It should work with most DEC 21*4*-based chips/ethercards, as well + as with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and + ASIX. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called xircom_cb.o. If you want to compile + it as a module, say M here and read + <file:Documentation/modules.txt>. If unsure, say N. + +PCMCIA Wireless LAN +CONFIG_NET_PCMCIA_RADIO + Say Y here if you would like to use a PCMCIA (PC-card) device to + connect to a wireless local area network. Then say Y to the driver + for your particular card below. + + To use your PC-cards, you will need supporting software from David + Hinds' pcmcia-cs package (see the file <file:Documentation/Changes> + for location). You also want to check out the PCMCIA-HOWTO, + available from <http://www.tldp.org/docs.html#howto>. + +Hermes chipset 802.11b support (Orinoco/Prism2/Symbol cards) +CONFIG_HERMES + A driver for 802.11b wireless cards based based on the "Hermes" or + Intersil HFA384x (Prism 2) MAC controller. This includes the vast + majority of the PCMCIA 802.11b cards (which are nearly all rebadges) + - except for the Cisco/Aironet cards. Cards supported include the + Apple Airport (not a PCMCIA card), WavelanIEEE/Orinoco, + Cabletron/EnteraSys Roamabout, ELSA AirLancer, MELCO Buffalo, Avaya, + IBM High Rate Wireless, Farralon Syyline, Samsung MagicLAN, Netgear + MA401, LinkSys WPC-11, D-Link DWL-650, 3Com AirConnect, Intel + PRO/Wireless, and Symbol Spectrum24 High Rate amongst others. + + This option includes the guts of the driver, but in order to + actually use a card you will also need to enable support for PCMCIA + Hermes cards, PLX9052 based PCI adaptors or the Apple Airport below. + + You will also very likely also need the Wireless Tools in order to + configure your card and that /etc/pcmcia/wireless.opts works : + <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html> + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called hermes.o. + +Hermes 802.11b in PLX9052 based PCI adaptor support +CONFIG_PLX_HERMES + Enable support for PCMCIA cards supported by the "Hermes" (aka + orinoco_cs) driver when used in PLX9052 based PCI adaptors. These + adaptors are not a full PCMCIA controller but act as a more limited + PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that + 802.11b PCMCIA cards can be used in desktop machines. The Netgear + MA301 is such an adaptor. + + Support for these adaptors is so far still incomplete and buggy. + You have been warned. + +Prism 2.5 PCI 802.11b adaptor support +CONFIG_PCI_HERMES + Enable support for PCI and mini-PCI 802.11b wireless NICs based on + the Prism 2.5 chipset. These are true PCI cards, not the 802.11b + PCMCIA cards bundled with PCI<->PCMCIA adaptors which are also + common. Some of the built-in wireless adaptors in laptops are of + this variety. + +Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards) +CONFIG_PCMCIA_HERMES + A driver for "Hermes" chipset based PCMCIA wireless adaptors, such + as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ + EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and + others). It should also be usable on various Prism II based cards + such as the Linksys, D-Link and Farallon Skyline. It should also + work on Symbol cards such as the 3Com AirConnect and Ericsson WLAN. + + To use your PC-cards, you will need supporting software from David + Hinds' pcmcia-cs package (see the file <file:Documentation/Changes> + for location). You also want to check out the PCMCIA-HOWTO, + available from <http://www.tldp.org/docs.html#howto>. + + You will also very likely also need the Wireless Tools in order to + configure your card and that /etc/pcmcia/wireless.opts works: + <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called orinoco_cs.o. + +Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards +CONFIG_AIRO + This is the standard Linux driver to support Cisco/Aironet ISA and + PCI 802.11 wireless cards. + It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X + - with or without encryption) as well as card before the Cisco + acquisition (Aironet 4500, Aironet 4800, Aironet 4800B). + + This driver support both the standard Linux Wireless Extensions + and Cisco proprietary API, so both the Linux Wireless Tools and the + Cisco Linux utilities can be used to configure the card. + + The driver can be compiled as a module and will be named "airo.o". + +Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards +CONFIG_AIRO_CS + This is the standard Linux driver to support Cisco/Aironet PCMCIA + 802.11 wireless cards. This driver is the same as the Aironet + driver part of the Linux Pcmcia package. + It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X + - with or without encryption) as well as card before the Cisco + acquisition (Aironet 4500, Aironet 4800, Aironet 4800B). It also + supports OEM of Cisco such as the DELL TrueMobile 4800 and Xircom + 802.11b cards. + + This driver support both the standard Linux Wireless Extensions + and Cisco proprietary API, so both the Linux Wireless Tools and the + Cisco Linux utilities can be used to configure the card. + + To use your PC-cards, you will need supporting software from David + Hinds' pcmcia-cs package (see the file <file:Documentation/Changes> + for location). You also want to check out the PCMCIA-HOWTO, + available from <http://www.tldp.org/docs.html#howto>. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called airo_cs.o. + +Aviator/Raytheon 2.4MHz wireless support +CONFIG_PCMCIA_RAYCS + Say Y here if you intend to attach an Aviator/Raytheon PCMCIA + (PC-card) wireless Ethernet networking card to your computer. + Please read the file <file:Documentation/networking/ray_cs.txt> for + details. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ray_cs.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. If + unsure, say N. + +Apple Airport support (built-in) +CONFIG_APPLE_AIRPORT + Say Y here to support the Airport 802.11b wireless Ethernet hardware + built into the Macintosh iBook and other recent PowerPC-based + Macintosh machines. This is essentially a Lucent Orinoco card with + a non-standard interface + +Xircom Netwave AirSurfer wireless support +CONFIG_PCMCIA_NETWAVE + Say Y here if you intend to attach this type of PCMCIA (PC-card) + wireless Ethernet networking card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called netwave_cs.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + If unsure, say N. + +AT&T/Lucent Wavelan wireless support +CONFIG_PCMCIA_WAVELAN + Say Y here if you intend to attach an AT&T/Lucent Wavelan PCMCIA + (PC-card) wireless Ethernet networking card to your computer. This + driver is for the non-IEEE-802.11 Wavelan cards. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called wavelan_cs.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + If unsure, say N. + +PLIP (parallel port) support +CONFIG_PLIP + PLIP (Parallel Line Internet Protocol) is used to create a + reasonably fast mini network consisting of two (or, rarely, more) + local machines. A PLIP link from a Linux box is a popular means to + install a Linux distribution on a machine which doesn't have a + CD-ROM drive (a minimal system has to be transferred with floppies + first). The kernels on both machines need to have this PLIP option + enabled for this to work. + + The PLIP driver has two modes, mode 0 and mode 1. The parallel + ports (the connectors at the computers with 25 holes) are connected + with "null printer" or "Turbo Laplink" cables which can transmit 4 + bits at a time (mode 0) or with special PLIP cables, to be used on + bidirectional parallel ports only, which can transmit 8 bits at a + time (mode 1); you can find the wiring of these cables in + <file:Documentation/networking/PLIP.txt>. The cables can be up to + 15m long. Mode 0 works also if one of the machines runs DOS/Windows + and has some PLIP software installed, e.g. the Crynwr PLIP packet + driver (<http://oak.oakland.edu/simtel.net/msdos/pktdrvr-pre.html>) + and winsock or NCSA's telnet. + + If you want to use PLIP, say Y and read the PLIP mini-HOWTO as well + as the NET-3-HOWTO, both available from + <http://www.tldp.org/docs.html#howto>. Note that the PLIP + protocol has been changed and this PLIP driver won't work together + with the PLIP support in Linux versions 1.0.x. This option enlarges + your kernel by about 8 KB. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt> as well as + <file:Documentation/networking/net-modules.txt>. The module will be + called plip.o. If unsure, say Y or M, in case you buy a laptop + later. + +EQL (serial line load balancing) support +CONFIG_EQUALIZER + If you have two serial connections to some other computer (this + usually requires two modems and two telephone lines) and you use + SLIP (the protocol for sending Internet traffic over telephone + lines) or PPP (a better SLIP) on them, you can make them behave like + one double speed connection using this driver. Naturally, this has + to be supported at the other end as well, either with a similar EQL + Linux driver or with a Livingston Portmaster 2e. + + Say Y if you want this and read + <file:Documentation/networking/eql.txt>. You may also want to read + section 6.2 of the NET-3-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called eql.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. If + unsure, say N. + +Universal TUN/TAP device driver support +CONFIG_TUN + TUN/TAP provides packet reception and transmission for user space + programs. It can be viewed as a simple Point-to-Point or Ethernet + device, which instead of receiving packets from a physical media, + receives them from user space program and instead of sending packets + via physical media writes them to the user space program. + + When a program opens /dev/net/tun, driver creates and registers + corresponding net device tunX or tapX. After a program closed above + devices, driver will automatically delete tunXX or tapXX device and + all routes corresponding to it. + + Please read <file:Documentation/networking/tuntap.txt> for more + information. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called tun.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + + If you don't know what to use this for, you don't need it. + +Ethertap network tap (OBSOLETE) +CONFIG_ETHERTAP + If you say Y here (and have said Y to "Kernel/User network link + driver", above) and create a character special file /dev/tap0 with + major number 36 and minor number 16 using mknod ("man mknod"), you + will be able to have a user space program read and write raw + Ethernet frames from/to that special file. tap0 can be configured + with ifconfig and route like any other Ethernet device but it is not + connected to any physical LAN; everything written by the user to + /dev/tap0 is treated by the kernel as if it had come in from a LAN + to the device tap0; everything the kernel wants to send out over the + device tap0 can instead be read by the user from /dev/tap0: the user + mode program replaces the LAN that would be attached to an ordinary + Ethernet device. Please read the file + <file:Documentation/networking/ethertap.txt> for more information. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ethertap.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + + If you don't know what to use this for, you don't need it. + +Sealevel Systems 4021 support +CONFIG_SEALEVEL_4021 + This is a driver for the Sealevel Systems ACB 56 serial I/O adapter. + + This driver can only be compiled as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to do that, say M here. The module will be called + sealevel.o. + +TMPTX3912/PR31700 serial port support +CONFIG_SERIAL_TX3912 + The TX3912 is a Toshiba RISC processor based o the MIPS 3900 core; + see <http://www.toshiba.com/taec/components/Generic/risc/tx3912.htm>. + Say Y here to enable kernel support for the on-board serial port. + +Console on TMPTX3912/PR31700 serial port +CONFIG_SERIAL_TX3912_CONSOLE + The TX3912 is a Toshiba RISC processor based o the MIPS 3900 core; + see <http://www.toshiba.com/taec/components/Generic/risc/tx3912.htm>. + Say Y here to direct console I/O to the on-board serial port. + +Enable Au1000 serial console +CONFIG_AU1000_SERIAL_CONSOLE + If you have an Alchemy AU1000 processor (MIPS based) and you want + to use a console on a serial port, say Y. Otherwise, say N. + +Enable Au1000 UART Support +CONFIG_AU1000_UART + If you have an Alchemy AU1000 processor (MIPS based) and you want + to use serial ports, say Y. Otherwise, say N. + +SyncLink HDLC/SYNCPPP support +CONFIG_SYNCLINK_SYNCPPP + Enables HDLC/SYNCPPP support for the SyncLink WAN driver. + Normally the SyncLink WAN driver works with the main PPP + driver (ppp.c) and pppd program. HDLC/SYNCPPP support allows use + of the Cisco HDLC/PPP driver (syncppp.c). + The SyncLink WAN driver (in character devices) must also be enabled. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called syncppp.o. + +FarSync T-Series X.21 (and V.35/V.24) cards +CONFIG_FARSYNC + This driver supports the FarSync T-Series X.21 (and V.35/V.24) cards + from FarSite Communications Ltd. + Synchronous communication is supported on all ports at speeds up to + 8Mb/s (128K on V.24) using synchronous PPP or Cisco HDLC. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want) + say M here and read <file:Documentation/modules.txt>. + The module will be called farsync.o and if you want the module to be + automatically loaded when the interface is referenced then you + should add "alias syncX farsync" to /etc/modules.conf for each + interface, where X is 0, 1, 2, ... + +Frame Relay (DLCI) support +CONFIG_DLCI + This is support for the frame relay protocol; frame relay is a fast + low-cost way to connect to a remote Internet access provider or to + form a private wide area network. The one physical line from your + box to the local "switch" (i.e. the entry point to the frame relay + network, usually at the phone company) can carry several logical + point-to-point connections to other computers connected to the frame + relay network. For a general explanation of the protocol, check out + <http://www.frforum.com/> on the WWW. To use frame relay, you need + supporting hardware (called FRAD) and certain programs from the + net-tools package as explained in + <file:Documentation/networking/framerelay.txt>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called dlci.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Max open DLCI +CONFIG_DLCI_COUNT + This is the maximal number of logical point-to-point frame relay + connections (the identifiers of which are called DCLIs) that + the driver can handle. The default is probably fine. + +Max DLCI per device +CONFIG_DLCI_MAX + You can specify here how many logical point-to-point frame relay + connections (the identifiers of which are called DCLIs) should be + handled by each of your hardware frame relay access devices. Go with + the default. + +SDLA (Sangoma S502/S508) support +CONFIG_SDLA + Say Y here if you need a driver for the Sangoma S502A, S502E, and + S508 Frame Relay Access Devices. These are multi-protocol cards, but + only frame relay is supported by the driver at this time. Please + read <file:Documentation/framerelay.txt>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called sdla.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Acorn Econet/AUN protocols +CONFIG_ECONET + Econet is a fairly old and slow networking protocol mainly used by + Acorn computers to access file and print servers. It uses native + Econet network cards. AUN is an implementation of the higher level + parts of Econet that runs over ordinary Ethernet connections, on + top of the UDP packet protocol, which in turn runs on top of the + Internet protocol IP. + + If you say Y here, you can choose with the next two options whether + to send Econet/AUN traffic over a UDP Ethernet connection or over + a native Econet network card. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called econet.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +AUN over UDP +CONFIG_ECONET_AUNUDP + Say Y here if you want to send Econet/AUN traffic over a UDP + connection (UDP is a packet based protocol that runs on top of the + Internet protocol IP) using an ordinary Ethernet network card. + +Native Econet +CONFIG_ECONET_NATIVE + Say Y here if you have a native Econet network card installed in + your computer. + +WAN router +CONFIG_WAN_ROUTER + Wide Area Networks (WANs), such as X.25, frame relay and leased + lines, are used to interconnect Local Area Networks (LANs) over vast + distances with data transfer rates significantly higher than those + achievable with commonly used asynchronous modem connections. + Usually, a quite expensive external device called a `WAN router' is + needed to connect to a WAN. + + As an alternative, WAN routing can be built into the Linux kernel. + With relatively inexpensive WAN interface cards available on the + market, a perfectly usable router can be built for less than half + the price of an external router. If you have one of those cards and + wish to use your Linux box as a WAN router, say Y here and also to + the WAN driver for your card, below. You will then need the + wan-tools package which is available from <ftp://ftp.sangoma.com/>. + Read <file:Documentation/networking/wan-router.txt> for more + information. + + The WAN routing support is also available as a module called + wanrouter.o ( = code which can be inserted in and removed from the + running kernel whenever you want). If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + + If unsure, say N. + +Fast switching (read help!) +CONFIG_NET_FASTROUTE + Saying Y here enables direct NIC-to-NIC (NIC = Network Interface + Card) data transfers on the local network, which is fast. + + IMPORTANT NOTE: This option is NOT COMPATIBLE with "Network packet + filtering" (CONFIG_NETFILTER). Say N here if you say Y there. + + However, it will work with all options in the "Advanced router" + section (except for "Use TOS value as routing key" and + "Use FWMARK value as routing key"). + + At the moment, few devices support fast switching (tulip is one of + them, a modified 8390 driver can be found at + <ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz>). + + If unsure, say N. + +Forwarding between high speed interfaces +CONFIG_NET_HW_FLOWCONTROL + This option enables NIC (Network Interface Card) hardware throttling + during periods of extremal congestion. At the moment only a couple + of device drivers support it (really only one -- tulip, a modified + 8390 driver can be found at + <ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz>). + + Really, this option is applicable to any machine attached to a fast + enough network, and even a 10 Mb NIC is able to kill a not very slow + box, such as a 120MHz Pentium. + + However, do not say Y here if you did not experience any serious + problems. + +QoS and/or fair queueing +CONFIG_NET_SCHED + When the kernel has several packets to send out over a network + device, it has to decide which ones to send first, which ones to + delay, and which ones to drop. This is the job of the packet + scheduler, and several different algorithms for how to do this + "fairly" have been proposed. + + If you say N here, you will get the standard packet scheduler, which + is a FIFO (first come, first served). If you say Y here, you will be + able to choose from among several alternative algorithms which can + then be attached to different network devices. This is useful for + example if some of your network devices are real time devices that + need a certain minimum data flow rate, or if you need to limit the + maximum data flow rate for traffic which matches specified criteria. + This code is considered to be experimental. + + To administer these schedulers, you'll need the user-level utilities + from the package iproute2+tc at <ftp://ftp.inr.ac.ru/ip-routing/>. + That package also contains some documentation; for more, check out + <http://snafu.freedom.org/linux2.2/iproute-notes.html>. + + This Quality of Service (QoS) support will enable you to use + Differentiated Services (diffserv) and Resource Reservation Protocol + (RSVP) on your Linux router if you also say Y to "QoS support", + "Packet classifier API" and to some classifiers below. Documentation + and software is at <http://icawww1.epfl.ch/linux-diffserv/>. + + If you say Y here and to "/proc file system" below, you will be able + to read status information about packet schedulers from the file + /proc/net/psched. + + The available schedulers are listed in the following questions; you + can say Y to as many as you like. If unsure, say N now. + +CBQ packet scheduler +CONFIG_NET_SCH_CBQ + Say Y here if you want to use the Class-Based Queueing (CBQ) packet + scheduling algorithm for some of your network devices. This + algorithm classifies the waiting packets into a tree-like hierarchy + of classes; the leaves of this tree are in turn scheduled by + separate algorithms (called "disciplines" in this context). + + See the top of <file:net/sched/sch_cbq.c> for references about the + CBQ algorithm. + + CBQ is a commonly used scheduler, so if you're unsure, you should + say Y here. Then say Y to all the queueing algorithms below that you + want to use as CBQ disciplines. Then say Y to "Packet classifier + API" and say Y to all the classifiers you want to use; a classifier + is a routine that allows you to sort your outgoing traffic into + classes based on a certain criterion. + + This code is also available as a module called sch_cbq.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +CONFIG_NET_SCH_HTB + Say Y here if you want to use the Hierarchical Token Buckets (HTB) + packet scheduling algorithm for some of your network devices. See + URL <http://luxik.cdi.cz/~devik/qos/htb/> for complete manual and + in-depth articles. + + HTB is very similar to the CBQ regarding its goals however is has + different properties and different algorithm. + + This code is also available as a module called sch_htb.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +CSZ packet scheduler +CONFIG_NET_SCH_CSZ + Say Y here if you want to use the Clark-Shenker-Zhang (CSZ) packet + scheduling algorithm for some of your network devices. At the + moment, this is the only algorithm that can guarantee service for + real-time applications (see the top of <file:net/sched/sch_csz.c> + for details and references about the algorithm). + + Note: this scheduler is currently broken. + + This code is also available as a module called sch_csz.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +ATM pseudo-scheduler +CONFIG_NET_SCH_ATM + Say Y here if you want to use the ATM pseudo-scheduler. This + provides a framework for invoking classifiers (aka "filters"), which + in turn select classes of this queuing discipline. Each class maps + the flow(s) it is handling to a given virtual circuit (see the top of + <file:net/sched/sch_atm.c>). + + This code is also available as a module called sch_atm.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +The simplest PRIO pseudo-scheduler +CONFIG_NET_SCH_PRIO + Say Y here if you want to use an n-band priority queue packet + "scheduler" for some of your network devices or as a leaf discipline + for the CBQ scheduling algorithm. If unsure, say Y. + + This code is also available as a module called sch_prio.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +Diffserv field marker +CONFIG_NET_SCH_DSMARK + Say Y if you want to schedule packets according to the + Differentiated Services architecture proposed in RFC 2475. + Technical information on this method, with pointers to associated + RFCs, is available at <http://www.gta.ufrj.br/diffserv/>. + + This code is also available as a module called sch_dsmark.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +GRED queue +CONFIG_NET_SCH_GRED + Say Y here if you want to use the Generic Random Early Detection + (RED) packet scheduling algorithm for some of your network devices + (see the top of <file:net/sched/sch_red.c> for details and + references about the algorithm). + + This code is also available as a module called sch_gred.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +RED queue +CONFIG_NET_SCH_RED + Say Y here if you want to use the Random Early Detection (RED) + packet scheduling algorithm for some of your network devices (see + the top of <file:net/sched/sch_red.c> for details and references + about the algorithm). + + This code is also available as a module called sch_red.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +SFQ queue +CONFIG_NET_SCH_SFQ + Say Y here if you want to use the Stochastic Fairness Queueing (SFQ) + packet scheduling algorithm for some of your network devices or as a + leaf discipline for the CBQ scheduling algorithm (see the top of + <file:net/sched/sch_sfq.c> for details and references about the SFQ + algorithm). + + This code is also available as a module called sch_sfq.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +ESFQ queue +CONFIG_NET_SCH_ESFQ + Say Y here if you want to use the Stochastic Fairness Queueing (SFQ) + packet scheduling algorithm for some of your network devices or as a + leaf discipline for the CBQ scheduling algorithm (see the top of + <file:net/sched/sch_esfq.c> for details and references about the SFQ + algorithm). + + This is an enchanced SFQ version which allows you to control the + hardcoded values in the SFQ scheduler: queue depth, hash table size, + queues limit. Also adds control to the hash function used to identify + packet flows. Hash by src or dst ip and original sfq hash. + + This code is also available as a module called sch_esfq.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +TEQL queue +CONFIG_NET_SCH_TEQL + Say Y here if you want to use the True Link Equalizer (TLE) packet + scheduling algorithm for some of your network devices or as a leaf + discipline for the CBQ scheduling algorithm. This queueing + discipline allows the combination of several physical devices into + one virtual device. (see the top of <file:net/sched/sch_teql.c> for + details). + + This code is also available as a module called sch_teql.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +TBF queue +CONFIG_NET_SCH_TBF + Say Y here if you want to use the Simple Token Bucket Filter (TBF) + packet scheduling algorithm for some of your network devices or as a + leaf discipline for the CBQ scheduling algorithm (see the top of + <file:net/sched/sch_tbf.c> for a description of the TBF algorithm). + + This code is also available as a module called sch_tbf.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +Ingress Qdisc +CONFIG_NET_SCH_INGRESS + If you say Y here, you will be able to police incoming bandwidth + and drop packets when this bandwidth exceeds your desired rate. + If unsure, say Y. + + This code is also available as a module called cls_ingress.o + ( = code which can be inserted in and removed from the running + kernel whenever you want). If you want to compile it as a module, + say M here and read <file:Documentation/modules.txt>. + +QoS support +CONFIG_NET_QOS + Say Y here if you want to include Quality Of Service scheduling + features, which means that you will be able to request certain + rate-of-flow limits for your network devices. + + This Quality of Service (QoS) support will enable you to use + Differentiated Services (diffserv) and Resource Reservation Protocol + (RSVP) on your Linux router if you also say Y to "Packet classifier + API" and to some classifiers below. Documentation and software is at + <http://icawww1.epfl.ch/linux-diffserv/>. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about QoS support. + +Rate estimator +CONFIG_NET_ESTIMATOR + In order for Quality of Service scheduling to work, the current + rate-of-flow for a network device has to be estimated; if you say Y + here, the kernel will do just that. + +Packet classifier API +CONFIG_NET_CLS + The CBQ scheduling algorithm requires that network packets which are + scheduled to be sent out over a network device be classified + according to some criterion. If you say Y here, you will get a + choice of several different packet classifiers with the following + questions. + + This will enable you to use Differentiated Services (diffserv) and + Resource Reservation Protocol (RSVP) on your Linux router. + Documentation and software is at + <http://icawww1.epfl.ch/linux-diffserv/>. + +Traffic policing (needed for in/egress) +CONFIG_NET_CLS_POLICE + Say Y to support traffic policing (bandwidth limits). Needed for + ingress and egress rate limiting. + +TC index classifier +CONFIG_NET_CLS_TCINDEX + If you say Y here, you will be able to classify outgoing packets + according to the tc_index field of the skb. You will want this + feature if you want to implement Differentiated Services using + sch_dsmark. If unsure, say Y. + + This code is also available as a module called cls_tcindex.o + ( = code which can be inserted in and removed from the running + kernel whenever you want). If you want to compile it as a module, + say M here and read <file:Documentation/modules.txt>. + +Routing tables based classifier +CONFIG_NET_CLS_ROUTE4 + If you say Y here, you will be able to classify outgoing packets + according to the route table entry they matched. If unsure, say Y. + + This code is also available as a module called cls_route.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +Firewall based classifier +CONFIG_NET_CLS_FW + If you say Y here, you will be able to classify outgoing packets + according to firewall criteria you specified. + + This code is also available as a module called cls_fw.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +U32 classifier +CONFIG_NET_CLS_U32 + If you say Y here, you will be able to classify outgoing packets + according to their destination address. If unsure, say Y. + + This code is also available as a module called cls_u32.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +Special RSVP classifier +CONFIG_NET_CLS_RSVP + The Resource Reservation Protocol (RSVP) permits end systems to + request a minimum and maximum data flow rate for a connection; this + is important for real time data such as streaming sound or video. + + Say Y here if you want to be able to classify outgoing packets based + on their RSVP requests. + + This code is also available as a module called cls_rsvp.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +Special RSVP classifier for IPv6 +CONFIG_NET_CLS_RSVP6 + The Resource Reservation Protocol (RSVP) permits end systems to + request a minimum and maximum data flow rate for a connection; this + is important for real time data such as streaming sound or video. + + Say Y here if you want to be able to classify outgoing packets based + on their RSVP requests and you are using the new Internet Protocol + IPv6 as opposed to the older and more common IPv4. + + This code is also available as a module called cls_rsvp6.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +Network code profiler +CONFIG_NET_PROFILE + If you say Y here and to "/proc file system support" below, some + obscure and undocumented information about the network code's + performance will be written to /proc/net/profile. If you don't know + what it is about, you don't need it: say N. + +Network packet generator +CONFIG_NET_PKTGEN + This module will inject preconfigured packets, at a configurable + rate, out of a given interface. It is used for network interface + stress testing and performance analysis. If you don't understand + what was just said, you don't need it: say N. + + Documentation on how to use the packet generator can be found + at <file:Documentation/networking/pktgen.txt>. + + This code is also available as a module called pktgen.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +Wan interfaces support +CONFIG_WAN + Wide Area Networks (WANs), such as X.25, frame relay and leased + lines, are used to interconnect Local Area Networks (LANs) over vast + distances with data transfer rates significantly higher than those + achievable with commonly used asynchronous modem connections. + Usually, a quite expensive external device called a `WAN router' is + needed to connect to a WAN. + + As an alternative, a relatively inexpensive WAN interface card can + allow your Linux box to directly connect to a WAN. If you have one + of those cards and wish to use it under Linux, say Y here and also + to the WAN driver for your card, below. + + If unsure, say N. + +Comtrol Hostess SV-11 support +CONFIG_HOSTESS_SV11 + This is a network card for low speed synchronous serial links, at + up to 256Kbps. It supports both PPP and Cisco HDLC. + + At this point, the driver can only be compiled as a module. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called hostess_sv11.o. + +COSA/SRP sync serial board support +CONFIG_COSA + This is a driver for COSA and SRP synchronous serial boards. These + boards allow to connect synchronous serial devices (for example + base-band modems, or any other device with the X.21, V.24, V.35 or + V.36 interface) to your Linux box. The cards can work as the + character device, synchronous PPP network device, or the Cisco HDLC + network device. + + To actually use the COSA or SRP board, you will need user-space + utilities for downloading the firmware to the cards and to set them + up. Look at the <http://www.fi.muni.cz/~kas/cosa/> for more + information about the cards (including the pointer to the user-space + utilities). You can also read the comment at the top of the + <file:drivers/net/wan/cosa.c> for details about the cards and the driver + itself. + + The driver will be compiled as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cosa.o. For general information about + modules read <file:Documentation/modules.txt>. + +Etinc PCISYNC serial board support +CONFIG_DSCC4 + This is a driver for Etinc PCISYNC boards based on the Infineon + (ex. Siemens) DSCC4 chipset. It is supposed to work with the four + ports card. Take a look at <http://www.cogenit.fr/dscc4/> + for further informations about the driver and his configuration. + + The driver will be compiled as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called dscc4.o. For general information about + modules read <file:Documentation/modules.txt>. + +LanMedia Corp. serial boards (SSI/V.35, T1/E1, HSSI, T3) +CONFIG_LANMEDIA + This is a driver for the following Lan Media family of serial + boards. + + LMC 1000 board allows you to connect synchronous serial devices (for + example base-band modems, or any other device with the X.21, V.24, + V.35 or V.36 interface) to your Linux box. + + LMC 1200 with on board DSU board allows you to connect your Linux + box directly to a T1 or E1 circuit. + + LMC 5200 board provides a HSSI interface capable of running up to + 52 mbits per second. + + LMC 5245 board connects directly to a T3 circuit saving the + additional external hardware. + + To change setting such as syncPPP vs cisco HDLC or clock source you + will need lmcctl. It is available at <ftp://ftp.lanmedia.com/>. + + This code is also available as a module called lmc.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +Fibre Channel driver support +CONFIG_NET_FC + Fibre Channel is a high speed serial protocol mainly used to connect + large storage devices to the computer; it is compatible with and + intended to replace SCSI. + + If you intend to use Fibre Channel, you need to have a Fibre channel + adaptor card in your computer; say Y here and to the driver for your + adaptor below. You also should have said Y to "SCSI support" and + "SCSI generic support". + +Interphase 5526 Tachyon chipset based adaptor support +CONFIG_IPHASE5526 + Say Y here if you have a Fibre Channel adaptor of this kind. + + The driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called iph5526.o. For general information about + modules read <file:Documentation/modules.txt>. + +Red Creek Hardware VPN +CONFIG_RCPCI + This is a driver for hardware which provides a Virtual Private + Network (VPN). Say Y if you have it. + + This code is also available as a module called rcpci.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +Granch SBNI12 Leased Line adapter driver +CONFIG_SBNI + This is a driver for ISA SBNI12-xx cards which are low cost + alternatives to leased line modems. Say Y if you want to insert + the driver into the kernel or say M to compile it as a module (the + module will be called sbni.o). + + You can find more information and last versions of drivers and + utilities at <http://www.granch.ru/>. If you have any question you + can send email to sbni@granch.ru. + + Say N if unsure. + +SBNI multiple-line feature support +CONFIG_SBNI_MULTILINE + Schedule traffic for some parallel lines, via SBNI12 adapters. + If you have two computers connected with two parallel lines it's + possible to increase transfer rate nearly twice. You should have + a program named 'sbniconfig' to configure adapters. + + Say N if unsure. + +WAN router drivers +CONFIG_WAN_ROUTER_DRIVERS + If you have a WAN interface card and you want your Linux box to act + as a WAN router, thereby connecting you Local Area Network to the + outside world over the WAN connection, say Y here and then to the + driver for your card below. In addition, you need to say Y to "Wan + Router". + + You will need the wan-tools package which is available from + <ftp://ftp.sangoma.com/>. Read + <file:Documentation/networking/wan-router.txt> for more information. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about WAN router drivers. If unsure, say N. + +Sangoma WANPIPE(tm) multiprotocol cards +CONFIG_VENDOR_SANGOMA + WANPIPE from Sangoma Technologies Inc. (<http://www.sangoma.com/>) + is a family of intelligent multiprotocol WAN adapters with data + transfer rates up to 4Mbps. They are also known as Synchronous + Data Link Adapters (SDLA) and are designated as S514-PCI or + S508-ISA. These cards support + + - X.25, Frame Relay, PPP, Cisco HDLC protocols. + + - API support for protocols like HDLC (LAPB), + HDLC Streaming, X.25, Frame Relay and BiSync. + + - Ethernet Bridging over Frame Relay protocol. + + - MULTILINK PPP + + - Async PPP (Modem Dialup) + + If you have one or more of these cards, say M to this option; you + may then also want to read the file + <file:Documentation/networking/wanpipe.txt>. The next questions + will ask you about the protocols you want the driver to support. + + The driver will be compiled as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called wanpipe.o. For general information about + modules read <file:Documentation/modules.txt>. + +WANPIPE X.25 support +CONFIG_WANPIPE_X25 + Say Y to this option if you are planning to connect a WANPIPE card + to an X.25 network. Note, this feature also includes the X.25 API + support used to develop custom applications over the X.25 protocol. + If you say N, the X.25 support will not be included in the driver. + The X.25 option is supported on S514-PCI and S508-ISA cards. + +WANPIPE Frame Relay support +CONFIG_WANPIPE_FR + Say Y to this option if you are planning to connect a WANPIPE card + to a frame relay network, or use frame relay API to develop + custom applications over the Frame Relay protocol. + This feature also contains the Ethernet Bridging over Frame Relay, + where a WANPIPE frame relay link can be directly connected to the + Linux kernel bridge. If you say N, the frame relay support will + not be included in the driver. The Frame Relay option is + supported on S514-PCI and S508-ISA cards. + +WANPIPE PPP support +CONFIG_WANPIPE_PPP + Say Y to this option if you are planning to connect a WANPIPE card + to a leased line using Point-to-Point protocol (PPP). If you say N, + the PPP support will not be included in the driver. The PPP option + is supported on S514-PCI/S508-ISA cards. + +WANPIPE Multi-Port PPP support +CONFIG_WANPIPE_MULTPPP + Say Y to this option if you are planning to connect a WANPIPE card + to a leased line using Point-to-Point protocol (PPP). Note, the + MultiPort PPP uses the Linux Kernel SyncPPP protocol over the + Sangoma HDLC Streaming adapter. In this case each Sangoma adapter + port can support an independent PPP connection. For example, a + single Quad-Port PCI adapter can support up to four independent + PPP links. If you say N,the PPP support will not be included in the + driver. The PPP option is supported on S514-PCI/S508-ISA cards. + +WANPIPE Cisco HDLC support +CONFIG_WANPIPE_CHDLC + Say Y to this option if you are planning to connect a WANPIPE card + to a leased line using the Cisco HDLC protocol. This now supports + Dual Port Cisco HDLC on the S514-PCI/S508-ISA cards. + This support also allows user to build applications using the + HDLC streaming API. + + CHDLC Streaming driver also supports MULTILINK PPP + support that can bind multiple WANPIPE T1 cards into + a single logical channel. + + If you say N, the Cisco HDLC support and + HDLC streaming API and MULTILINK PPP will not be + included in the driver. + +MultiGate (COMX) synchronous serial board support +CONFIG_COMX + Say Y if you want to use any board from the MultiGate (COMX) family. + These boards are synchronous serial adapters for the PC, + manufactured by ITConsult-Pro Co, Hungary. + + Read <file:Documentation/networking/comx.txt> for help on + configuring and using COMX interfaces. Further info on these cards + can be found at <http://www.itc.hu/> or <info@itc.hu>. + + You must say Y to "/proc file system support" (CONFIG_PROC_FS) to + use this driver. + + If you want to compile this as a module, say M and read + <file:Documentation/modules.txt>. The module will be called comx.o. + +Support for COMX/CMX/HiCOMX boards +CONFIG_COMX_HW_COMX + Hardware driver for the 'CMX', 'COMX' and 'HiCOMX' boards from the + MultiGate family. Say Y if you have one of these. + + You will need additional firmware to use these cards, which are + downloadable from <ftp://ftp.itc.hu/>. + + If you want to compile this as a module, say M and read + <file:Documentation/modules.txt>. The module will be called + comx-hw-comx.o. + +Support for LoCOMX board +CONFIG_COMX_HW_LOCOMX + Hardware driver for the 'LoCOMX' board from the MultiGate family. + Say Y if you have a board like this. + + If you want to compile this as a module, say M and read + <file:Documentation/modules.txt>. The module will be called + comx-hw-locomx.o. + +Support for MixCOM board +CONFIG_COMX_HW_MIXCOM + Hardware driver for the 'MixCOM' board from the MultiGate family. + Say Y if you have a board like this. + + If you want to use the watchdog device on this card, you should + select it in the Watchdog Cards section of the Character Devices + configuration. The ISDN interface of this card is Teles 16.3 + compatible, you should enable it in the ISDN configuration menu. The + driver for the flash ROM of this card is available separately on + <ftp://ftp.itc.hu/>. + + If you want to compile this as a module, say M and read + <file:Documentation/modules.txt>. The module will be called + comx-hw-mixcom.o. + +i810 TCO timer/watchdog support +CONFIG_I810_TCO + Hardware driver for the TCO timer built into the Intel i810 and i815 + chipset family. The TCO (Total Cost of Ownership) timer is a + watchdog timer that will reboot the machine after its second + expiration. The expiration time can be configured by command + argument "i810_margin=<n>" where <n> is the counter initial value. + It is decremented every 0.6 secs, the default is 50 which gives a + timeout of 30 seconds and one minute until reset. + + On some motherboards the driver may fail to reset the chipset's + NO_REBOOT flag which prevents the watchdog from rebooting the + machine. If this is the case you will get a kernel message like + "i810tco init: failed to reset NO_REBOOT flag". + + If you want to compile this as a module, say M and read + <file:Documentation/modules.txt>. The module will be called + i810-tco.o. + +SliceCOM/PciCOM board support +CONFIG_COMX_HW_MUNICH + Hardware driver for the 'SliceCOM' (channelized E1) and 'PciCOM' + boards (X21) from the MultiGate family. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called comx-hw-munich.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + + Read linux/Documentation/networking/slicecom.txt for help on + configuring and using SliceCOM interfaces. Further info on these cards + can be found at <http://www.itc.hu> or <info@itc.hu>. + +Support for HDLC and syncPPP protocols on MultiGate boards +CONFIG_COMX_PROTO_PPP + Cisco-HDLC and synchronous PPP protocol driver for all MultiGate + boards. Say Y if you want to use either protocol on your MultiGate + boards. + + If you want to compile this as a module, say M and read + <file:Documentation/modules.txt>. The module will be called + comx-proto-ppp.o. + +Support for LAPB protocol on MultiGate boards +CONFIG_COMX_PROTO_LAPB + LAPB protocol driver for all MultiGate boards. Say Y if you + want to use this protocol on your MultiGate boards. + + If you want to compile this as a module, say M and read + <file:Documentation/modules.txt>. The module will be called + comx-proto-lapb.o. + +Support for Frame Relay on MultiGate boards +CONFIG_COMX_PROTO_FR + Frame Relay protocol driver for all MultiGate boards. Say Y if you + want to use this protocol on your MultiGate boards. + + If you want to compile this as a module, say M and read + <file:Documentation/modules.txt>. The module will be called + comx-proto-fr.o. + +Cyclom 2X(tm) multiprotocol cards +CONFIG_CYCLADES_SYNC + Cyclom 2X from Cyclades Corporation (<http://www.cyclades.com/> and + <http://www.cyclades.com.br/>) is an intelligent multiprotocol WAN + adapter with data transfer rates up to 512 Kbps. These cards support + the X.25 and SNA related protocols. If you have one or more of these + cards, say Y to this option. The next questions will ask you about + the protocols you want the driver to support (for now only X.25 is + supported). + + While no documentation is available at this time please grab the + wanconfig tarball in + <http://www.conectiva.com.br/~acme/cycsyn-devel/> (with minor changes + to make it compile with the current wanrouter include files; efforts + are being made to use the original package available at + <ftp://ftp.sangoma.com/>). + + Feel free to contact me or the cycsyn-devel mailing list at + acme@conectiva.com.br and cycsyn-devel@bazar.conectiva.com.br for + additional details, I hope to have documentation available as soon + as possible. (Cyclades Brazil is writing the Documentation). + + The driver will be compiled as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cyclomx.o. For general information about + modules read <file:Documentation/modules.txt>. + +Cyclom 2X X.25 support +CONFIG_CYCLOMX_X25 + Say Y to this option if you are planning to connect a Cyclom 2X card + to an X.25 network. + + If you say N, the X.25 support will not be included in the driver + (saves about 11 KB of kernel memory). + +Generic HDLC driver +CONFIG_HDLC + Say Y to this option if your Linux box contains a WAN card supported + by this driver and you are planning to connect the box to a WAN + ( = Wide Area Network). You will need supporting software from + <http://hq.pm.waw.pl/hdlc/>. + Generic HDLC driver currently supports raw HDLC, Cisco HDLC, Frame + Relay, synchronous Point-to-Point Protocol (PPP) and X.25. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called hdlc.o. + + If unsure, say N here. + +Raw HDLC support +CONFIG_HDLC_RAW + Say Y to this option if you want generic HDLC driver to support + raw HDLC over WAN (Wide Area Network) connections. + + If unsure, say N here. + +Cisco HDLC support +CONFIG_HDLC_CISCO + Say Y to this option if you want generic HDLC driver to support + Cisco HDLC over WAN (Wide Area Network) connections. + + If unsure, say N here. + +Frame-Relay HDLC support +CONFIG_HDLC_FR + Say Y to this option if you want generic HDLC driver to support + Frame-Relay protocol over WAN (Wide Area Network) connections. + + If unsure, say N here. + +Frame-Relay bridging support +CONFIG_HDLC_FR_BRIDGE + Say Y to this option if you want generic HDLC driver to support + bridging LAN frames over Frame-Relay links. + + If unsure, say N here. + +Synchronous Point-to-Point Protocol (PPP) support +CONFIG_HDLC_PPP + Say Y to this option if you want generic HDLC driver to support + PPP over WAN (Wide Area Network) connections. + + If unsure, say N here. + +CCITT X.25 over HDLC support +CONFIG_HDLC_X25 + Say Y to this option if you want generic HDLC driver to support + X.25 protocol over WAN (Wide Area Network) connections. + + If unsure, say N here. + +SDL RISCom/N2 support +CONFIG_N2 + This driver is for RISCom/N2 single or dual channel ISA cards + made by SDL Communications Inc. If you have such a card, + say Y here and see <http://hq.pm.waw.pl/pub/hdlc/>. + + Note that N2csu and N2dds cards are not supported by this driver. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called n2.o. + + If unsure, say N here. + +Moxa C101 support +CONFIG_C101 + This driver is for C101 SuperSync ISA cards made by Moxa + Technologies Co., Ltd. If you have such a card, + say Y here and see <http://hq.pm.waw.pl/pub/hdlc/> + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called c101.o. + + If unsure, say N here. + +Ethernet (10 or 100Mbit) +CONFIG_NET_ETHERNET + Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common + type of Local Area Network (LAN) in universities and companies. + + Common varieties of Ethernet are: 10BASE-2 or Thinnet (10 Mbps over + coaxial cable, linking computers in a chain), 10BASE-T or twisted + pair (10 Mbps over twisted pair cable, linking computers to central + hubs), 10BASE-F (10 Mbps over optical fiber links, using hubs), + 100BASE-TX (100 Mbps over two twisted pair cables, using hubs), + 100BASE-T4 (100 Mbps over 4 standard voice-grade twisted pair + cables, using hubs), 100BASE-FX (100 Mbps over optical fiber links) + [the 100BASE varieties are also known as Fast Ethernet], and Gigabit + Ethernet (1 Gbps over optical fiber or short copper links). + + If your Linux machine will be connected to an Ethernet and you have + an Ethernet network interface card (NIC) installed in your computer, + say Y here and read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. You will then also have + to say Y to the driver for your particular NIC. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about Ethernet network cards. If unsure, say N. + +Western Digital/SMC cards +CONFIG_NET_VENDOR_SMC + If you have a network (Ethernet) card belonging to this class, say Y + and read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about Western Digital cards. If you say Y, you will be + asked for your specific card in the following questions. + +WD80*3 support +CONFIG_WD80x3 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called wd.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +SMC Ultra MCA support +CONFIG_ULTRAMCA + If you have a network (Ethernet) card of this type and are running + an MCA based system (PS/2), say Y and read the Ethernet-HOWTO, + available from <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called smc-mca.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +SMC Ultra support +CONFIG_ULTRA + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + Important: There have been many reports that, with some motherboards + mixing an SMC Ultra and an Adaptec AHA154x SCSI card (or compatible, + such as some BusLogic models) causes corruption problems with many + operating systems. The Linux smc-ultra driver has a work-around for + this but keep it in mind if you have such a SCSI card and have + problems. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called smc-ultra.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt> as + well as <file:Documentation/networking/net-modules.txt>. + +SMC Ultra32 EISA support +CONFIG_ULTRA32 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called smc-ultra32.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt> as + well as <file:Documentation/networking/net-modules.txt>. + +SMC 9194 support +CONFIG_SMC9194 + This is support for the SMC9xxx based Ethernet cards. Choose this + option if you have a DELL laptop with the docking station, or + another SMC9192/9194 based chipset. Say Y if you want it compiled + into the kernel, and read the file + <file:Documentation/networking/smc9.txt> and the Ethernet-HOWTO, + available from <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called smc9194.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +PCI NE2000 and clones support +CONFIG_NE2K_PCI + This driver is for NE2000 compatible PCI cards. It will not work + with ISA NE2000 cards (they have their own driver, "NE2000/NE1000 + support" below). If you have a PCI NE2000 network (Ethernet) card, + say Y and read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver also works for the following NE2000 clone cards: + RealTek RTL-8029 Winbond 89C940 Compex RL2000 KTI ET32P2 + NetVin NV5000SC Via 86C926 SureCom NE34 Winbond + Holtek HT80232 Holtek HT80229 + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ne2k-pci.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt> as + well as <file:Documentation/networking/net-modules.txt>. + +Racal-Interlan (Micom) NI cards +CONFIG_NET_VENDOR_RACAL + If you have a network (Ethernet) card belonging to this class, such + as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO, + available from <http://www.tldp.org/docs.html#howto>. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about NI cards. If you say Y, you will be asked for + your specific card in the following questions. + +NI5010 support +CONFIG_NI5010 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. Note that this is still + experimental code. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ni5010.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +NI5210 support +CONFIG_NI52 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ni52.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +NI6510 support +CONFIG_NI65 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ni65.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +RealTek RTL-8139C+ 10/100 PCI Fast Ethernet Adapter support +CONFIG_8139CP + This is a driver for the Fast Ethernet PCI network cards based on + the RTL8139C+ chips. If you have one of those, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. This is recommended. + The module will be called 8139cp.o. + +RealTek RTL-8139 PCI Fast Ethernet Adapter support +CONFIG_8139TOO + This is a driver for the Fast Ethernet PCI network cards based on + the RTL8139 chips. If you have one of those, say Y and read + <file:Documentation/networking/8139too.txt> as well as the + Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. This is + recommended. The module will be called 8139too.o. + +Use PIO instead of MMIO +CONFIG_8139TOO_PIO + This instructs the driver to use programmed I/O ports (PIO) instead + of PCI shared memory (MMIO). This can possibly solve some problems + in case your mainboard has memory consistency issues. If unsure, + say N. + +Support for uncommon RTL-8139 rev. K (automatic channel equalization) +CONFIG_8139TOO_TUNE_TWISTER + This implements a function which might come in handy in case you + are using low quality on long cabling. It is required for RealTek + RTL-8139 revision K boards, and totally unused otherwise. It tries + to match the transceiver to the cable characteristics. This is + experimental since hardly documented by the manufacturer. + If unsure, say Y. + +Support for older RTL-8129/8130 boards +CONFIG_8139TOO_8129 + This enables support for the older and uncommon RTL-8129 and + RTL-8130 chips, which support MII via an external transceiver, + instead of an internal one. Disabling this option will save some + memory by making the code size smaller. If unsure, say Y. + +Use older RX-reset method +CONFIG_8139_OLD_RX_RESET + The 8139too driver was recently updated to contain a more rapid + reset sequence, in the face of severe receive errors. This "new" + RX-reset method should be adequate for all boards. But if you + experience problems, you can enable this option to restore the + old RX-reset behavior. If unsure, say N. + +SiS 900/7016 PCI Fast Ethernet Adapter support +CONFIG_SIS900 + This is a driver for the Fast Ethernet PCI network cards based on + the SiS 900 and SiS 7016 chips. The SiS 900 core is also embedded in + SiS 630 and SiS 540 chipsets. If you have one of those, say Y and + read the Ethernet-HOWTO, available at + <http://www.tldp.org/docs.html#howto>. Please read + <file:Documentation/networking/sis900.txt> and comments at the + beginning of <file:drivers/net/sis900.c> for more information. + + This driver also supports AMD 79C901 HomePNA so that you can use + your phone line as a network cable. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. This is + recommended. The module will be called sis900.o. + +Packet Engines Yellowfin Gigabit-NIC / Symbios 53c885 support +CONFIG_YELLOWFIN + Say Y here if you have a Packet Engines G-NIC PCI Gigabit Ethernet + adapter or the SYM53C885 Ethernet controller. The Gigabit adapter is + used by the Beowulf Linux cluster project. See + <http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html> for more + information about this driver in particular and Beowulf in general. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. This is + recommended. The module will be called yellowfin.o. + +General Instruments Surfboard 1000 +CONFIG_NET_SB1000 + This is a driver for the General Instrument (also known as + NextLevel) SURFboard 1000 internal + cable modem. This is an ISA card which is used by a number of cable + TV companies to provide cable modem access. It's a one-way + downstream-only cable modem, meaning that your upstream net link is + provided by your regular phone modem. + + At present this driver only compiles as a module, so say M here if + you have this card. The module will be called sb1000.o. Then read + <file:Documentation/networking/README.sb1000> for information on how + to use this module, as it needs special ppp scripts for establishing + a connection. Further documentation and the necessary scripts can be + found at: + + <http://www.jacksonville.net/~fventuri/> + <http://home.adelphia.net/~siglercm/sb1000.html> + <http://linuxpower.cx/~cable/> + + If you don't have this card, of course say N. + +Adaptec Starfire support +CONFIG_ADAPTEC_STARFIRE + Say Y here if you have an Adaptec Starfire (or DuraLAN) PCI network + adapter. The DuraLAN chip is used on the 64 bit PCI boards from + Adaptec e.g. the ANA-6922A. The older 32 bit boards use the tulip + driver. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. This is + recommended. The module will be called starfire.o. + +Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support +CONFIG_ACENIC + Say Y here if you have an Alteon AceNIC, 3Com 3C985(B), NetGear + GA620, SGI Gigabit or Farallon PN9000-SX PCI Gigabit Ethernet + adapter. The driver allows for using the Jumbo Frame option (9000 + bytes/frame) however it requires that your switches can handle this + as well. To enable Jumbo Frames, add `mtu 9000' to your ifconfig + line. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. This is + recommended. The module will be called acenic.o. + +Omit support for old Tigon I based AceNICs +CONFIG_ACENIC_OMIT_TIGON_I + Say Y here if you only have Tigon II based AceNICs and want to leave + out support for the older Tigon I based cards which are no longer + being sold (ie. the original Alteon AceNIC and 3Com 3C985 (non B + version)). This will reduce the size of the driver object by + app. 100KB. If you are not sure whether your card is a Tigon I or a + Tigon II, say N here. + + The safe and default value for this is N. + +SysKonnect SK-98xx support +CONFIG_SK98LIN + Say Y here if you have a SysKonnect SK-98xx Gigabit Ethernet Server + Adapter. The following adapters are supported by this driver: + - SK-9841 (single link 1000Base-LX) + - SK-9842 (dual link 1000Base-LX) + - SK-9843 (single link 1000Base-SX) + - SK-9844 (dual link 1000Base-SX) + - SK-9821 (single link 1000Base-T) + - SK-9822 (dual link 1000Base-T) + - SK-9861 (single link Volition connector) + - SK-9862 (dual link Volition connector) + The driver also supports the following adapters from Allied Telesyn: + - AT2970... + + The dual link adapters support a link-failover feature. Read + <file:Documentation/networking/sk98lin.txt> for information about + optional driver parameters. + Questions concerning this driver may be addressed to: + linux@syskonnect.de + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. This is + recommended. The module will be called sk98lin.o. + +Sun GEM support +CONFIG_SUNGEM + Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0. See also + <http://www.sun.com/products-n-solutions/hardware/docs/pdf/806-3985-10.pdf>. + + This chip is also used by Apple under the name GMAC in all their recent + machines starting with the first iBook. This includes all AGP capable + Apple machines except some early G4s and iMacs that still used a + Tulip chip. This driver obsoletes the GMAC driver for these machines. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called sungem.o. + +Broadcom Tigon3 support +CONFIG_TIGON3 + This driver supports Broadcom Tigon3 based gigabit Ethernet cards. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. This is + recommended. The module will be called tg3.o. + +MyriCOM Gigabit Ethernet support +CONFIG_MYRI_SBUS + This driver supports MyriCOM Sbus gigabit Ethernet cards. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. This is + recommended. The module will be called myri_sbus.o. + +D-Link 2000-based Gigabit Ethernet support +CONFIG_DL2K + This driver supports D-Link 2000-based gigabit ethernet cards, which + includes + D-Link DGE-550T Gigabit Ethernet Adapter. + D-Link DL2000-based Gigabit Ethernet Adapter. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. This is + recommended. The module will be called dl2k.o. + +EtherExpress Pro/100 support (e100, Alternate Intel driver) +CONFIG_E100 + This driver supports Intel(R) PRO/100 family of adapters, which + includes: + + Controller Adapter Name Board IDs + ---------- ------------ --------- + + 82558 PRO/100+ PCI Adapter 668081-xxx, + 689661-xxx + 82558 PRO/100+ Management Adapter 691334-xxx, + 701738-xxx, + 721383-xxx + 82558 PRO/100+ Dual Port Server Adapter 714303-xxx, + 711269-xxx, + A28276-xxx + 82558 PRO/100+ PCI Server Adapter 710550-xxx + 82550 PRO/100 S Server Adapter 752438-xxx + 82559 A56831-xxx, + A10563-xxx, + A12171-xxx, + A12321-xxx, + A12320-xxx, + A12170-xxx + 748568-xxx + 748565-xxx + 82550 PRO/100 S Desktop Adapter 751767-xxx + 82559 748592-xxx, + A12167-xxx, + A12318-xxx, + A12317-xxx, + A12165-xxx, + 748569-xxx + 82559 PRO/100+ Server Adapter 729757-xxx + 82559 PRO/100 S Management Adapter 748566-xxx, + 748564-xxx + 82550 PRO/100 S Dual Port Server Adapter A56831-xxx + 82551 PRO/100 M Desktop Adapter A80897-xxx + PRO/100 S Advanced Management Adapter + 747842-xxx, + 745171-xxx + CNR PRO/100 VE Desktop Adapter A10386-xxx, + A10725-xxx, + A23801-xxx, + A19716-xxx + PRO/100 VM Desktop Adapter A14323-xxx, + A19725-xxx, + A23801-xxx, + A22220-xxx, + A23796-xxx + + + To verify that your adapter is supported, find the board ID number + on the adapter. Look for a label that has a barcode and a number + in the format 123456-001 (six digits hyphen three digits). Match + this to the list of numbers above. + + For more information on how to identify your adapter, go to the + Adapter & Driver ID Guide at: + + http://support.intel.com/support/network/adapter/pro100/21397.htm + + For the latest Intel PRO/100 network driver for Linux, see: + + http://appsr.intel.com/scripts-df/support_intel.asp + + More specific information on configuring the driver is in + <file:Documentation/networking/e100.txt>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called e100.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +Intel(R) PRO/1000 Gigabit Ethernet support +CONFIG_E1000 + This driver supports Intel(R) PRO/1000 gigabit ethernet family of + adapters, which includes: + + Controller Adapter Name Board IDs + ---------- ------------ --------- + 82542 PRO/1000 Gigabit Server Adapter 700262-xxx, + 717037-xxx + 82543 PRO/1000 F Server Adapter 738640-xxx, + A38888-xxx + 82543 PRO/1000 T Server Adapter A19845-xxx, + A33948-xxx + 82544 PRO/1000 XT Server Adapter A51580-xxx + 82544 PRO/1000 XF Server Adapter A50484-xxx + 82544 PRO/1000 T Desktop Adapter A62947-xxx + 82540 PRO/1000 MT Desktop Adapter A78408-xxx + 82545 PRO/1000 MT Server Adapter A92165-xxx + 82546 PRO/1000 MT Dual Port Server Adapter A92111-xxx + 82545 PRO/1000 MF Server Adapter A91622-xxx + 82545 PRO/1000 MF Server Adapter(LX) A91624-xxx + 82546 PRO/1000 MF Dual Port Server Adapter A91620-xxx + + For more information on how to identify your adapter, go to the + Adapter & Driver ID Guide at: + + <http://support.intel.com/support/network/adapter/pro100/21397.htm> + + For general information and support, go to the Intel support + website at: + + <http://support.intel.com> + + More specific information on configuring the driver is in + <file:Documentation/networking/e1000.txt>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called e1000.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +AMD LANCE and PCnet (AT1500 and NE2100) support +CONFIG_LANCE + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. Some LinkSys cards are + of this type. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. This is + recommended. The module will be called lance.o. + +SGI IOC3 Ethernet +CONFIG_SGI_IOC3_ETH + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + +National Semiconductor DP83902AV support +CONFIG_STNIC + Support for cards based on the National Semiconductor DP83902AV + ST-NIC Serial Network Interface Controller for Twisted Pair. This + is a 10Mbit/sec Ethernet controller. Product overview and specs at + <http://www.national.com/pf/DP/DP83902A.html>. + + If unsure, say N. + +3COM cards +CONFIG_NET_VENDOR_3COM + If you have a network (Ethernet) card belonging to this class, say Y + and read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about 3COM cards. If you say Y, you will be asked for + your specific card in the following questions. + +3c501 "EtherLink" support +CONFIG_EL1 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. Also, consider buying a + new card, since the 3c501 is slow, broken, and obsolete: you will + have problems. Some people suggest to ping ("man ping") a nearby + machine every minute ("man cron") when using this card. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called 3c501.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +3c503 "EtherLink II" support +CONFIG_EL2 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called 3c503.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +3c505 "EtherLink Plus" support +CONFIG_ELPLUS + Information about this network (Ethernet) card can be found in + <file:Documentation/networking/3c505.txt>. If you have a card of + this type, say Y and read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt> as well as + <file:Documentation/networking/net-modules.txt>. The module will be + called 3c505.o. + +3c507 (EtherLink 16) support +CONFIG_EL16 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called 3c507.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +3c523 "EtherlinkMC" support +CONFIG_ELMC + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called 3c523.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +3c527 "EtherLink/MC 32" support +CONFIG_ELMC_II + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called 3c527.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +3c509/3c529 (MCA)/3c579 "EtherLink III" support +CONFIG_EL3 + If you have a network (Ethernet) card belonging to the 3Com + EtherLinkIII series, say Y and read the Ethernet-HOWTO, available + from <http://www.tldp.org/docs.html#howto>. + + If your card is not working you may need to use the DOS + setup disk to disable Plug & Play mode, and to select the default + media type. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt> as well as + <file:Documentation/networking/net-modules.txt>. The module will be + called 3c509.o. + +3c515 ISA Fast EtherLink +CONFIG_3C515 + If you have a 3Com ISA EtherLink XL "Corkscrew" 3c515 Fast Ethernet + network card, say Y and read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt> as well as + <file:Documentation/networking/net-modules.txt>. The module will be + called 3c515.o. + +3c590/3c900 series (592/595/597) "Vortex/Boomerang/Cyclone" support +CONFIG_VORTEX + This option enables driver support for a large number of 10mbps and + 10/100mbps EISA, PCI and PCMCIA 3Com network cards: + + "Vortex" (Fast EtherLink 3c590/3c592/3c595/3c597) EISA and PCI + "Boomerang" (EtherLink XL 3c900 or 3c905) PCI + "Cyclone" (3c540/3c900/3c905/3c980/3c575/3c656) PCI and Cardbus + "Tornado" (3c905) PCI + "Hurricane" (3c555/3cSOHO) PCI + + If you have such a card, say Y and read the Ethernet-HOWTO, + available from <http://www.tldp.org/docs.html#howto>. More + specific information is in + <file:Documentation/networking/vortex.txt> and in the comments at + the beginning of <file:drivers/net/3c59x.c>. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called 3c59x.o. + +Other ISA cards +CONFIG_NET_ISA + If your network (Ethernet) card hasn't been mentioned yet and its + bus system (that's the way the cards talks to the other components + of your computer) is ISA (as opposed to EISA, VLB or PCI), say Y. + Make sure you know the name of your card. Read the Ethernet-HOWTO, + available from <http://www.tldp.org/docs.html#howto>. + + If unsure, say Y. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the remaining ISA network card questions. If you say Y, you will be + asked for your specific card in the following questions. + +Generic ARCnet support +CONFIG_ARCNET + If you have a network card of this type, say Y and check out the + (arguably) beautiful poetry in + <file:Documentation/networking/arcnet.txt>. + + You need both this driver, and the driver for the particular ARCnet + chipset of your card. If you don't know, then it's probably a + COM90xx type card, so say Y (or M) to "ARCnet COM90xx chipset + support" below. + + You might also want to have a look at the Ethernet-HOWTO, available + from <http://www.tldp.org/docs.html#howto>(even though ARCnet + is not really Ethernet). + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called arcnet.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +Enable old ARCNet packet format (RFC 1051) +CONFIG_ARCNET_1051 + This allows you to use RFC1051 with your ARCnet card via the virtual + arc0s device. You only need arc0s if you want to talk to ARCnet + software complying with the "old" standard, specifically, the DOS + arcnet.com packet driver, Amigas running AmiTCP, and some variants + of NetBSD. You do not need to say Y here to communicate with + industry-standard RFC1201 implementations, like the arcether.com + packet driver or most DOS/Windows ODI drivers. RFC1201 is included + automatically as the arc0 device. Please read the ARCnet + documentation in <file:Documentation/networking/arcnet.txt> for more + information about using arc0e and arc0s. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called rfc1051.o. + +Enable standard ARCNet packet format (RFC 1201) +CONFIG_ARCNET_1201 + This allows you to use RFC1201 with your ARCnet card via the virtual + arc0 device. You need to say Y here to communicate with + industry-standard RFC1201 implementations, like the arcether.com + packet driver or most DOS/Windows ODI drivers. Please read the + ARCnet documentation in <file:Documentation/networking/arcnet.txt> + for more information about using arc0. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called rfc1201.o. + +Enable raw mode packet interface +CONFIG_ARCNET_RAW + ARCnet "raw mode" packet encapsulation, no soft headers. Unlikely + to work unless talking to a copy of the same Linux arcnet driver, + but perhaps marginally faster in that case. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called arc-rawmode.o. + +ARCnet COM90xx (normal) chipset driver +CONFIG_ARCNET_COM90xx + This is the chipset driver for the standard COM90xx cards. If you + have always used the old ARCnet driver without knowing what type of + card you had, this is probably the one for you. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called com90xx.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +ARCnet COM90xx (IO mapped) chipset driver +CONFIG_ARCNET_COM90xxIO + This is the chipset driver for the COM90xx cards, using them in + IO-mapped mode instead of memory-mapped mode. This is slower than + the normal driver. Only use it if your card doesn't support shared + memory. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called com90io.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +ARCnet COM90xx (RIM I) chipset driver +CONFIG_ARCNET_RIM_I + This is yet another chipset driver for the COM90xx cards, but this + time only using memory-mapped mode, and no IO ports at all. This + driver is completely untested, so if you have one of these cards, + please mail dwmw2@infradead.org, especially if it works! + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you + want). The module will be called arc-rimi.o. If you want to compile + it as a module, say M here and read <file:Documentation/modules.txt> + as well as <file:Documentation/networking/net-modules.txt>. + +ARCnet COM20020 chipset driver +CONFIG_ARCNET_COM20020 + This is the driver for the new COM20020 chipset. It supports such + things as promiscuous mode, so packet sniffing is possible, and + extra diagnostic information. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called com20020.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt> as + well as <file:Documentation/networking/net-modules.txt>. + +Cabletron E21xx support +CONFIG_E2100 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called e2100.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +CS89x0 support (Daynaport CS and LC cards) +CONFIG_CS89x0 + Support for CS89x0 chipset based Ethernet cards. If you have a + network (Ethernet) card of this type, say Y and read the + Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto> as well as + <file:Documentation/networking/cs89x0.txt>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt> as well as + <file:Documentation/networking/net-modules.txt>. The module will be + called cs89x.o. + +DEPCA, DE10x, DE200, DE201, DE202, DE422 support +CONFIG_DEPCA + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto> as well as + <file:drivers/net/depca.c>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt> as well as + <file:Documentation/networking/net-modules.txt>. The module will be + called + depca.o. + +EtherWORKS 3 (DE203, DE204, DE205) support +CONFIG_EWRK3 + This driver supports the DE203, DE204 and DE205 network (Ethernet) + cards. If this is for you, say Y and read + <file:Documentation/networking/ewrk3.txt> in the kernel source as + well as the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt> as well as + <file:Documentation/networking/net-modules.txt>. The module will be + called ewrk3.o. + +SEEQ8005 support +CONFIG_SEEQ8005 + This is a driver for the SEEQ 8005 network (Ethernet) card. If this + is for you, read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt> as well as + <file:Documentation/networking/net-modules.txt>. The module will be + called ewrk3.o. + +AT1700/1720 support +CONFIG_AT1700 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt> as well as + <file:Documentation/networking/net-modules.txt>. The module will be + called at1700.o. + +FMV-181/182/183/184 support +CONFIG_FMV18X + If you have a Fujitsu FMV-181/182/183/184 network (Ethernet) card, + say Y and read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + If you use an FMV-183 or FMV-184 and it is not working, you may need + to disable Plug & Play mode of the card. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called fmv18x.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +EtherExpressPro and EtherExpress 10 (i82595) support +CONFIG_EEXPRESS_PRO + If you have a network (Ethernet) card of this type, say Y. This + driver supports intel i82595{FX,TX} based boards. Note however + that the EtherExpress PRO/100 Ethernet card has its own separate + driver. Please read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called eepro.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +EtherExpress 16 support +CONFIG_EEXPRESS + If you have an EtherExpress16 network (Ethernet) card, say Y and + read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. Note that the Intel + EtherExpress16 card used to be regarded as a very poor choice + because the driver was very unreliable. We now have a new driver + that should do better. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt> as well as + <file:Documentation/networking/net-modules.txt>. The module will be + called eexpress.o. + +Packet Engines Hamachi GNIC-II support +CONFIG_HAMACHI + If you have a Gigabit Ethernet card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt> as well as + <file:Documentation/networking/net-modules.txt>. The module will be + called hamachi.o. + +HP PCLAN+ (27247B and 27252A) support +CONFIG_HPLAN_PLUS + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called hp-plus.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +HP PCLAN (27245 and other 27xxx series) support +CONFIG_HPLAN + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called hp.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +HP 10/100VG PCLAN (ISA, EISA, PCI) support +CONFIG_HP100 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt> as well as + <file:Documentation/networking/net-modules.txt>. The module will be + called hp100.o. + +NE2000/NE1000 support +CONFIG_NE2000 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. Many Ethernet cards + without a specific driver are compatible with NE2000. + + If you have a PCI NE2000 card however, say N here and Y to "PCI + NE2000 support", above. If you have a NE2000 card and are running on + an MCA system (a bus system used on some IBM PS/2 computers and + laptops), say N here and Y to "NE/2 (ne2000 MCA version) support", + below. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ne.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +National Semiconductor DP8381x series PCI Ethernet support +CONFIG_NATSEMI + This driver is for the National Semiconductor DP83810 series, + which is used in cards from PureData, NetGear, Linksys + and others, including the 83815 chip. + More specific information and updates are available from + <http://www.scyld.com/network/natsemi.html>. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called natsemi.o. + +NatSemi workaround for high errors +CONFIG_NATSEMI_CABLE_MAGIC + Some systems see lots of errors with NatSemi ethernet controllers + on certain cables. If you are seeing lots of errors, try turning + this option on. Some boards have incorrect values for supporting + resistors that can cause this change to break. If you turn this + option on and your network suddenly stops working, turn this + option off. + +SK_G16 support +CONFIG_SK_G16 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + +NE/2 (ne2000 MCA version) support +CONFIG_NE2_MCA + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ne2.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +SKnet MCA support +CONFIG_SKMC + These are Micro Channel Ethernet adapters. You need to say Y to "MCA + support" in order to use this driver. Supported cards are the SKnet + Junior MC2 and the SKnet MC2(+). The driver automatically + distinguishes between the two cards. Note that using multiple boards + of different type hasn't been tested with this driver. Say Y if you + have one of these Ethernet adapters. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called sk_mca.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +IBM LAN Adapter/A support +CONFIG_IBMLANA + This is a Micro Channel Ethernet adapter. You need to set + CONFIG_MCA to use this driver. It is both available as an in-kernel + driver and as a module ( = code which can be inserted in and removed + from the running kernel whenever you want). If you want to compile + it as a module, say M here and read <file:Documentation/modules.txt> + as well as <file:Documentation/networking/net-modules.txt>. The only + currently supported card is the IBM LAN Adapter/A for Ethernet. It + will both support 16K and 32K memory windows, however a 32K window + gives a better security against packet losses. Usage of multiple + boards with this driver should be possible, but has not been tested + up to now due to lack of hardware. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called ibmlana.o. + +EISA, VLB, PCI and on board controllers +CONFIG_NET_PCI + This is another class of network cards which attach directly to the + bus. If you have one of those, say Y and read the Ethernet-HOWTO, + available from <http://www.tldp.org/docs.html#howto>. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about this class of network cards. If you say Y, you + will be asked for your specific card in the following questions. If + you are unsure, say Y. + +AMD PCnet32 (VLB and PCI) support +CONFIG_PCNET32 + If you have a PCnet32 or PCnetPCI based network (Ethernet) card, + answer Y here and read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called pcnet32.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +Ansel Communications EISA 3200 support +CONFIG_AC3200 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ac3200.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +Mylex EISA LNE390A/LNE390B support +CONFIG_LNE390 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called lne390.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +Novell/Eagle/Microdyne NE3210 EISA support +CONFIG_NE3210 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. Note that this driver + will NOT WORK for NE3200 cards as they are completely different. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ne3210.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +Apricot Xen-II on board Ethernet +CONFIG_APRICOT + If you have a network (Ethernet) controller of this type, say Y and + read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt> as well as + <file:Documentation/networking/net-modules.txt>. The module will be + called apricot.o. + +Generic DECchip & DIGITAL EtherWORKS PCI/EISA +CONFIG_DE4X5 + This is support for the DIGITAL series of PCI/EISA Ethernet cards. + These include the DE425, DE434, DE435, DE450 and DE500 models. If + you have a network card of this type, say Y and read the + Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. More specific + information is contained in + <file:Documentation/networking/de4x5.txt>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called de4x5.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +DECchip Tulip (dc21x4x) PCI support +CONFIG_TULIP + This driver is developed for the SMC EtherPower series Ethernet + cards and also works with cards based on the DECchip + 21040/21041/21140 (Tulip series) chips. Some LinkSys PCI cards are + of this type. (If your card is NOT SMC EtherPower 10/100 PCI + (smc9332dst), you can also try the driver for "Generic DECchip" + cards, above. However, most people with a network card of this type + will say Y here.) Do read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. More specific + information is contained in + <file:Documentation/networking/tulip.txt>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called tulip.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +New Tulip bus configuration +CONFIG_TULIP_MWI + This configures your Tulip card specifically for the card and + system cache line size type you are using. + + This is experimental code, not yet tested on many boards. + + If unsure, say N. + +Use PCI shared memory for NIC registers +CONFIG_TULIP_MMIO + Use PCI shared memory for the NIC registers, rather than going through + the Tulip's PIO (programmed I/O ports). Faster, but could produce + obscure bugs if your mainboard has memory controller timing issues. + If in doubt, say N. + +Digi Intl. RightSwitch SE-X support +CONFIG_DGRS + This is support for the Digi International RightSwitch series of + PCI/EISA Ethernet switch cards. These include the SE-4 and the SE-6 + models. If you have a network card of this type, say Y and read the + Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. More specific + information is contained in <file:Documentation/networking/dgrs.txt>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called dgrs.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +EtherExpress Pro/100 support +CONFIG_EEPRO100 + If you have an Intel EtherExpress PRO/100 PCI network (Ethernet) + card, say Y and read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called eepro100.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt> as + well as <file:Documentation/networking/net-modules.txt>. + +Enable Power Management +CONFIG_EEPRO100_PM + Many Intel EtherExpress PRO/100 PCI network cards are capable + of providing power management capabilities. To make use of these + capabilities, say Y. + + WARNING: This option is intended for kernel developers and testers. + It is still very experimental, with some people reporting complete + lockups. + + It is recommended to say N here. + +Myson MTD-8xx PCI Ethernet support +CONFIG_FEALNX + Say Y here to support the Mysom MTD-800 family of PCI-based Ethernet + cards. Specifications and data at + <http://www.myson.com.hk/mtd/datasheet/>. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called fealnx.o. + +LP486E on board Ethernet +CONFIG_LP486E + Say Y here to support the 82596-based on-board Ethernet controller + for the Panther motherboard, which is one of the two shipped in the + Intel Professional Workstation. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called lp486e.o. + +ICL EtherTeam 16i/32 support +CONFIG_ETH16I + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called eth16i.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +TI ThunderLAN support +CONFIG_TLAN + If you have a PCI Ethernet network card based on the ThunderLAN chip + which is supported by this driver, say Y and read the + Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + Devices currently supported by this driver are Compaq Netelligent, + Compaq NetFlex and Olicom cards. Please read the file + <file:Documentation/networking/tlan.txt> for more details. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called tlan.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + + Please email feedback to torben.mathiasen@compaq.com. + +VIA Rhine support +CONFIG_VIA_RHINE + If you have a VIA "rhine" based network card (Rhine-I (3043) or + Rhine-2 (VT86c100A)), say Y here. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called via-rhine.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt> as + well as <file:Documentation/networking/net-modules.txt>. + +VIA Rhine MMIO support (EXPERIMENTAL) +CONFIG_VIA_RHINE_MMIO + This instructs the driver to use PCI shared memory (MMIO) instead of + programmed I/O ports (PIO). Enabling this gives an improvement in + processing time in parts of the driver. + + It is not known if this works reliably on all "rhine" based cards, + but it has been tested successfully on some DFE-530TX adapters. + + If unsure, say N. + +Davicom DM910x/DM980x support +CONFIG_DM9102 + This driver is for DM9102(A)/DM9132/DM9801 compatible PCI cards from + Davicom (<http://www.davicom.com.tw/>). If you have such a network + (Ethernet) card, say Y. Some information is contained in the file + <file:Documentation/networking/dmfe.txt>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called dmfe.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +Racal-Interlan EISA ES3210 support +CONFIG_ES3210 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called es3210.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/networking/net-modules.txt>. + +SMC EtherPower II +CONFIG_EPIC100 + This driver is for the SMC EtherPower II 9432 PCI Ethernet NIC, + which is based on the SMC83c17x (EPIC/100). + More specific information and updates are available from + <http://www.scyld.com/network/epic100.html>. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called epic100.o. + +DEC LANCE Ethernet controller support +CONFIG_DECLANCE + This driver is for the series of Ethernet controllers produced by + DEC (now Compaq) based on the AMD Lance chipset, including the + DEPCA series. (This chipset is better known via the NE2100 cards.) + +SGI Seeq Ethernet controller support +CONFIG_SGISEEQ + Say Y here if you have an Seeq based Ethernet network card. This is + used in many Silicon Graphics machines. + +Sundance Alta PCI Ethernet support +CONFIG_SUNDANCE + This driver is for the Sundance "Alta" chip. + More specific information and updates are available from + <http://www.scyld.com/network/sundance.html>. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called sundance.o. + +Sundance Alta memory-mapped I/O support +CONFIG_SUNDANCE_MMIO + Enable memory-mapped I/O for interaction with Sundance NIC registers. + Do NOT enable this by default, PIO (enabled when MMIO is disabled) + is known to solve bugs on certain chips. + + If unsure, say N. + +Sun3/Sun3x on-board LANCE support +CONFIG_SUN3LANCE + Most Sun3 and Sun3x motherboards (including the 3/50, 3/60 and 3/80) + featured an AMD Lance 10Mbit Ethernet controller on board; say Y + here to compile in the Linux driver for this and enable Ethernet. + General Linux information on the Sun 3 and 3x series (now + discontinued) is at + <http://www.angelfire.com/ca2/tech68k/sun3.html>. + + If you're not building a kernel for a Sun 3, say N. + +Sun3 on-board Intel 82586 support +CONFIG_SUN3_82586 + This driver enables support for the on-board Intel 82586 based + Ethernet adapter found on Sun 3/1xx and 3/2xx motherboards. Note + that this driver does not support 82586-based adapters on additional + VME boards. + +Winbond W89c840 PCI Ethernet support +CONFIG_WINBOND_840 + This driver is for the Winbond W89c840 chip. It also works with + the TX9882 chip on the Compex RL100-ATX board. + More specific information and updates are available from + <http://www.scyld.com/network/drivers.html>. + +Zenith Z-Note support +CONFIG_ZNET + The Zenith Z-Note notebook computer has a built-in network + (Ethernet) card, and this is the Linux driver for it. Note that the + IBM Thinkpad 300 is compatible with the Z-Note and is also supported + by this driver. Read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + +Philips SAA9730 Ethernet support +CONFIG_LAN_SAA9730 + The SAA9730 is a combined multimedia and peripheral controller used + in thin clients, Internet access terminals, and diskless + workstations. + See <http://www.semiconductors.philips.com/pip/SAA9730_flyer_1>. + +Pocket and portable adapters +CONFIG_NET_POCKET + Cute little network (Ethernet) devices which attach to the parallel + port ("pocket adapters"), commonly used with laptops. If you have + one of those, say Y and read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + If you want to plug a network (or some other) card into the PCMCIA + (or PC-card) slot of your laptop instead (PCMCIA is the standard for + credit card size extension cards used by all modern laptops), you + need the pcmcia-cs package (location contained in the file + <file:Documentation/Changes>) and you can say N here. + + Laptop users should read the Linux Laptop home page at + <http://www.cs.utexas.edu/users/kharker/linux-laptop/>. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about this class of network devices. If you say Y, you + will be asked for your specific device in the following questions. + +AT-LAN-TEC/RealTek pocket adapter support +CONFIG_ATP + This is a network (Ethernet) device which attaches to your parallel + port. Read <file:drivers/net/atp.c> as well as the Ethernet-HOWTO, + available from <http://www.tldp.org/docs.html#howto>, if you + want to use this. If you intend to use this driver, you should have + said N to the "Parallel printer support", because the two drivers + don't like each other. + + If you want to compile this driver as a module however ( = code + which can be inserted in and removed from the running kernel + whenever you want), say M here and read + <file:Documentation/modules.txt>. The module will be called atp.o. + +D-Link DE600 pocket adapter support +CONFIG_DE600 + This is a network (Ethernet) device which attaches to your parallel + port. Read <file:Documentation/networking/DLINK.txt> as well as the + Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>, if you want to use + this. It is possible to have several devices share a single parallel + port and it is safe to compile the corresponding drivers into the + kernel. + + If you want to compile this driver as a module however ( = code + which can be inserted in and removed from the running kernel + whenever you want), say M here and read + <file:Documentation/modules.txt>. + The module will be called de600.o. + +D-Link DE620 pocket adapter support +CONFIG_DE620 + This is a network (Ethernet) device which attaches to your parallel + port. Read <file:Documentation/networking/DLINK.txt> as well as the + Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>, if you want to use + this. It is possible to have several devices share a single parallel + port and it is safe to compile the corresponding drivers into the + kernel. + + If you want to compile this driver as a module however ( = code + which can be inserted in and removed from the running kernel + whenever you want), say M here and read + <file:Documentation/modules.txt>. + The module will be called de620.o. + +Token Ring driver support +CONFIG_TR + Token Ring is IBM's way of communication on a local network; the + rest of the world uses Ethernet. To participate on a Token Ring + network, you need a special Token ring network card. If you are + connected to such a Token Ring network and want to use your Token + Ring card under Linux, say Y here and to the driver for your + particular card below and read the Token-Ring mini-HOWTO, available + from <http://www.tldp.org/docs.html#howto>. Most people can + say N here. + +IBM Tropic chipset based adapter support +CONFIG_IBMTR + This is support for all IBM Token Ring cards that don't use DMA. If + you have such a beast, say Y and read the Token-Ring mini-HOWTO, + available from <http://www.tldp.org/docs.html#howto>. + + Warning: this driver will almost definitely fail if more than one + active Token Ring card is present. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ibmtr.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +IBM Olympic chipset PCI adapter support +CONFIG_IBMOL + This is support for all non-Lanstreamer IBM PCI Token Ring Cards. + Specifically this is all IBM PCI, PCI Wake On Lan, PCI II, PCI II + Wake On Lan, and PCI 100/16/4 adapters. + + If you have such an adapter, say Y and read the Token-Ring + mini-HOWTO, available from <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called olympic.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + + Also read <file:Documentation/networking/olympic.txt> or check the + Linux Token Ring Project site for the latest information at + <http://www.linuxtr.net/>. + +IBM Lanstreamer chipset PCI adapter support +CONFIG_IBMLS + This is support for IBM Lanstreamer PCI Token Ring Cards. + + If you have such an adapter, say Y and read the Token-Ring + mini-HOWTO, available from <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a modules ( = code which can be + inserted in and removed from the running kernel whenever you want). + The modules will be called lanstreamer.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + +Generic TMS380 Token Ring ISA/PCI/MCA/EISA adapter support +CONFIG_TMS380TR + This driver provides generic support for token ring adapters + based on the Texas Instruments TMS380 series chipsets. This + includes the SysKonnect TR4/16(+) ISA (SK-4190), SysKonnect + TR4/16(+) PCI (SK-4590), SysKonnect TR4/16 PCI (SK-4591), + Compaq 4/16 PCI, Thomas-Conrad TC4048 4/16 PCI, and several + Madge adapters. If you say Y here, you will be asked to select + which cards to support below. If you're using modules, each + class of card will be supported by a separate module. + + If you have such an adapter and would like to use it, say Y and + read the Token-Ring mini-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + Also read the file <file:Documentation/networking/tms380tr.txt> or + check <http://www.auk.cx/tms380tr/>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called tms380tr.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + +Generic TMS380 PCI support +CONFIG_TMSPCI + This tms380 module supports generic TMS380-based PCI cards. + + These cards are known to work: + - Compaq 4/16 TR PCI + - SysKonnect TR4/16 PCI (SK-4590/SK-4591) + - Thomas-Conrad TC4048 PCI 4/16 + - 3Com Token Link Velocity + + This driver is available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called tmspci.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + +Generic TMS380 ISA support +CONFIG_TMSISA + This tms380 module supports generic TMS380-based ISA cards. + + These cards are known to work: + - SysKonnect TR4/16 ISA (SK-4190) + + This driver is available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called tmsisa.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + +Madge Smart 16/4 PCI Mk2 support +CONFIG_ABYSS + This tms380 module supports the Madge Smart 16/4 PCI Mk2 + cards (51-02). + + This driver is available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called abyss.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + +Madge Smart 16/4 Ringnode MicroChannel +CONFIG_MADGEMC + This tms380 module supports the Madge Smart 16/4 MC16 and MC32 + MicroChannel adapters. + + This driver is available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called madgemc.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + +SMC ISA/MCA Token Ring adapter support +CONFIG_SMCTR + This is support for the ISA and MCA SMC Token Ring cards, + specifically SMC TokenCard Elite (8115T) and SMC TokenCard Elite/A + (8115T/A) adapters. + + If you have such an adapter and would like to use it, say Y or M and + read the Token-Ring mini-HOWTO, available from + <http://www.tldp.org/docs.html#howto> and the file + <file:Documentation/networking/smctr.txt>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called smctr.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + +3COM 3C359 Token Link Velocity XL PCI adapter support +CONFIG_3C359 + This is support for the 3Com PCI Velocity XL cards, specifically + the 3Com 3C359, please note this is not for the 3C339 cards, you + should use the tms380 driver instead. + + If you have such an adapter, say Y and read the Token-Ring + mini-HOWTO, available from <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will will be called 3c359.o. If you want to compile it + as a module, say M here and read Documentation/modules.txt. + + Also read the file <file:Documentation/networking/3c359.txt> or check the + Linux Token Ring Project site for the latest information at + <http://www.linuxtr.net> + +Sun Happy Meal 10/100baseT support +CONFIG_HAPPYMEAL + This driver supports the "hme" interface present on most Ultra + systems and as an option on older Sbus systems. This driver supports + both PCI and Sbus devices. This driver also supports the "qfe" quad + 100baseT device available in both PCI and Sbus configurations. + + This support is also available as a module called sunhme.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +Sun Lance support +CONFIG_SUNLANCE + This driver supports the "le" interface present on all 32-bit Sparc + systems, on some older Ultra systems and as an Sbus option. These + cards are based on the AMD Lance chipset, which is better known + via the NE2100 cards. + + This support is also available as a module called sunlance.o ( = + code which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +Sun BigMAC 10/100baseT support +CONFIG_SUNBMAC + This driver supports the "be" interface available as an Sbus option. + This is Sun's older 100baseT Ethernet device. + + This support is also available as a module called sunbmac.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +Sun QuadEthernet support +CONFIG_SUNQE + This driver supports the "qe" 10baseT Ethernet device, available as + an Sbus option. Note that this is not the same as Quad FastEthernet + "qfe" which is supported by the Happy Meal driver instead. + + This support is also available as a module called sunqe.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +Traffic Shaper +CONFIG_SHAPER + The traffic shaper is a virtual network device that allows you to + limit the rate of outgoing data flow over some other network device. + The traffic that you want to slow down can then be routed through + these virtual devices. See + <file:Documentation/networking/shaper.txt> for more information. + + An alternative to this traffic shaper is the experimental + Class-Based Queueing (CBQ) scheduling support which you get if you + say Y to "QoS and/or fair queueing" above. + + To set up and configure shaper devices, you need the shapecfg + program, available from <ftp://shadow.cabi.net/pub/Linux/> in the + shaper package. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called shaper.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. If + unsure, say N. + +FDDI driver support +CONFIG_FDDI + Fiber Distributed Data Interface is a high speed local area network + design; essentially a replacement for high speed Ethernet. FDDI can + run over copper or fiber. If you are connected to such a network and + want a driver for the FDDI card in your computer, say Y here (and + then also Y to the driver for your FDDI card, below). Most people + will say N. + +Digital DEFEA and DEFPA adapter support +CONFIG_DEFXX + This is support for the DIGITAL series of EISA (DEFEA) and PCI + (DEFPA) controllers which can connect you to a local FDDI network. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called defxx.o. + +SysKonnect FDDI PCI support +CONFIG_SKFP + Say Y here if you have a SysKonnect FDDI PCI adapter. + The following adapters are supported by this driver: + - SK-5521 (SK-NET FDDI-UP) + - SK-5522 (SK-NET FDDI-UP DAS) + - SK-5541 (SK-NET FDDI-FP) + - SK-5543 (SK-NET FDDI-LP) + - SK-5544 (SK-NET FDDI-LP DAS) + - SK-5821 (SK-NET FDDI-UP64) + - SK-5822 (SK-NET FDDI-UP64 DAS) + - SK-5841 (SK-NET FDDI-FP64) + - SK-5843 (SK-NET FDDI-LP64) + - SK-5844 (SK-NET FDDI-LP64 DAS) + - Netelligent 100 FDDI DAS Fibre SC + - Netelligent 100 FDDI SAS Fibre SC + - Netelligent 100 FDDI DAS UTP + - Netelligent 100 FDDI SAS UTP + - Netelligent 100 FDDI SAS Fibre MIC + + Read <file:Documentation/networking/skfp.txt> for information about + the driver. + + Questions concerning this driver can be addressed to: + linux@syskonnect.de + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. This is + recommended. The module will be called skfp.o. + +HIgh Performance Parallel Interface (HIPPI) support +CONFIG_HIPPI + HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and + 1600Mbit/sec dual-simplex switched or point-to-point network. HIPPI + can run over copper (25m) or fiber (300m on multi-mode or 10km on + single-mode). HIPPI networks are commonly used for clusters and to + connect to super computers. If you are connected to a HIPPI network + and have a HIPPI network card in your computer that you want to use + under Linux, say Y here (you must also remember to enable the driver + for your HIPPI card below). Most people will say N here. + +Essential RoadRunner HIPPI PCI adapter support +CONFIG_ROADRUNNER + Say Y here if this is your PCI HIPPI network card. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called rrunner.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. If + unsure, say N. + +Use large TX/RX rings +CONFIG_ROADRUNNER_LARGE_RINGS + If you say Y here, the RoadRunner driver will preallocate up to 2 MB + of additional memory to allow for fastest operation, both for + transmitting and receiving. This memory cannot be used by any other + kernel code or by user space programs. Say Y here only if you have + the memory. + +Acorn Ether1 support +CONFIG_ARM_ETHER1 + If you have an Acorn system with one of these (AKA25) network cards, + you should say Y to this option if you wish to use it with Linux. + +Acorn/ANT Ether3 support +CONFIG_ARM_ETHER3 + If you have an Acorn system with one of these network cards, you + should say Y to this option if you wish to use it with Linux. + +I-Cubed EtherH support +CONFIG_ARM_ETHERH + If you have an Acorn system with one of these network cards, you + should say Y to this option if you wish to use it with Linux. + +EBSA-110 Ethernet interface (AM79C961A) +CONFIG_ARM_AM79C961A + If you wish to compile a kernel for the EBSA-110, then you should + always answer Y to this. + +Support Thumb instructions +CONFIG_ARM_THUMB + Say Y if you want to have kernel support for ARM Thumb instructions, + fault handlers, and system calls. + + The Thumb instruction set is a compressed form of the standard ARM + instruction set resulting in smaller binaries at the expense of + slightly less efficient code. + + If you don't know what this all is, saying Y is a safe choice. + +Support CD-ROM drives that are not SCSI or IDE/ATAPI +CONFIG_CD_NO_IDESCSI + If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y + here, otherwise N. Read the CD-ROM-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about these CD-ROM drives. If you are unsure what you + have, say Y and find out whether you have one of the following + drives. + + For each of these drivers, a file Documentation/cdrom/{driver_name} + exists. Especially in cases where you do not know exactly which kind + of drive you have you should read there. Most of these drivers use a + file drivers/cdrom/{driver_name}.h where you can define your + interface parameters and switch some internal goodies. + + All these CD-ROM drivers are also usable as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want). If you want to compile them as module, say M instead of Y and + read <file:Documentation/modules.txt>. + + If you want to use any of these CD-ROM drivers, you also have to + answer Y or M to "ISO 9660 CD-ROM file system support" below (this + answer will get "defaulted" for you if you enable any of the Linux + CD-ROM drivers). + +Sony CDU31A/CDU33A CD-ROM support +CONFIG_CDU31A + These CD-ROM drives have a spring-pop-out caddyless drawer, and a + rectangular green LED centered beneath it. NOTE: these CD-ROM + drives will not be auto detected by the kernel at boot time; you + have to provide the interface address as an option to the kernel at + boot time as described in <file:Documentation/cdrom/cdu31a> or fill + in your parameters into <file:drivers/cdrom/cdu31a.c>. Try "man + bootparam" or see the documentation of your boot loader (lilo or + loadlin) about how to pass options to the kernel. + + If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM + file system support" below, because that's the file system used on + CD-ROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cdu31a.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Standard Mitsumi [no XA/Multisession] CD-ROM support +CONFIG_MCD + This is the older of the two drivers for the older Mitsumi models + LU-005, FX-001 and FX-001D. This is not the right driver for the + FX-001DE and the triple or quad speed models (all these are + IDE/ATAPI models). Please also the file + <file:Documentation/cdrom/mcd>. + + With the old LU-005 model, the whole drive chassis slides out for cd + insertion. The FX-xxx models use a motorized tray type mechanism. + Note that this driver does not support XA or MultiSession CDs + (PhotoCDs). There is a new driver (next question) which can do + this. If you want that one, say N here. + + If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM + file system support" below, because that's the file system used on + CD-ROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called mcd.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +IRQ channel for Mitsumi CD-ROM +CONFIG_MCD_IRQ + This allows you to specify the default value of the IRQ used by the + driver. This setting can be overridden by passing the "mcd=" + parameter to the kernel at boot time (or at module load time if you + said M to "Standard Mitsumi CD-ROM support"). + +I/O base address for Mitsumi CD-ROM +CONFIG_MCD_BASE + This allows you to specify the default value of the I/O base address + used by the driver. This setting can be overridden by passing the + "mcd=" parameter to the kernel at boot time (or at module load time + if you said M to "Standard Mitsumi CD-ROM support"). + +Mitsumi [XA/MultiSession] CD-ROM support +CONFIG_MCDX + Use this driver if you want to be able to read XA or MultiSession + CDs (PhotoCDs) as well as ordinary CDs with your Mitsumi LU-005, + FX-001 or FX-001D CD-ROM drive. In addition, this driver uses much + less kernel memory than the old one, if that is a concern. This + driver is able to support more than one drive, but each drive needs + a separate interface card. Please read the file + <file:Documentation/cdrom/mcdx>. + + If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM + file system support" below, because that's the file system used on + CD-ROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called mcdx.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Matsushita/Panasonic/Creative, Longshine, TEAC CD-ROM support +CONFIG_SBPCD + This driver supports most of the drives which use the Panasonic or + Sound Blaster interface. Please read the file + <file:Documentation/cdrom/sbpcd>. + + The Matsushita CR-521, CR-522, CR-523, CR-562, CR-563 drives + (sometimes labeled "Creative"), the Creative Labs CD200, the + Longshine LCS-7260, the "IBM External ISA CD-ROM" (in fact a CR-56x + model), the TEAC CD-55A fall under this category. Some other + "electrically compatible" drives (Vertos, Genoa, some Funai models) + are currently not supported; for the Sanyo H94A drive currently a + separate driver (asked later) is responsible. Most drives have a + uniquely shaped faceplate, with a caddyless motorized drawer, but + without external brand markings. The older CR-52x drives have a + caddy and manual loading/eject, but still no external markings. The + driver is able to do an extended auto-probing for interface + addresses and drive types; this can help to find facts in cases you + are not sure, but can consume some time during the boot process if + none of the supported drives gets found. Once your drive got found, + you should enter the reported parameters into + <file:drivers/cdrom/sbpcd.h> and set "DISTRIBUTION 0" there. + + This driver can support up to four CD-ROM controller cards, and each + card can support up to four CD-ROM drives; if you say Y here, you + will be asked how many controller cards you have. If compiled as a + module, only one controller card (but with up to four drives) is + usable. + + If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM + file system support" below, because that's the file system used on + CD-ROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called sbpcd.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Matsushita/Panasonic, ... second CD-ROM controller support +CONFIG_SBPCD2 + Say Y here only if you have two CD-ROM controller cards of this type + (usually only if you have more than four drives). You should enter + the parameters for the second, third and fourth interface card into + <file:drivers/cdrom/sbpcd.h> before compiling the new kernel. Read + the file <file:Documentation/cdrom/sbpcd>. + +Matsushita/Panasonic, ... third CD-ROM controller support +CONFIG_SBPCD3 + Say Y here only if you have three CD-ROM controller cards of this + type (usually only if you have more than six drives). You should + enter the parameters for the second, third and fourth interface card + into <file:include/linux/sbpcd.h> before compiling the new kernel. + Read the file <file:Documentation/cdrom/sbpcd>. + +Matsushita/Panasonic, ... fourth CD-ROM controller support +CONFIG_SBPCD4 + Say Y here only if you have four CD-ROM controller cards of this + type (usually only if you have more than eight drives). You should + enter the parameters for the second, third and fourth interface card + into <file:include/linux/sbpcd.h> before compiling the new kernel. + Read the file <file:Documentation/cdrom/sbpcd>. + +Aztech/Orchid/Okano/Wearnes/TXC/CyDROM CD-ROM support +CONFIG_AZTCD + This is your driver if you have an Aztech CDA268-01A, Orchid + CD-3110, Okano or Wearnes CDD110, Conrad TXC, or CyCD-ROM CR520 or + CR540 CD-ROM drive. This driver -- just like all these CD-ROM + drivers -- is NOT for CD-ROM drives with IDE/ATAPI interfaces, such + as Aztech CDA269-031SE. Please read the file + <file:Documentation/cdrom/aztcd>. + + If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM + file system support" below, because that's the file system used on + CD-ROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called aztcd.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Sony CDU535 CD-ROM support +CONFIG_CDU535 + This is the driver for the older Sony CDU-535 and CDU-531 CD-ROM + drives. Please read the file <file:Documentation/cdrom/sonycd535>. + + If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM + file system support" below, because that's the file system used on + CD-ROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called sonycd535.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +Goldstar R420 CD-ROM support +CONFIG_GSCD + If this is your CD-ROM drive, say Y here. As described in the file + <file:Documentation/cdrom/gscd>, you might have to change a setting + in the file <file:drivers/cdrom/gscd.h> before compiling the + kernel. Please read the file <file:Documentation/cdrom/gscd>. + + If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM + file system support" below, because that's the file system used on + CD-ROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called gscd.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Philips/LMS CM206 CD-ROM support +CONFIG_CM206 + If you have a Philips/LMS CD-ROM drive cm206 in combination with a + cm260 host adapter card, say Y here. Please also read the file + <file:Documentation/cdrom/cm206>. + + If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM + file system support" below, because that's the file system used on + CD-ROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cm206.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Optics Storage DOLPHIN 8000AT CD-ROM support +CONFIG_OPTCD + This is the driver for the 'DOLPHIN' drive with a 34-pin Sony + compatible interface. It also works with the Lasermate CR328A. If + you have one of those, say Y. This driver does not work for the + Optics Storage 8001 drive; use the IDE-ATAPI CD-ROM driver for that + one. Please read the file <file:Documentation/cdrom/optcd>. + + If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM + file system support" below, because that's the file system used on + CD-ROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called optcd.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Sanyo CDR-H94A CD-ROM support +CONFIG_SJCD + If this is your CD-ROM drive, say Y here and read the file + <file:Documentation/cdrom/sjcd>. You should then also say Y or M to + "ISO 9660 CD-ROM file system support" below, because that's the + file system used on CD-ROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called sjcd.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +ISP16/MAD16/Mozart soft configurable cdrom interface support +CONFIG_ISP16_CDI + These are sound cards with built-in cdrom interfaces using the OPTi + 82C928 or 82C929 chips. Say Y here to have them detected and + possibly configured at boot time. In addition, You'll have to say Y + to a driver for the particular cdrom drive you have attached to the + card. Read <file:Documentation/cdrom/isp16> for details. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called isp16.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +iSeries Virtual I/O CD Support +CONFIG_VIOCD + If you are running Linux on an IBM iSeries system and you want to + read a CD drive owned by OS/400, say Y here. + +Quota support +CONFIG_QUOTA + If you say Y here, you will be able to set per user limits for disk + usage (also called disk quotas). Currently, it works only for the + ext2 file system. You need additional software in order to use quota + support; for details, read the Quota mini-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. Probably the quota + support is only useful for multi user systems. If unsure, say N. + +Memory Technology Device (MTD) support +CONFIG_MTD + Memory Technology Devices are flash, RAM and similar chips, often + used for solid state file systems on embedded devices. This option + will provide the generic support for MTD drivers to register + themselves with the kernel and for potential users of MTD devices + to enumerate the devices which are present and obtain a handle on + them. It will also allow you to select individual drivers for + particular hardware and users of MTD devices. If unsure, say N. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + mtdcore.o + +MTD debugging support +CONFIG_MTD_DEBUG + This turns on low-level debugging for the entire MTD sub-system. + Normally, you should say 'N'. + +MTD partitioning support +CONFIG_MTD_PARTITIONS + If you have a device which needs to divide its flash chip(s) up + into multiple 'partitions', each of which appears to the user as + a separate MTD device, you require this option to be enabled. If + unsure, say 'Y'. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + mtdpart.o + + Note, however, that you don't need this option for the DiskOnChip + devices. Partitioning on NFTL 'devices' is a different - that's the + 'normal' form of partitioning used on a block device. + +RedBoot partition table parsing +CONFIG_MTD_REDBOOT_PARTS + RedBoot is a ROM monitor and bootloader which deals with multiple + 'images' in flash devices by putting a table in the last erase block + of the device, similar to a partition table, which gives the + offsets, lengths and names of all the images stored in the flash. + + If you need code which can detect and parse this table, and register + MTD 'partitions' corresponding to each image in the table, enable + this option. + + You will still need the parsing functions to be called by the driver + for your particular device. It won't happen automatically. The + SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for + example. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + redboot.o + +Compaq bootldr partition table parsing +CONFIG_MTD_BOOTLDR_PARTS + The Compaq bootldr deals with multiple 'images' in flash devices + by putting a table in one of the first erase blocks of the device, + similar to a partition table, which gives the offsets, lengths and + names of all the images stored in the flash. + + If you need code which can detect and parse this table, and register + MTD 'partitions' corresponding to each image in the table, enable + this option. + + You will still need the parsing functions to be called by the driver + for your particular device. It won't happen automatically. The + SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for + example. + +ARM Firmware Suite flash layout / partition parsing +CONFIG_MTD_AFS_PARTS + The ARM Firmware Suite allows the user to divide flash devices into + multiple 'images'. Each such image has a header containing its name + and offset/size etc. + + If you need code which can detect and parse these tables, and + register MTD 'partitions' corresponding to each image detected, + enable this option. + + You will still need the parsing functions to be called by the driver + for your particular device. It won't happen automatically. The + 'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example. + +MTD debugging verbosity (0 = quiet, 3 = noisy) +CONFIG_MTD_DEBUG_VERBOSE + Determines the verbosity level of the MTD debugging messages. + +Direct chardevice access to MTD devices +CONFIG_MTD_CHAR + This provides a character device for each MTD device present in + the system, allowing the user to read and write directly to the + memory chips, and also use ioctl() to obtain information about + the device, or to erase parts of it. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + mtdchar.o + +Caching block device access to MTD devices +CONFIG_MTD_BLOCK + Although most flash chips have an erase size too large to be useful + as block devices, it is possible to use MTD devices which are based + on RAM chips in this manner. This block device is a user of MTD + devices performing that function. + + At the moment, it is also required for the Journalling Flash File + System(s) to obtain a handle on the MTD device when it's mounted + (although JFFS and JFFS2 don't actually use any of the functionality + of the mtdblock device). + + Later, it may be extended to perform read/erase/modify/write cycles + on flash chips to emulate a smaller block size. Needless to say, + this is very unsafe, but could be useful for file systems which are + almost never written to. + + You do not need this option for use with the DiskOnChip devices. For + those, enable NFTL support (CONFIG_NFTL) instead. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + mtdblock.o + +Readonly block device access to MTD devices +CONFIG_MTD_BLOCK_RO + This allows you to mount read-only file systems (such as cramfs) + from an MTD device, without the overhead (and danger) of the caching + driver. + + You do not need this option for use with the DiskOnChip devices. For + those, enable NFTL support (CONFIG_NFTL) instead. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + mtdblock_ro.o + +FTL (Flash Translation Layer) support +CONFIG_FTL + This provides support for the original Flash Translation Layer which + is part of the PCMCIA specification. It uses a kind of pseudo- + file system on a flash device to emulate a block device with + 512-byte sectors, on top of which you put a 'normal' file system. + + You may find that the algorithms used in this code are patented + unless you live in the Free World where software patents aren't + legal - in the USA you are only permitted to use this on PCMCIA + hardware, although under the terms of the GPL you're obviously + permitted to copy, modify and distribute the code as you wish. Just + not use it. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + ftl.o + +NFTL (NAND Flash Translation Layer) support +CONFIG_NFTL + This provides support for the NAND Flash Translation Layer which is + used on M-Systems' DiskOnChip devices. It uses a kind of pseudo- + file system on a flash device to emulate a block device with + 512-byte sectors, on top of which you put a 'normal' file system. + + You may find that the algorithms used in this code are patented + unless you live in the Free World where software patents aren't + legal - in the USA you are only permitted to use this on DiskOnChip + hardware, although under the terms of the GPL you're obviously + permitted to copy, modify and distribute the code as you wish. Just + not use it. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + nftl.o + +Write support for NFTL (EXPERIMENTAL) +CONFIG_NFTL_RW + If you're lucky, this will actually work. Don't whinge if it + doesn't. Send mail to the MTD mailing list + <linux-mtd@lists.infradead.org> if you want to help to make it more + reliable. + +Detect flash chips by Common Flash Interface (CFI) probe +CONFIG_MTD_CFI + The Common Flash Interface specification was developed by Intel, + AMD and other flash manufactures that provides a universal method + for probing the capabilities of flash devices. If you wish to + support any device that is CFI-compliant, you need to enable this + option. Visit <http://www.amd.com/products/nvd/overview/cfi.html> + for more information on CFI. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + cfi_probe.o + +CFI Advanced configuration options +CONFIG_MTD_CFI_ADV_OPTIONS + If you need to specify a specific endianness for access to flash + chips, or if you wish to reduce the size of the kernel by including + support for only specific arrangements of flash chips, say 'Y'. This + option does not directly affect the code, but will enable other + configuration options which allow you to do so. + + If unsure, say 'N'. + +Specific CFI Flash geometry selection +CONFIG_MTD_CFI_GEOMETRY + This option does not affect the code directly, but will enable + some other configuration options which would allow you to reduce + the size of the kernel by including support for only certain + arrangements of CFI chips. If unsure, say 'N' and all options + which are supported by the current code will be enabled. + +Support 8-bit buswidth +CONFIG_MTD_CFI_B1 + If you wish to support CFI devices on a physical bus which is + 8 bits wide, say 'Y'. + +Support 16-bit buswidth +CONFIG_MTD_CFI_B2 + If you wish to support CFI devices on a physical bus which is + 16 bits wide, say 'Y'. + +Support 32-bit buswidth +CONFIG_MTD_CFI_B4 + If you wish to support CFI devices on a physical bus which is + 32 bits wide, say 'Y'. + +Support 1-chip flash interleave +CONFIG_MTD_CFI_I1 + If your flash chips are not interleaved - i.e. you only have one + flash chip addressed by each bus cycle, then say 'Y'. + +Support 2-chip flash interleave +CONFIG_MTD_CFI_I2 + If your flash chips are interleaved in pairs - i.e. you have two + flash chips addressed by each bus cycle, then say 'Y'. + +Support 4-chip flash interleave +CONFIG_MTD_CFI_I4 + If your flash chips are interleaved in fours - i.e. you have four + flash chips addressed by each bus cycle, then say 'Y'. + +# Choice: mtd_data_swap +Flash cmd/query data swapping +CONFIG_MTD_CFI_NOSWAP + This option defines the way in which the CPU attempts to arrange + data bits when writing the 'magic' commands to the chips. Saying + 'NO', which is the default when CONFIG_MTD_CFI_ADV_OPTIONS isn't + enabled, means that the CPU will not do any swapping; the chips + are expected to be wired to the CPU in 'host-endian' form. + Specific arrangements are possible with the BIG_ENDIAN_BYTE and + LITTLE_ENDIAN_BYTE, if the bytes are reversed. + + If you have a LART, on which the data (and address) lines were + connected in a fashion which ensured that the nets were as short + as possible, resulting in a bit-shuffling which seems utterly + random to the untrained eye, you need the LART_ENDIAN_BYTE option. + + Yes, there really exists something sicker than PDP-endian :) + +CFI support for Intel/Sharp Extended Command Set chips +CONFIG_MTD_CFI_INTELEXT + The Common Flash Interface defines a number of different command + sets which a CFI-compliant chip may claim to implement. This code + provides support for one of those command sets, used on Intel + StrataFlash and other parts. + +CFI support for AMD/Fujitsu Standard Command Set chips +CONFIG_MTD_CFI_AMDSTD + The Common Flash Interface defines a number of different command + sets which a CFI-compliant chip may claim to implement. This code + provides support for one of those command sets, used on chips + chips including the AMD Am29LV320. + +CFI support for Intel/Sharp Standard Commands +CONFIG_MTD_CFI_INTELSTD + The Common Flash Interface defines a number of different command + sets which a CFI-compliant chip may claim to implement. This code + provides support for one of those command sets. + +pre-CFI Sharp chip support +CONFIG_MTD_SHARP + This option enables support for flash chips using Sharp-compatible + commands, including some which are not CFI-compatible and hence + cannot be used with the CONFIG_MTD_CFI_INTELxxx options. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + sharp.o + +AMD compatible flash chip support (non-CFI) +CONFIG_MTD_AMDSTD + This option enables support for flash chips using AMD-compatible + commands, including some which are not CFI-compatible and hence + cannot be used with the CONFIG_MTD_CFI_AMDSTD option. + + It also works on AMD compatible chips that do conform to CFI. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + amd_flash.o + +Support for RAM chips in bus mapping +CONFIG_MTD_RAM + This option enables basic support for RAM chips accessed through + a bus mapping driver. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + map_ram.o + +Support for ROM chips in bus mapping +CONFIG_MTD_ROM + This option enables basic support for ROM chips accessed through + a bus mapping driver. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + map_rom.o + +JEDEC device support +CONFIG_MTD_JEDEC + Enable older older JEDEC flash interface devices for self + programming flash. It is commonly used in older AMD chips. It is + only called JEDEC because the JEDEC association + <http://www.jedec.org/> distributes the identification codes for the + chips. WARNING!!!! This code does not compile and is incomplete as + are the specific JEDEC devices drivers. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + jedec.o + +CFI Flash device mapped on StrongARM SA11x0 +CONFIG_MTD_SA1100 + This enables access to the flash chips on most platforms based on + the SA1100 and SA1110, including the Assabet and the Compaq iPAQ. + If you have such a board, say 'Y'. + +Support for Compaq bootldr partition tables on SA11x0 +CONFIG_MTD_SA1100_REDBOOT_PARTITIONS + Enabling this option will cause the kernel to look for a RedBoot + FIS (Flash Image System) table in the last erase block of the flash + chips detected. If you are using RedBoot on your SA11x0-based board + and want Linux to present 'partitions' matching the images which + RedBoot has listed, say 'Y'. + +Support for Compaq bootldr partition tables on SA11x0 +CONFIG_MTD_SA1100_BOOTLDR_PARTITIONS + Enabling this option will cause the kernel to look for a Compaq + bootldr partition table on the flash chips detected. If you are + using the Compaq bootldr on your SA11x0-based board and want Linux + to present 'partitions' matching the images which the bootldr has + listed, say 'Y'. + +Flash chip mapping in physical memory +CONFIG_MTD_PHYSMAP + This provides a 'mapping' driver which allows the CFI probe and + command set driver code to communicate with flash chips which + are mapped physically into the CPU's memory. You will need to + configure the physical address and size of the flash chips on + your particular board as well as the bus width. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + physmap.o + +Physical start location of flash chip mapping +CONFIG_MTD_PHYSMAP_START + This is the physical memory location at which the flash chips + are mapped on your particular target board. Refer to the + memory map which should hopefully be in the documentation for + your board. + +Physical length of flash chip mapping +CONFIG_MTD_PHYSMAP_LEN + This is the total length of the mapping of the flash chips on + your particular board. If there is space, or aliases, in the + physical memory map between the chips, this could be larger + than the total amount of flash present. Refer to the memory + map which should hopefully be in the documentation for your + board. + +Buswidth of flash in bytes +CONFIG_MTD_PHYSMAP_BUSWIDTH + This is the total width of the data bus of the flash devices + in octets. For example, if you have a data bus width of 32 + bits, you would set the bus width octet value to 4. This is + used internally by the CFI drivers. + +Flash chip mapping on Sun Microsystems boardsets +CONFIG_MTD_SUN_UFLASH + This provides a 'mapping' driver which supports the way in + which user-programmable flash chips are connected on various + Sun Microsystems boardsets. This driver will require CFI support + in the kernel, so if you did not enable CFI previously, do that now. + +Flash chip mapping on Nora +CONFIG_MTD_NORA + If you had to ask, you don't have one. Say 'N'. + +Flash chip mapping on Photron PNC-2000 +CONFIG_MTD_PNC2000 + PNC-2000 is the name of Network Camera product from PHOTRON + Ltd. in Japan. It uses CFI-compliant flash. + +Flash chip mapping on RPXlite or CLLF PPC board +CONFIG_MTD_RPXLITE + The RPXLite PowerPC board has CFI-compliant chips mapped in + a strange sparse mapping. This 'mapping' driver supports that + arrangement, allowing the CFI probe and command set driver code + to communicate with the chips on the RPXLite board. More at + <http://www.embeddedplanet.com/rpx_lite_specification_sheet.htm>. + +Flash chip mapping on AMD SC520 CDP board +CONFIG_MTD_SC520CDP + The SC520 CDP board has two banks of CFI-compliant chips and one + Dual-in-line JEDEC chip. This 'mapping' driver supports that + arrangement, implementing three MTD devices. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + sc520cdp.o + +Flash chip mapping on Arcom Control Systems SBC-MediaGX +CONFIG_MTD_SBC_GXX + This provides a driver for the on-board flash of Arcom Control + Systems' SBC-GXn family of boards, formerly known as SBC-MediaGX. + By default the flash is split into 3 partitions which are accessed + as separate MTD devices. This board utilizes Intel StrataFlash. + More info at + <http://www.arcomcontrols.com/products/icp/pc104/processors/>. + +CFI Flash device mapped on D-Box2 +CONFIG_MTD_DBOX2 + This enables access routines for the flash chips on the Nokia/Sagem + D-Box 2 board. If you have one of these boards and would like to use + the flash chips on it, say 'Y'. + +CFI Flash device mapped on the XScale IQ80310 board +CONFIG_MTD_IQ80310 + This enables access routines for the flash chips on the Intel XScale + IQ80310 evaluation board. If you have one of these boards and would + like to use the flash chips on it, say 'Y'. + +CFI Flash device mapped on AMD NetSc520 +CONFIG_MTD_NETSC520 + This enables access routines for the flash chips on the AMD NetSc520 + demonstration board. If you have one of these boards and would like + to use the flash chips on it, say 'Y'. + +Flash chip mapping on Arcom Control Systems ELAN-104NC +CONFIG_MTD_ELAN_104NC + This provides a driver for the on-board flash of the Arcom Control + System's ELAN-104NC development board. By default the flash + is split into 3 partitions which are accessed as separate MTD + devices. This board utilizes Intel StrataFlash. More info at + <http://www.arcomcontrols.com/products/icp/pc104/processors/>. + +Flash chip mapping on Compaq iPAQ/Bitsy +CONFIG_MTD_BITSY + This provides a driver for the on-board flash found in Compaq's + iPAQ Palm PC and their research prototype the Itsy. iPAQ info at + <http://www5.compaq.com/products/handhelds/pocketpc/> and the + Itsy <http://www.research.digital.com/wrl/projects/Itsy/index.html>. + +Flash chip mapping on Compaq iPAQ/Bitsy +CONFIG_MTD_DC21285 + This provides a driver for the flash accessed using Intel's + 21285 bridge used with Intel's StrongARM processors. More info at + <http://developer.intel.com/design/bridge/quicklist/dsc-21285.htm>. + +Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board +CONFIG_MTD_CSTM_MIPS_IXX + This provides a mapping driver for the Integrated Tecnology Express, + Inc (ITE) QED-4N-S01B eval board and the Globespan IVR Reference + Board. It provides the necessary addressing, length, buswidth, vpp + code and addition setup of the flash device for these boards. In + addition, this mapping driver can be used for other boards via + setting of the CONFIG_MTD_CSTM_MIPS_IXX_START/LEN/BUSWIDTH + parameters. This mapping will provide one mtd device using one + partition. The start address can be offset from the beginning of + flash and the len can be less than the total flash device size to + allow a window into the flash. Both CFI and JEDEC probes are + called. + +Physical start location of flash chip mapping +CONFIG_MTD_CSTM_MIPS_IXX_START + This is the physical memory location that the MTD driver will + use for the flash chips on your particular target board. + Refer to the memory map which should hopefully be in the + documentation for your board. + +Physical length of flash chip mapping +CONFIG_MTD_CSTM_MIPS_IXX_LEN + This is the total length that the MTD driver will use for the + flash chips on your particular board. Refer to the memory + map which should hopefully be in the documentation for your + board. + +Physical bus width of flash mapping in bytes +CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH + This is the total bus width of the mapping of the flash chips + on your particular board. + +JEDEC Flash device mapped on Mixcom piggyback card +CONFIG_MTD_MIXMEM + This supports the paging arrangement for access to flash chips + on the MixCOM piggyback card, allowing the flash chip drivers + to get on with their job of driving the flash chips without + having to know about the paging. If you have one of these boards, + you probably want to enable this mapping driver. More info is at + <http://www.itc.hu/>. + +JEDEC Flash device mapped on Octagon 5066 SBC +CONFIG_MTD_OCTAGON + This provides a 'mapping' driver which supports the way in which + the flash chips are connected in the Octagon-5066 Single Board + Computer. More information on the board is available at + <http://www.octagonsystems.com/Products/5066/5066.html>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + octagon-5066.o + +JEDEC Flash device mapped on Tempustech VMAX SBC301 +CONFIG_MTD_VMAX + This provides a 'mapping' driver which supports the way in which + the flash chips are connected in the Tempustech VMAX SBC301 Single + Board Computer. More information on the board is available at + <http://www.tempustech.com/tt301.htm>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + vmax301.o + +Support for NAND flash devices +CONFIG_MTD_NAND + This enables support for accessing all type of NAND flash + devices. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + nand.o + +Support for software ECC algorithm +CONFIG_MTD_NAND_ECC + This enables software-based ECC for use with NAND flash chips. It + can detect and correct 1 bit errors per 256 byte blocks. This + should be used to increase the reliability of the data stored and + read on the device. + +Support for verify read after write +CONFIG_MTD_NAND_VERIFY_WRITE + This adds an extra check when data is written to the flash. The + NAND flash device internally checks only bits transitioning + from 1 to 0. There is a rare possibility that even though the + device thinks the write was successful, a bit could have been + flipped accidentally due to device wear, gamma rays, whatever. + Enable this if you are really paranoid. + +Support for the SPIA board +CONFIG_MTD_NAND_SPIA + If you had to ask, you don't have one. Say 'N'. + +M-Systems Disk-On-Chip 1000 support +CONFIG_MTD_DOC1000 + This provides an MTD device driver for the M-Systems DiskOnChip + 1000 devices, which are obsolete so you probably want to say 'N'. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + doc1000.o + +M-Systems Disk-On-Chip 2000 and Millennium support +CONFIG_MTD_DOC2000 + This provides an MTD device driver for the M-Systems DiskOnChip + 2000 and Millennium devices. Originally designed for the DiskOnChip + 2000, it also now includes support for the DiskOnChip Millennium. + If you have problems with this driver and the DiskOnChip Millennium, + you may wish to try the alternative Millennium driver below. To use + the alternative driver, you will need to undefine DOC_SINGLE_DRIVER + in the <file:drivers/mtd/devices/docprobe.c> source code. + + If you use this device, you probably also want to enable the NFTL + 'NAND Flash Translation Layer' option below, which is used to + emulate a block device by using a kind of file system on the flash + chips. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + doc2000.o + +Alternative Disk-On-Chip Millennium support +CONFIG_MTD_DOC2001 + This provides an alternative MTD device driver for the M-Systems + DiskOnChip Millennium devices. Use this if you have problems with + the combined DiskOnChip 2000 and Millennium driver above. To get + the DiskOnChip probe code to load and use this driver instead of + the other one, you will need to undefine DOC_SINGLE_DRIVER near + the beginning of <file:drivers/mtd/devices/docprobe.c>. + + If you use this device, you probably also want to enable the NFTL + 'NAND Flash Translation Layer' option below, which is used to + emulate a block device by using a kind of file system on the flash + chips. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + doc2001.o + +Probe for DiskOnChip devices +CONFIG_MTD_DOCPROBE + This isn't a real config option, it's derived. + +Advanced detection options for DiskOnChip +CONFIG_MTD_DOCPROBE_ADVANCED + This option allows you to specify nonstandard address at which to + probe for a DiskOnChip, or to change the detection options. You + are unlikely to need any of this unless you are using LinuxBIOS. + Say 'N'. + +Probe for 0x55 0xAA BIOS Extension Signature +CONFIG_MTD_DOCPROBE_55AA + Check for the 0x55 0xAA signature of a DiskOnChip, and do not + continue with probing if it is absent. The signature will always be + present for a DiskOnChip 2000 or a normal DiskOnChip Millennium. + Only if you have overwritten the first block of a DiskOnChip + Millennium will it be absent. Enable this option if you are using + LinuxBIOS or if you need to recover a DiskOnChip Millennium on which + you have managed to wipe the first block. + +Physical address of DiskOnChip +CONFIG_MTD_DOCPROBE_ADDRESS + By default, the probe for DiskOnChip devices will look for a + DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000. + This option allows you to specify a single address at which to probe + for the device, which is useful if you have other devices in that + range which get upset when they are probed. + + (Note that on PowerPC, the normal probe will only check at + 0xE4000000.) + + Normally, you should leave this set to zero, to allow the probe at + the normal addresses. + +Probe high addresses +CONFIG_MTD_DOCPROBE_HIGH + By default, the probe for DiskOnChip devices will look for a + DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000. + This option changes to make it probe between 0xFFFC8000 and + 0xFFFEE000. Unless you are using LinuxBIOS, this is unlikely to be + useful to you. Say 'N'. + +Ramix PMC551 PCI Mezzanine ram card support +CONFIG_MTD_PMC551 + This provides a MTD device driver for the Ramix PMC551 RAM PCI card + from Ramix Inc. <http://www.ramix.com/products/memory/pmc551.html>. + These devices come in memory configurations from 32M - 1G. If you + have one, you probably want to enable this. + + If this driver is compiled as a module you get the ability to select + the size of the aperture window pointing into the devices memory. + What this means is that if you have a 1G card, normally the kernel + will use a 1G memory map as its view of the device. As a module, + you can select a 1M window into the memory and the driver will + "slide" the window around the PMC551's memory. This was + particularly useful on the 2.2 kernels on PPC architectures as there + was limited kernel space to deal with. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + pmc551.o + +PMC551 256M DRAM Bugfix +CONFIG_MTD_PMC551_BUGFIX + Some of Ramix's PMC551 boards with 256M configurations have invalid + column and row mux values. This option will fix them, but will + break other memory configurations. If unsure say N. + +PMC551 Debugging +CONFIG_MTD_PMC551_DEBUG + This option makes the PMC551 more verbose during its operation and + is only really useful if you are developing on this driver or + suspect a possible hardware or driver bug. If unsure say N. + +Use extra onboard system memory as MTD device +CONFIG_MTD_SLRAM + If your CPU cannot cache all of the physical memory in your machine, + you can still use it for storage or swap by using this driver to + present it to the system as a Memory Technology Device. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + slram.o + +DEC MS02-NV NVRAM module support +CONFIG_MTD_MS02NV + This is a MTD driver for the DEC's MS02-type (54-20948-01) battery + backed-up NVRAM module. The module was originally meant as an NFS + accelerator. Say Y here if you have a DECstation 5000/2x0 or a + DECsystem 5900 equipped with such a module. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module will + be called ms02-nv.o. + +Debugging RAM test driver +CONFIG_MTD_MTDRAM + This enables a test MTD device driver which uses vmalloc() to + provide storage. You probably want to say 'N' unless you're + testing stuff. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + mtdram.o + +MTDRAM erase block size in KB +CONFIG_MTDRAM_ERASE_SIZE + This allows you to configure the size of the erase blocks in the + device emulated by the MTDRAM driver. If the MTDRAM driver is built + as a module, it is also possible to specify this as a parameter when + loading the module. + +MTDRAM device size in KB +CONFIG_MTDRAM_TOTAL_SIZE + This allows you to configure the total size of the MTD device + emulated by the MTDRAM driver. If the MTDRAM driver is built + as a module, it is also possible to specify this as a parameter when + loading the module. + +SRAM Hexadecimal Absolute position or 0 +CONFIG_MTDRAM_ABS_POS + If you have system RAM accessible by the CPU but not used by Linux + in normal operation, you can give the physical address at which the + available RAM starts, and the MTDRAM driver will use it instead of + allocating space from Linux's available memory. Otherwise, leave + this set to zero. Most people will want to leave this as zero. + +CFI Flash device mapping on the Flaga Digital Module +CONFIG_MTD_CFI_FLAGADM + Mapping for the Flaga digital module. If you don´t have one, ignore + this setting. + +Momenco Ocelot boot flash device +CONFIG_MTD_OCELOT + This enables access routines for the boot flash device and for the + NVRAM on the Momenco Ocelot board. If you have one of these boards + and would like access to either of these, say 'Y'. + +Support for absent chips in bus mapping +CONFIG_MTD_ABSENT + This option enables support for a dummy probing driver used to + allocated placeholder MTD devices on systems that have socketed + or removable media. Use of this driver as a fallback chip probe + preserves the expected registration order of MTD device nodes on + the system regardless of media presence. Device nodes created + with this driver will return -ENODEV upon access. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + map_absent.o + +MTD emulation using block device +CONFIG_MTD_BLKMTD + This driver allows a block device to appear as an MTD. It would + generally be used in the following cases: + + Using Compact Flash as an MTD, these usually present themselves to + the system as an ATA drive. + Testing MTD users (eg JFFS2) on large media and media that might + be removed during a write (using the floppy drive). + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + blkmtd.o + +Cirrus CDB89712 evaluation board mappings +CONFIG_MTD_CDB89712 + This enables access to the flash or ROM chips on the CDB89712 board. + (This board has 8 MB of Intel Strataflash, a 128 byte boot ROM, and 48 KB of + internal SRAM. This driver provides MTD devices for all three components.) + If you have such a board, say 'Y'. + +Detect non-CFI AMD/JEDEC-compatible flash chips +CONFIG_MTD_JEDECPROBE + This option enables JEDEC-style probing of flash chips which are not + compatible with the Common Flash Interface, but will use the common + CFI-targetted flash drivers for any chips which are identified which + are in fact compatible in all but the probe method. This actually + covers most AMD/Fujitsu-compatible chips, and will shortly cover also + non-CFI Intel chips (that code is in MTD CVS and should shortly be sent + for inclusion in Linus' tree) + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + jedec_probe.o + +BIOS flash chip on Intel L440GX boards +CONFIG_MTD_L440GX + Support for treating the BIOS flash chip on Intel L440GX motherboards + as an MTD device - with this you can reprogram your BIOS. + + BE VERY CAREFUL. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + l440gx.o + +28F160xx flash driver for LART +CONFIG_MTD_LART + This enables the flash driver for LART. Please note that you do + not need any mapping/chip driver for LART. This one does it all + for you, so go disable all of those if you enabled some of them (: + +Older (theoretically obsoleted now) drivers for non-CFI chips +CONFIG_MTD_OBSOLETE_CHIPS + This option does not enable any code directly, but will allow you to + select some other chip drivers which are now considered obsolete, + because the generic CONFIG_JEDEC_PROBE code above should now detect + the chips which are supported by these drivers, and allow the generic + CFI-compatible drivers to drive the chips. Say 'N' here unless you have + already tried the CONFIG_JEDEC_PROBE method and reported its failure + to the MTD mailing list at <linux-mtd@lists.infradead.org> + +CFI Flash device mapped on Hitachi SolutionEngine +CONFIG_MTD_SOLUTIONENGINE + This enables access to the flash chips on the Hitachi SolutionEngine and + similar boards. Say 'Y' if you are building a kernel for such a board. + +CFI Flash device mapped on TQM8XXL PPC board +CONFIG_MTD_TQM8XXL + The TQM8xxL PowerPC board has up to two banks of CFI-compliant + chips, currently uses AMD one. This 'mapping' driver supports + that arrangement, allowing the CFI probe and command set driver + code to communicate with the chips on the TQM8xxL board. More at + <http://www.denx.de/embedded-ppc-en.html>. + +Darkness +CONFIG_MEMORY_SET + This is an option about which you will never be asked a question. + Therefore, I conclude that you do not exist - go away. + + There is a grue here. + +Physical memory size +CONFIG_MEMORY_SIZE + This sets the default memory size assumed by your SH kernel. It can + be overridden as normal by the 'mem=' argument on the kernel command + line. If unsure, consult your board specifications or just leave it + as 0x00400000 which was the default value before this became + configurable. + +Cache and PCI noncoherent +CONFIG_SH_PCIDMA_NONCOHERENT + Enable this option if your platform does not have a CPU cache which + remains coherent with PCI DMA. It is safest to say 'Y', although you + will see better performance if you can say 'N', because the PCI DMA + code will not have to flush the CPU's caches. If you have a PCI host + bridge integrated with your SH CPU, refer carefully to the chip specs + to see if you can say 'N' here. Otherwise, leave it as 'Y'. + +USB (Universal Serial Bus) support +CONFIG_USB + Universal Serial Bus (USB) is a specification for a serial bus + subsystem which offers higher speeds and more features than the + traditional PC serial port. The bus supplies power to peripherals + and allows for hot swapping. Up to 127 USB peripherals can be + connected to a single USB port in a tree structure. The USB port is + the root of the tree, the peripherals are the leaves and the inner + nodes are special USB devices called hubs. Many newer PC's have USB + ports and newer peripherals such as scanners, keyboards, mice, + modems, and printers support the USB protocol and can be connected + to the PC via those ports. + + Say Y here if your computer has a USB port and you want to use USB + devices. You then need to say Y to at least one of "UHCI support" + or "OHCI support" below (the type of interface that the USB hardware + in your computer provides to the operating system) and then choose + from among the drivers for USB peripherals. You may want to check + out the information provided in <file:Documentation/usb/> and + especially the links given in <file:Documentation/usb/usb-help.txt>. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called usbcore.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +USB verbose debug messages +CONFIG_USB_DEBUG + Say Y here if you want the USB core & hub drivers to produce a bunch + of debug messages to the system log. Select this if you are having a + problem with USB support and want to see more of what is going on. + +USB long timeout for slow-responding devices (some MGE Ellipse UPSes) +CONFIG_USB_LONG_TIMEOUT + This option makes the standard time out a bit longer. Basically, + some devices are just slow to respond, so this makes usb more + patient. There should be no harm in selecting this, but it is + needed for some MGE Ellipse UPSes. + + If you have an MGE Ellipse UPS, or you see timeouts in HID + transactions, say Y; otherwise say N. + +EHCI (USB 2.0) support +CONFIG_USB_EHCI_HCD + The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0 + "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware. + If your USB host controller supports USB 2.0, you will likely want to + configure this Host Controller Driver. At this writing, the primary + implementation of EHCI is a chip from NEC, widely available in add-on + PCI cards, but implementations are in the works from other vendors + including Intel and Philips. Motherboard support is appearing. + + EHCI controllers are packaged with "companion" host controllers (OHCI + or UHCI) to handle USB 1.1 devices connected to root hub ports. Ports + will connect to EHCI if it the device is high speed, otherwise they + connect to a companion controller. If you configure EHCI, you should + probably configure the OHCI (for NEC and some other vendors) USB Host + Controller Driver too. + + You may want to read <file:Documentation/usb/ehci.txt>. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ehci-hcd.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +UHCI (Intel PIIX4, VIA, ...) support +CONFIG_USB_UHCI + The Universal Host Controller Interface is a standard by Intel for + accessing the USB hardware in the PC (which is also called the USB + host controller). If your USB host controller conforms to this + standard, you may want to say Y, but see below. All recent boards + with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX, + i810, i820) conform to this standard. Also all VIA PCI chipsets + (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro + 133). + + Currently there exist two drivers for UHCI host controllers: this + one and the so-called JE driver, which you can get from + "UHCI alternate (JE) support", below. You need only one. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called usb-uhci.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +UHCI (Intel PIIX4, VIA, ...) alternate (JE) support +CONFIG_USB_UHCI_ALT + The Universal Host Controller Interface is a standard by Intel for + accessing the USB hardware in the PC (which is also called the USB + host controller). If your USB host controller conforms to this + standard, you may want to say Y, but see below. All recent boards + with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX, + i810, i820) conform to this standard. Also all VIA PCI chipsets + (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro + 133). If unsure, say Y. + + Currently there exist two drivers for UHCI host controllers: this + so-called JE driver, and the one you get from "UHCI support", above. + You need only one. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called uhci.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support +CONFIG_USB_OHCI + The Open Host Controller Interface is a standard by + Compaq/Microsoft/National for accessing the USB PC hardware (also + called USB host controller). If your USB host controller conforms to + this standard, say Y. The USB host controllers on most non-Intel + architectures and on several x86 compatibles with non-Intel chipsets + -- like SiS (aktual 610, 610 and so on) or ALi (ALi IV, ALi V, + Aladdin Pro..) -- conform to this standard. + + You may want to read <file:Documentation/usb/ohci.txt>. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called usb-ohci.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + +USB Human Interface Device (full HID) support +CONFIG_USB_HID + Say Y here if you want full HID support to connect keyboards, + mice, joysticks, graphic tablets, or any other HID based devices + to your computer via USB. You also need to select HID Input layer + support (below) if you want to use keyboards, mice, joysticks and + the like. + + You can't use this driver and the HIDBP (Boot Protocol) keyboard + and mouse drivers at the same time. More information is available: + <file:Documentation/input/input.txt>. + + If unsure, say Y. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called hid.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +USB HID Input layer support +CONFIG_USB_HIDINPUT + Say Y here if you want to use a USB keyboard, mouse or joystick, + or any other HID input device. You also need Input layer support, + (CONFIG_INPUT) which you select under "Input core support". + + If unsure, say Y. + +/dev/usb/hiddev raw HID device support +CONFIG_USB_HIDDEV + Say Y here if you want to support HID devices (from the USB + specification standpoint) that aren't strictly user interface + devices, like monitor controls and Uninterruptable Power Supplies. + + This module supports these devices separately using a separate + event interface on /dev/usb/hiddevX (char 180:96 to 180:111). + This driver requires CONFIG_USB_HID. + + If unsure, say Y. + +USB HIDBP Keyboard (basic) support +CONFIG_USB_KBD + Say Y here only if you are absolutely sure that you don't want + to use the generic HID driver for your USB keyboard and prefer + to use the keyboard in its limited Boot Protocol mode instead. + + This is almost certainly not what you want. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called usbkbd.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + + If even remotely unsure, say N. + +USB HIDBP Mouse (basic) support +CONFIG_USB_MOUSE + Say Y here only if you are absolutely sure that you don't want + to use the generic HID driver for your USB keyboard and prefer + to use the keyboard in its limited Boot Protocol mode instead. + + This is almost certainly not what you want. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called usbmouse.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + + If even remotely unsure, say N. + +Wacom Intuos/Graphire tablet support +CONFIG_USB_WACOM + Say Y here if you want to use the USB version of the Wacom Intuos + or Graphire tablet. Make sure to say Y to "Mouse support" + (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" + (CONFIG_INPUT_EVDEV) as well. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called wacom.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Aiptek 6000U/8000U tablet support +CONFIG_USB_AIPTEK + Say Y here if you want to use the USB version of the Aiptek 6000U/8000U + tablet. Make sure to say Y to "Event interface support" + (CONFIG_INPUT_EVDEV) as well. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called aiptek.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Use input layer for ADB devices +CONFIG_INPUT_ADBHID + Say Y here if you want to have ADB (Apple Desktop Bus) HID devices + such as keyboards, mice, joysticks, or graphic tablets handled by + the input layer. If you say Y here, make sure to say Y to the + corresponding drivers "Keyboard support" (CONFIG_INPUT_KEYBDEV), + "Mouse Support" (CONFIG_INPUT_MOUSEDEV) and "Event interface + support" (CONFIG_INPUT_EVDEV) as well. + + If you say N here, you still have the option of using the old ADB + keyboard and mouse drivers. + + If unsure, say Y. + +Input core support +CONFIG_INPUT + Say Y here if you want to enable any of the following options for + USB Human Interface Device (HID) support. + + Say Y here if you want to enable any of the USB HID options in the + USB support section which require Input core support. + + Otherwise, say N. + +Keyboard support +CONFIG_INPUT_KEYBDEV + Say Y here if you want your USB HID keyboard (or an ADB keyboard + handled by the input layer) to be able to serve as a system + keyboard. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called keybdev.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Mouse support +CONFIG_INPUT_MOUSEDEV + Say Y here if you want your USB HID mouse (or ADB mouse handled by + the input layer) to be accessible as char devices 13:32+ - + /dev/input/mouseX and 13:63 - /dev/input/mice as an emulated ImPS/2 + mouse. That way, all user space programs will be able to use your + mouse. + + If unsure, say Y. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called mousedev.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +Horizontal screen resolution +CONFIG_INPUT_MOUSEDEV_SCREEN_X + If you're using a digitizer, or a graphic tablet, and want to use + it as a mouse then the mousedev driver needs to know the X window + screen resolution you are using to correctly scale the data. If + you're not using a digitizer, this value is ignored. + +Vertical screen resolution +CONFIG_INPUT_MOUSEDEV_SCREEN_Y + If you're using a digitizer, or a graphic tablet, and want to use + it as a mouse then the mousedev driver needs to know the X window + screen resolution you are using to correctly scale the data. If + you're not using a digitizer, this value is ignored. + +Joystick support +CONFIG_INPUT_JOYDEV + Say Y here if you want your USB HID joystick or gamepad to be + accessible as char device 13:0+ - /dev/input/jsX device. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called joydev.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Event interface support +CONFIG_INPUT_EVDEV + Say Y here if you want your USB or ADB HID device events be + accessible under char device 13:64+ - /dev/input/eventX in a generic + way. This is the future ... + +USB Scanner support +CONFIG_USB_SCANNER + Say Y here if you want to connect a USB scanner to your computer's + USB port. Please read <file:Documentation/usb/scanner.txt> and + <file:Documentation/usb/scanner-hp-sane.txt> for more information. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called scanner.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +HP 5300C scanner support +CONFIG_USB_HP5300 + Say Y here if you want to connect a HP5300C scanner to your + computer's USB port. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called hp5300.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +USB Audio support +CONFIG_USB_AUDIO + Say Y here if you want to connect USB audio equipment such as + speakers to your computer's USB port. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called audio.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +EMI 2|6 USB Audio interface support +CONFIG_USB_EMI26 + This driver loads firmware to Emagic EMI 2|6 low latency USB + Audio interface. + + After firmware load the device is handled with standard linux + USB Audio driver. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called audio.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +USB Modem (CDC ACM) support +CONFIG_USB_ACM + This driver supports USB modems and ISDN adapters which support the + Communication Device Class Abstract Control Model interface. + Please read <file:Documentation/usb/acm.txt> for details. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called acm.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +USB serial converter support +CONFIG_USB_SERIAL + Say Y here if you have a USB device that provides normal serial + ports, or acts like a serial device, and you want to connect it to + your USB bus. + + Please read <file:Documentation/usb/usb-serial.txt> for more + information on the specifics of the different devices that are + supported, and on how to use them. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called usbserial.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + +USB Generic Serial Driver +CONFIG_USB_SERIAL_GENERIC + Say Y here if you want to use the generic USB serial driver. Please + read <file:Documentation/usb/usb-serial.txt> for more information on + using this driver. It is recommended that the "USB Serial converter + support" be compiled as a module for this driver to be used + properly. + +USB ConnectTech WhiteHEAT Serial Driver +CONFIG_USB_SERIAL_WHITEHEAT + Say Y here if you want to use a ConnectTech WhiteHEAT 4 port + USB to serial converter device. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called whiteheat.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +USB Handspring Visor Driver +CONFIG_USB_SERIAL_VISOR + Say Y here if you want to connect to your HandSpring Visor, Palm + m500 or m505 through its USB docking station. See + <http://usbvisor.sourceforge.net/> for more information on using this + driver. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called visor.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +USB Compaq iPAQ Driver +CONFIG_USB_SERIAL_IPAQ + Say Y here if you want to connect to your Compaq iPAQ, HP Jornada 548/568 + or Casio EM500 running Windows CE 3.0 or PocketPC 2002 using a USB + cradle/cable. For information on using the driver, + read <file:Documentation/usb/usb-serial.txt>. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ipaq.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +USB IR Dongle Serial Driver +CONFIG_USB_SERIAL_IR + Say Y here if you want to enable simple serial support for USB IrDA + devices. This is useful if you do not want to use the full IrDA + stack. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ir-usb.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +USB Belkin and Paracom Single Port Serial Driver +CONFIG_USB_SERIAL_BELKIN + Say Y here if you want to use a Belkin USB Serial single port + adaptor (F5U103 is one of the model numbers) or the Peracom single + port USB to serial adapter. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called belkin_sa.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +USB FTDI Single Port Serial Driver +CONFIG_USB_SERIAL_FTDI_SIO + Say Y here if you want to use a FTDI SIO single port USB to serial + converter device. The implementation I have is called the USC-1000. + This driver has also be tested with the 245 and 232 devices. + + See <http://ftdi-usb-sio.sourceforge.net/> for more + information on this driver and the device. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ftdi_sio.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +USB Keyspan PDA Single Port Serial Driver +CONFIG_USB_SERIAL_KEYSPAN_PDA + Say Y here if you want to use a Keyspan PDA single port USB to + serial converter device. This driver makes use of firmware + developed from scratch by Brian Warner. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called keyspan_pda.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + +USB Xircom / Entregra Single Port Serial Driver +CONFIG_USB_SERIAL_XIRCOM + Say Y here if you want to use a Xircom or Entregra single port USB to + serial converter device. This driver makes use of firmware + developed from scratch by Brian Warner. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called keyspan_pda.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + +USB Keyspan USA-xxx Serial Driver +CONFIG_USB_SERIAL_KEYSPAN + Say Y here if you want to use Keyspan USB to serial converter + devices. This driver makes use of Keyspan's official firmware + and was developed with their support. You must also include + firmware to support your particular device(s). + + See <http://misc.nu/hugh/keyspan.html> for more information. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called keyspan.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +USB Keyspan USA-28 Firmware +CONFIG_USB_SERIAL_KEYSPAN_USA28 + Say Y here to include firmware for the USA-28 converter. + +USB Keyspan USA-28X Firmware +CONFIG_USB_SERIAL_KEYSPAN_USA28X + Say Y here to include firmware for the USA-28X converter. + Be sure you have a USA-28X, there are also 28XA and 28XB + models, the label underneath has the actual part number. + +USB Keyspan USA-28XA Firmware +CONFIG_USB_SERIAL_KEYSPAN_USA28XA + Say Y here to include firmware for the USA-28XA converter. + Be sure you have a USA-28XA, there are also 28X and 28XB + models, the label underneath has the actual part number. + +USB Keyspan USA-28XB Firmware +CONFIG_USB_SERIAL_KEYSPAN_USA28XB + Say Y here to include firmware for the USA-28XB converter. + Be sure you have a USA-28XB, there are also 28X and 28XA + models, the label underneath has the actual part number. + +USB Keyspan USA-19 Firmware +CONFIG_USB_SERIAL_KEYSPAN_USA19 + Say Y here to include firmware for the USA-19 converter. + +USB Keyspan USA-18X Firmware +CONFIG_USB_SERIAL_KEYSPAN_USA18X + Say Y here to include firmware for the USA-18X converter. + +USB Keyspan USA-19W Firmware +CONFIG_USB_SERIAL_KEYSPAN_USA19W + Say Y here to include firmware for the USA-19W converter. + +USB Keyspan USA-19QW Firmware +CONFIG_USB_SERIAL_KEYSPAN_USA19QW + Say Y here to include firmware for the USA-19QW converter. + +USB Keyspan USA-19QI Firmware +CONFIG_USB_SERIAL_KEYSPAN_USA19QI + Say Y here to include firmware for the USA-19QI converter. + +USB Keyspan USA-49W Firmware +CONFIG_USB_SERIAL_KEYSPAN_USA49W + Say Y here to include firmware for the USA-49W converter. + +USB ZyXEL omni.net LCD Plus Driver +CONFIG_USB_SERIAL_OMNINET + Say Y here if you want to use a ZyXEL omni.net LCD ISDN TA. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called omninet.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +USB Digi International AccelePort USB Serial Driver +CONFIG_USB_SERIAL_DIGI_ACCELEPORT + Say Y here if you want to use Digi AccelePort USB 2 or 4 devices, + 2 port (plus parallel port) and 4 port USB serial converters. The + parallel port on the USB 2 appears as a third serial port on Linux. + The Digi Acceleport USB 8 is not yet supported by this driver. + + This driver works under SMP with the usb-uhci driver. It does not + work under SMP with the uhci driver. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called digi_acceleport.o. If you want to compile + it as a module, say M here and read + <file:Documentation/modules.txt>. + +USB Empeg empeg-car Mark I/II Driver +CONFIG_USB_SERIAL_EMPEG + Say Y here if you want to connect to your Empeg empeg-car Mark I/II + mp3 player via USB. The driver uses a single ttyUSB{0,1,2,...} + device node. See <file:Documentation/usb/usb-serial.txt> for more + tidbits of information. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called empeg.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +USB MCT Single Port Serial Driver +CONFIG_USB_SERIAL_MCT_U232 + Say Y here if you want to use a USB Serial single port adapter from + Magic Control Technology Corp. (U232 is one of the model numbers). + + This driver also works with Sitecom U232-P25 and D-Link DU-H3SP USB + BAY devices. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called mct_u232.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +USB Prolific 2303 Single Port Serial Driver +CONFIG_USB_SERIAL_PL2303 + Say Y here if you want to use the PL2303 USB Serial single port + adapter from Prolific. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called pl2303.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +USB REINER SCT cyberJack pinpad/e-com chipcard reader +CONFIG_USB_SERIAL_CYBERJACK + Say Y here if you want to use a cyberJack pinpad/e-com USB chipcard + reader. This is an interface to ISO 7816 compatible contactbased + chipcards, e.g. GSM SIMs. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cyberjack.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + + If unsure, say N. + +USB Edgeport Serial Driver +CONFIG_USB_SERIAL_EDGEPORT + Say Y here if you want to use any of the following devices from + Inside Out Networks (Digi): + Edgeport/4 + Rapidport/4 + Edgeport/4t + Edgeport/2 + Edgeport/4i + Edgeport/2i + Edgeport/421 + Edgeport/21 + Edgeport/8 + Edgeport/8 Dual + Edgeport/2D8 + Edgeport/4D8 + Edgeport/8i + Edgeport/2 DIN + Edgeport/4 DIN + Edgeport/16 Dual + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called io_edgeport.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + +USB PalmConnect (and other KL5KUSB105-based) Single Port Serial Driver +CONFIG_USB_SERIAL_KLSI + Say Y here if you want to use a KL5KUSB105 - based single port + serial adapter. The most widely known -- and currently the only + tested -- device in this category is the PalmConnect USB Serial + adapter sold by Palm Inc. for use with their Palm III and Palm V + series PDAs. + + Please read <file:Documentation/usb/usb-serial.txt> for more + information. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called kl5kusb105.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +USB Serial Converter verbose debug +CONFIG_USB_SERIAL_DEBUG + Say Y here if you want verbose debug messages from the USB Serial + Drivers sent to the kernel debug log. + +USB Printer support +CONFIG_USB_PRINTER + Say Y here if you want to connect a USB printer to your computer's + USB port. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called printer.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +USB IBM (Xirlink) C-It Camera support +CONFIG_USB_IBMCAM + Say Y here if you want to connect a IBM "C-It" camera, also known as + "Xirlink PC Camera" to your computer's USB port. For more + information, read <file:Documentation/usb/ibmcam.txt>. + + This driver uses the Video For Linux API. You must enable + (Y or M in config) Video For Linux (under Character Devices) + to use this driver. Information on this API and pointers to + "v4l" programs may be found on the WWW at + <http://roadrunner.swansea.uk.linux.org/v4l.shtml>. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ibmcam.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. This + camera has several configuration options which can be specified when + you load the module. Read <file:Documentation/usb/ibmcam.txt> to + learn more. + +USB OV511 Camera support +CONFIG_USB_OV511 + Say Y here if you want to connect this type of camera to your + computer's USB port. See <file:Documentation/usb/ov511.txt> for more + information and for a list of supported cameras. + + This driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" (under Character Devices) to use this driver. + Information on this API and pointers to "v4l" programs may be found + on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ov511.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +USB Communication Class Ethernet device support +CONFIG_USB_CDCETHER + This driver supports devices conforming to the Communication Device + Class Ethernet Control Model. This is used in some cable modems. + For more details on the specification, get the Communication Device + Class specification from <http://www.usb.org/>. + + This driver should work with the following devices: + * Ericsson PipeRider (all variants) + * Motorola (DM100 and SB4100) + * Broadcom Cable Modem (reference design) + * Toshiba PCX1100U and possibly other cable modems + * Sharp Zaurus SL-5000D + + The device creates a network device (ethX, where X depends on what + other networking devices you have in use), as for a normal PCI + or ISA based ethernet network card. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called CDCEther.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +NetChip 1080-based USB Host-to-Host Link +CONFIG_USB_NET1080 + The NetChip 1080 is a USB 1.1 host controller. NetChip has a web + site with technical information at <http://www.netchip.com/>. + +Philips webcam support +CONFIG_USB_PWC + Say Y or M here if you want to use one of these Philips USB webcams: + PCA645, PCA646, PCVC675, PCVC680, PCVC690, PCVC730, PCVC740, or + the Askey VC010. The PCA635, PCVC665 and PCVC720 are not supported + by this driver and never will be. + + This driver has an optional plugin, which is distributed as a binary + module only. It contains code that allow you to use higher + resolutions and framerates but may not be distributed as source. + But even without this plugin you can these cams for most + applications. + + See <file:Documentation/usb/philips.txt> for more information and + installation instructions. + + The built-in microphone is enabled by selecting USB Audio support. + + This driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" (under Character Devices) to use this driver. + Information on this API and pointers to "v4l" programs may be found + on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called pwc.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +USB SE401 Camera support +CONFIG_USB_SE401 + Say Y here if you want to connect this type of camera to your + computer's USB port. See <file:Documentation/usb/se401.txt> for more + information and for a list of supported cameras. + + This driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" (under Multimedia Devices) to use this driver. + Information on this API and pointers to "v4l" programs may be found + on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called se401.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +USB STV680 (Pencam) Camera support +CONFIG_USB_STV680 + Say Y here if you want to connect this type of camera to your + computer's USB port. This includes the Pencam line of cameras. + See <file:Documentation/usb/stv680.txt> for more information and for + a list of supported cameras. + + This driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" (under Multimedia Devices) to use this driver. + Information on this API and pointers to "v4l" programs may be found + on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called stv680.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Vicam +CONFIG_USB_VICAM + Say Y here if you have 3com homeconnect camera (vicam). + + This driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" (under Multimedia Devices) to use this driver. + Information on this API and pointers to "v4l" programs may be found + on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called vicam.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + + +Pegasus/Pegasus II based USB-Ethernet device support +CONFIG_USB_PEGASUS + Say Y here if you know you have Pegasus or Pegasus-II based adapter. + If in doubt then look at linux/drivers/usb/pegasus.h for the complete + list of supported devices. + If your particular adapter is not in the list and you are _sure_ it + is Pegasus or Pegasus-II based then send me (pmanolov@users.sourceforge.net) + vendor and device IDs. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called pegasus.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Realtek RTL8150 based USB-Ethernet device support +CONFIG_USB_RTL8150 + Say Y here if you have RTL8150 based usb-ethernet adapter. + Send me (petkan@users.sourceforge.net) any comments you may have. + You can also check for updates at <http://pegasus2.sourceforge.net/> + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called rtl8150.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +USB KLSI KL5USB101-based Ethernet device support +CONFIG_USB_KAWETH + Say Y here if you want to use one of the following 10Mbps only + USB Ethernet adapters based on the KLSI KL5KUSB101B chipset: + 3Com 3C19250 + ADS USB-10BT + ATEN USB Ethernet + ASANTE USB To Ethernet Adapter + AOX Endpoints USB Ethernet + Correga K.K. + D-Link DSB-650C and DU-E10 + Entrega / Portgear E45 + I-O DATA USB-ET/T + Jaton USB Ethernet Device Adapter + Kingston Technology USB Ethernet Adapter + Linksys USB10T + Mobility USB-Ethernet Adapter + NetGear EA-101 + Peracom Enet and Enet2 + Portsmith Express Ethernet Adapter + Shark Pocket Adapter + SMC 2202USB + Sony Vaio port extender + + This driver is likely to work with most 10Mbps only USB Ethernet + adapters, including some "no brand" devices. It does NOT work on + SmartBridges smartNIC or on Belkin F5U111 devices - you should use + the CATC NetMate driver for those. If you are not sure which one + you need, select both, and the correct one should be selected for + you. + + This driver makes the adapter appear as a normal Ethernet interface, + typically on eth0, if it is the only ethernet device, or perhaps on + eth1, if you have a PCI or ISA ethernet card installed. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called kaweth.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +USB CATC NetMate-based Ethernet device support +CONFIG_USB_CATC + Say Y if you want to use one of the following 10Mbps USB Ethernet + device based on the EL1210A chip. Supported devices are: + Belkin F5U011 + Belkin F5U111 + CATC NetMate + CATC NetMate II + smartBridges smartNIC + + This driver makes the adapter appear as a normal Ethernet interface, + typically on eth0, if it is the only ethernet device, or perhaps on + eth1, if you have a PCI or ISA ethernet card installed. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called catc.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +USB Kodak DC-2xx Camera support +CONFIG_USB_DC2XX + Say Y here if you want to connect this type of still camera to your + computer's USB port. See <file:Documentation/usb/dc2xx.txt> for + more information; some non-Kodak cameras may also work with this + driver, given application support (such as <http://www.gphoto.org/>). + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called dc2xx.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +USB Mustek MDC800 Digital Camera support +CONFIG_USB_MDC800 + Say Y here if you want to connect this type of still camera to + your computer's USB port. This driver can be used with gphoto 0.4.3 + and higher (look at <http://www.gphoto.org/>). + To use it create a device node with "mknod /dev/mustek c 180 32" and + configure it in your software. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called mdc800.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +USB Mass Storage support +CONFIG_USB_STORAGE + Say Y here if you want to connect USB mass storage devices to your + computer's USB port. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called usb-storage.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + +USB Mass Storage verbose debug +CONFIG_USB_STORAGE_DEBUG + Say Y here in order to have the USB Mass Storage code generate + verbose debugging messages. + +ISD-200 USB/ATA Bridge support +CONFIG_USB_STORAGE_ISD200 + Say Y here if you want to use USB Mass Store devices based + on the In-Systems Design ISD-200 USB/ATA bridge. + + Some of the products that use this chip are: + + - Archos Jukebox 6000 + - ISD SmartCable for Storage + - Taiwan Skymaster CD530U/DEL-0241 IDE bridge + - Sony CRX10U CD-R/RW drive + - CyQ've CQ8060A CDRW drive + - Planex eXtreme Drive RX-25HU USB-IDE cable (not model RX-25U) + +USS720 parport driver +CONFIG_USB_USS720 + This driver is for USB parallel port adapters that use the Lucent + Technologies USS-720 chip. These cables are plugged into your USB + port and provide USB compatibility to peripherals designed with + parallel port interfaces. + + The chip has two modes: automatic mode and manual mode. In automatic + mode, it looks to the computer like a standard USB printer. Only + printers may be connected to the USS-720 in this mode. The generic + USB printer driver ("USB Printer support", above) may be used in + that mode, and you can say N here if you want to use the chip only + in this mode. + + Manual mode is not limited to printers, any parallel port + device should work. This driver utilizes manual mode. + Note however that some operations are three orders of magnitude + slower than on a PCI/ISA Parallel Port, so timing critical + applications might not work. + + Say Y here if you own an USS-720 USB->Parport cable and intend to + connect anything other than a printer to it. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called uss720.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +USB device file system +CONFIG_USB_DEVICEFS + If you say Y here (and to "/proc file system support" in the "File + systems section, above), you will get a file /proc/bus/usb/devices + which lists the devices currently connected to your USB bus or + busses, a file /proc/bus/usb/drivers which lists the USB kernel + client drivers currently loaded, and for every connected device a + file named "/proc/bus/usb/xxx/yyy", where xxx is the bus number and + yyy the device number; the latter files can be used by user space + programs to talk directly to the device. These files are "virtual", + meaning they are generated on the fly and not stored on the hard + drive. + + You may need to mount the usbdevfs file system to see the files, use + mount -t usbdevfs none /proc/bus/usb + + For the format of the various /proc/bus/usb/ files, please read + <file:Documentation/usb/proc_usb_info.txt>. + + Please note that this code is completely unrelated to devfs, the + "/dev file system support". + + Most users want to say Y here. + +Enforce USB bandwidth allocation +CONFIG_USB_BANDWIDTH + If you say Y here, the USB subsystem enforces USB bandwidth + allocation and will prevent some device opens from succeeding + if they would cause USB bandwidth usage to go above 90% of + the bus bandwidth. + + If you say N here, these conditions will cause warning messages + about USB bandwidth usage to be logged and some devices or + drivers may not work correctly. + +DABUSB driver +CONFIG_USB_DABUSB + A Digital Audio Broadcasting (DAB) Receiver for USB and Linux + brought to you by the DAB-Team (<http://dab.in.tum.de/>). This + driver can be taken as an example for URB-based bulk, control, and + isochronous transactions. URB's are explained in + <file:Documentation/usb/URB.txt>. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called dabusb.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Host-to-Host USB networking +CONFIG_USB_USBNET + This driver supports network links over USB with USB "Network" + or "data transfer" cables, often used to network laptops to PCs. + Such cables have chips from suppliers such as Belkin/eTEK, GeneSys + (GeneLink), NetChip and Prolific. Intelligent USB devices could also + use this approach to provide Internet access, using standard USB + cabling. You can find these chips also on some motherboards with + USB PC2PC support. + + These links will have names like "usb0", "usb1", etc. They act + like two-node Ethernets, so you can use 802.1d Ethernet Bridging + (CONFIG_BRIDGE) to simplify your network routing. + + This code is also available as a kernel module (code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called usbnet.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Freecom USB/ATAPI Bridge support +CONFIG_USB_STORAGE_FREECOM + Support for the Freecom USB to IDE/ATAPI adaptor. + Freecom has a web page at <http://www.freecom.de/>. + +Microtech CompactFlash/SmartMedia reader +CONFIG_USB_STORAGE_DPCM + Say Y here to support the Microtech ZiO! CompactFlash/SmartMedia + reader, details at <http://www.microtechint.com/zio/index.html>. + This driver treats the flash card as a removable storage device. + +SanDisk SDDR-09 (and other SmartMedia) support +CONFIG_USB_STORAGE_SDDR09 + Say Y here to include additional code to support the Sandisk SDDR-09 + SmartMedia reader in the USB Mass Storage driver. + +SanDisk SDDR-55 SmartMedia support +CONFIG_USB_STORAGE_SDDR55 + Say Y here to include additional code to support the Sandisk SDDR-55 + SmartMedia reader in the USB Mass Storage driver. + +USB Diamond Rio500 support +CONFIG_USB_RIO500 + Say Y here if you want to connect a USB Rio500 mp3 player to your + computer's USB port. Please read <file:Documentation/usb/rio.txt> + for more information. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called rio500.o. If you want to compile it as + a module, say M here and read <file:Documenatation/modules.txt>. + +USB Auerswald ISDN device support +CONFIG_USB_AUERSWALD + Say Y here if you want to connect an Auerswald USB ISDN Device + to your computer's USB port. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called auerswald.o. If you want to compile it as + a module, say M here and read <file:Documenatation/modules.txt> + +CONFIG_USB_TIGL + If you own a Texas Instruments graphing calculator and use a + TI-GRAPH LINK USB cable (aka SilverLink), then you might be + interested in this driver. + + If you enable this driver, you will be able to communicate with + your calculator through a set of device nodes under /dev. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called tiglusb.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + + If you don't know what the SilverLink cable is or what a Texas + Instruments graphing calculator is, then you probably don't need this + driver. + + If unsure, say N. + +Tieman Voyager USB Braille display support +CONFIG_USB_BRLVOYAGER + Say Y here if you want to use the Voyager USB Braille display from + Tieman. See <file:Documentation/usb/brlvger.txt> for more + information. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called brlvger.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +USBLCD support +CONFIG_USB_LCD + Say Y here if you want to connect an USBLCD to your computer's + USB port. The USBLCD is a small USB interface board for + alphanumeric LCD modules. See <http://www.usblcd.de> for more + information. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called usblcd.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +D-Link DSB-R100 FM radio support +CONFIG_USB_DSBR + Say Y here if you want to connect this type of radio to your + computer's USB port. Note that the audio is not digital, and + you must connect the line out connector to a sound card or a + set of speakers. + + This driver uses the Video For Linux API. You must enable + (Y or M in config) Video For Linux (under Character Devices) + to use this driver. Information on this API and pointers to + "v4l" programs may be found on the WWW at + <http://roadrunner.swansea.uk.linux.org/v4l.shtml>. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called dsbr100.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Always do synchronous disk IO for UBD +CONFIG_BLK_DEV_UBD_SYNC + The User-Mode Linux port includes a driver called UBD which will let + you access arbitrary files on the host computer as block devices. + Writes to such a block device are not immediately written to the + host's disk; this may cause problems if, for example, the User-Mode + Linux 'Virtual Machine' uses a journalling file system and the host + computer crashes. + + Synchronous operation (i.e. always writing data to the host's disk + immediately) is configurable on a per-UBD basis by using a special + kernel command line option. Alternatively, you can say Y here to + turn on synchronous operation by default for all block. + + If you're running a journalling file system (like reiserfs, for + example) in your virtual machine, you will want to say Y here. If + you care for the safety of the data in your virtual machine, Y is a + wise choice too. In all other cases (for example, if you're just + playing around with User-Mode Linux) you can choose N. + +Enable ptrace proxy +CONFIG_PT_PROXY + This option enables a debugging interface which allows gdb to debug + the kernel without needing to actually attach to kernel threads. + If you want to do kernel debugging, say Y here; otherwise say N. + +Management console +CONFIG_MCONSOLE + The user mode linux management console is a low-level interface to + the kernel, somewhat like the i386 SysRq interface. Since there is + a full-blown operating system running under every user mode linux + instance, there is much greater flexibility possible than with the + SysRq mechanism. + + If you answer 'Y' to this option, to use this feature, you need the + mconsole client (called uml_mconsole) which is present in CVS in + 2.4.5-9um and later (path /tools/mconsole), and is also in the + distribution RPM package in 2.4.6 and later. + + It is safe to say 'Y' here. + +Enable kernel debugging symbols +CONFIG_DEBUGSYM + When this is enabled, the User-Mode Linux binary will include + debugging symbols. This enlarges the binary by a few megabytes, + but aids in tracking down kernel problems in UML. It is required + if you intend to do any kernel development. + + If you're truly short on disk space or don't expect to report any + bugs back to the UML developers, say N, otherwise say Y. + +Enable gcov support +CONFIG_GCOV + This option allows developers to retrieve coverage data from a UML + session. + + See <http://user-mode-linux.sourceforge.net/gcov.html> for more + details. + + If you're involved in UML kernel development and want to use gcov, + say Y. If you're unsure, say N. + +Enable gprof support +CONFIG_GPROF + This allows profiling of a User-Mode Linux kernel with the gprof + utility. + + See <http://user-mode-linux.sourceforge.net/gprof.html> for more + details. + + If you're involved in UML kernel development and want to use gprof, + say Y. If you're unsure, say N. + +Host filesystem +CONFIG_HOSTFS + While the User-Mode Linux port uses its own root file system for + booting and normal file access, this module lets the UML user + access files stored on the host. It does not require any + network connection between the Host and UML. An example use of + this might be: + + mount none /tmp/fromhost -t hostfs -o /tmp/umlshare + + where /tmp/fromhost is an empty directory inside UML and + /tmp/umlshare is a directory on the host with files the UML user + wishes to access. + + For more information, see + <http://user-mode-linux.sourceforge.net/hostfs.html>. + + If you'd like to be able to work with files stored on the host, + say Y or M here; otherwise say N. + +Example IO Memory driver +CONFIG_MMAPPER + The User-Mode Linux port can provide support for IO Memory + emulation with this option. This allows a host file to be + specified as an I/O region on the kernel command line. That file + will be mapped into UML's kernel address space where a driver can + locate it and do whatever it wants with the memory, including + providing an interface to it for UML processes to use. + + For more information, see + <http://user-mode-linux.sourceforge.net/iomem.html>. + + If you'd like to be able to provide a simulated IO port space for + User-Mode Linux processes, say Y. If unsure, say N. + +Virtual Serial Line +CONFIG_SSL + The User-Mode Linux environment allows you to create virtual serial + lines on the UML that are usually made to show up on the host as + ttys or ptys. + + See <http://user-mode-linux.sourceforge.net/input.html> for more + information and command line examples of how to use this facility. + + Unless you have a specific reason for disabling this, say Y. + +Virtual network device +CONFIG_UML_NET + While the User-Mode port cannot directly talk to any physical + hardware devices, this choice and the following transport options + provide one or more virtual network devices through which the UML + kernels can talk to each other, the host, and with the host's help, + machines on the outside world. + + For more information, including explanations of the networking and + sample configurations, see + <http://user-mode-linux.sourceforge.net/networking.html>. + + If you'd like to be able to enable networking in the User-Mode + linux environment, say Y; otherwise say N. Note that you must + enable at least one of the following transport options to actually + make use of UML networking. + +Daemon transport +CONFIG_UML_NET_DAEMON + This User-Mode Linux network transport allows one or more running + UMLs on a single host to communicate with each other, but not to + the host. + + To use this form of networking, you'll need to run the UML + networking daemon on the host. + + For more information, see + <http://user-mode-linux.sourceforge.net/networking.html> That site + has examples of the UML command line to use to enable Daemon + networking. + + If you'd like to set up a network with other UMLs on a single host, + say Y. If you need a network between UMLs on multiple physical + hosts, choose the Multicast Transport. To set up a network with + the host and/or other IP machines, say Y to the Ethertap or Slip + transports. You'll need at least one of them, but may choose + more than one without conflict. If you don't need UML networking, + say N. + +Ethertap transport +CONFIG_UML_NET_ETHERTAP + The Ethertap User-Mode Linux network transport allows a single + running UML to exchange packets with its host over one of the + host's Ethertap devices, such as /dev/tap0. Additional running + UMLs can use additional Ethertap devices, one per running UML. + While the UML believes it's on a (multi-device, broadcast) virtual + Ethernet network, it's in fact communicating over a point-to-point + link with the host. + + To use this, your host kernel must have support for Ethertap + devices. Also, if your host kernel is 2.4.x, it must have + CONFIG_NETLINK_DEV configured as Y or M. + + For more information, see + <http://user-mode-linux.sourceforge.net/networking.html> That site + has examples of the UML command line to use to enable Ethertap + networking. + + If you'd like to set up an IP network with the host and/or the + outside world, say Y to this, the Daemon Transport and/or the + Slip Transport. You'll need at least one of them, but may choose + more than one without conflict. If you don't need UML networking, + say N. + +TUN/TAP transport +CONFIG_UML_NET_TUNTAP + The UML TUN/TAP network transport allows a UML instance to exchange + packets with the host over a TUN/TAP device. This option will only + work with a 2.4 host, unless you've applied the TUN/TAP patch to + your 2.2 host kernel. + + To use this transport, your host kernel must have support for TUN/TAP + devices, either built-in or as a module. + +Multicast transport +CONFIG_UML_NET_MCAST + This Multicast User-Mode Linux network transport allows multiple + UMLs (even ones running on different host machines!) to talk to + each other over a virtual ethernet network. However, it requires + at least one UML with one of the other transports to act as a + bridge if any of them need to be able to talk to their hosts or any + other IP machines. + + To use this, your host kernel(s) must support IP Multicasting. + + For more information, see + <http://user-mode-linux.sourceforge.net/networking.html> That site + has examples of the UML command line to use to enable Multicast + networking, and notes about the security of this approach. + + If you need UMLs on multiple physical hosts to communicate as if + they shared an Ethernet network, say Y. If you need to communicate + with other IP machines, make sure you select one of the other + transports (possibly in addition to Multicast; they're not + exclusive). If you don't need to network UMLs say N to each of + the transports. + +SLIP transport +CONFIG_UML_NET_SLIP + The Slip User-Mode Linux network transport allows a running UML to + network with its host over a point-to-point link. Unlike Ethertap, + which can carry any Ethernet frame (and hence even non-IP packets), + the Slip transport can only carry IP packets. + + To use this, your host must support Slip devices. + + For more information, see + <http://user-mode-linux.sourceforge.net/networking.html>. That site + has examples of the UML command line to use to enable Slip + networking, and details of a few quirks with it. + + The Ethertap Transport is preferred over Slip because of its + limitation. If you prefer Slip, however, say Y here. Otherwise + choose the Multicast transport (to network multiple UMLs on + multiple hosts), Ethertap (to network with the host and the + outside world), and/or the Daemon transport (to network multiple + UMLs on a single host). You may choose more than one without + conflict. If you don't need UML networking, say N. + +Microtek USB scanner support +CONFIG_USB_MICROTEK + Say Y here if you want support for the Microtek X6USB and + possibly the Phantom 336CX, Phantom C6 and ScanMaker V6U(S)L. + Support for anything but the X6 is experimental. + Please report failures and successes. + The scanner will appear as a scsi generic device to the rest + of the system. Scsi support is required for this driver to compile + and work. SANE 1.0.4 or newer is needed to make use of your scanner. + This driver can be compiled as a module. + +HP53xx and Minolta Dual Scanner support +CONFIG_USB_HPUSBSCSI + Say Y here if you want support for the HP 53xx series of scanners + and the Minolta Scan Dual. This driver is experimental. + The scanner will be accessible as a SCSI device. + +USB Bluetooth support +CONFIG_USB_BLUETOOTH + Say Y here if you want to connect a USB Bluetooth device to your + computer's USB port. You will need the Bluetooth stack (available + at <http://developer.axis.com/software/index.shtml>) to fully use + the device. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called bluetooth.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +USB MIDI support +CONFIG_USB_MIDI + Say Y here if you want to connect a USB MIDI device to your + computer's USB port. This driver is for devices that comply with + 'Universal Serial Bus Device Class Definition for MIDI Device'. + + The following devices are known to work: + * Steinberg USB2MIDI + * Roland MPU64 + * Roland PC-300 + * Roland SC8850 + * Roland UM-1 + * Roland UM-2 + * Roland UA-100 + * Yamaha MU1000 + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called usb-midi.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Minix fs support +CONFIG_MINIX_FS + 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. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called minix.o. Note that the file system of your root + partition (the one containing the directory /) cannot be compiled as + a module. + +Reiserfs support +CONFIG_REISERFS_FS + Stores not just filenames but the files themselves in a balanced + tree. Uses journalling. + + 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 <http://www.reiserfs.org/> 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 <http://www.reiserfs.org/> 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. + +Enable extra Reiserfs consistency checks +CONFIG_REISERFS_CHECK + 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. + +Publish some reiserfs-specific info under /proc/fs/reiserfs +CONFIG_REISERFS_PROC_INFO + 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 by 440 bytes. + It isn't useful to average persons, and you probably can't measure the + performance cost of it. If you are fine-tuning reiserfs, say Y, + otherwise say N. + +Second extended fs support +CONFIG_EXT2_FS + This is the de facto standard Linux file system (method to organize + files on a storage device) for hard disks. + + You want to say Y here, unless you intend to use Linux exclusively + from inside a DOS partition using the UMSDOS file system. The + advantage of the latter is that you can get away without + repartitioning your hard drive (which often implies backing + everything up and restoring afterwards); the disadvantage is that + Linux becomes susceptible to DOS viruses and that UMSDOS is somewhat + slower than ext2fs. Even if you want to run Linux in this fashion, + it might be a good idea to have ext2fs around: it enables you to + read more floppy disks and facilitates the transition to a *real* + Linux partition later. Another (rare) case which doesn't require + ext2fs is a diskless Linux box which mounts all files over the + network using NFS (in this case it's sufficient to say Y to "NFS + file system support" below). Saying Y here will enlarge your kernel + by about 44 KB. + + The Ext2fs-Undeletion mini-HOWTO, available from + <http://www.tldp.org/docs.html#howto>, gives information about + how to retrieve deleted files on ext2fs file systems. + + To change the behaviour of ext2 file systems, you can use the tune2fs + utility ("man tune2fs"). To modify attributes of files and + directories on ext2 file systems, use chattr ("man chattr"). + + Ext2fs partitions can be read from within DOS using the ext2tool + command line tool package (available from + <ftp://ibiblio.org/pub/Linux/system/filesystems/ext2/>) and from + within Windows NT using the ext2nt command line tool package from + <ftp://ibiblio.org/pub/Linux/utils/dos/>. Explore2fs is a + graphical explorer for ext2fs partitions which runs on Windows 95 + and Windows NT and includes experimental write support; it is + available from + <http://jnewbigin-pc.it.swin.edu.au/Linux/Explore2fs.htm>. + + If you want to compile this file system as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want), say M here and read <file:Documentation/modules.txt>. The + module will be called ext2.o. 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. Most + everyone wants to say Y here. + +Ext3 journalling file system support (EXPERIMENTAL) +CONFIG_EXT3_FS + This is the journalling 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 journalling 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 + behaviour 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 <http://sourceforge.net/projects/e2fsprogs/>). + + If you want to compile this file system as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want), say M here and read <file:Documentation/modules.txt>. The + module will be called ext3.o. 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. + +Journal Block Device support (JBD for ext3) (EXPERIMENTAL) +CONFIG_JBD + This is a generic journalling 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. + + If you want to compile this device as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called jbd.o. If you are compiling ext3 into the kernel, + you cannot compile this code as a module. + +JBD (ext3) debugging support +CONFIG_JBD_DEBUG + If you are using the ext3 journalling 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". + +Buffer Head tracing (DEBUG) +CONFIG_BUFFER_DEBUG + If you are a kernel developer working with file systems or in the + block device layer, this buffer head tracing may help you to track + down bugs in your code. This enables some debugging macros + (BUFFER_TRACE, etc.) which allow you to track the state of a buffer + through various layers of code. The debugging code is used + primarily by ext3 and JBD code. + + Because this option adds considerably to the size of each buffer, + most people will want to say N here. + +BeOS filesystem support (BeFS) (read only) +CONFIG_BEFS_FS + 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 indices 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 + extremely 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. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called befs.o. + +Debug BeFS +CONFIG_BEFS_DEBUG + If you say Y here, you can use the 'debug' mount option to enable + debugging output from the driver. This is unlike previous versions + of the driver, where enabling this option would turn on debugging + output automatically. + + Example: + mount -t befs /dev/hda2 /mnt -o debug + +BFS file system support +CONFIG_BFS_FS + 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 + <file:Documentation/filesystems/bfs.txt>. + + If you don't know what this is about, say N. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called bfs.o. Note that the file system of your root + partition (the one containing the directory /) cannot be compiled as + a module. + +Compressed ROM file system support +CONFIG_CRAMFS + 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 <file:Documentation/filesystems/cramfs.txt> and + <file:fs/cramfs/README> for further information. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called cramfs.o. Note that the root file system (the one + containing the directory /) cannot be compiled as a module. + + If unsure, say N. + +CMS file system support +CONFIG_CMS_FS + Read only support for CMS minidisk file systems found on IBM + mainframe systems. Only the basic format is supported so far. If + you don't know what CMS is you probably don't want to know any more. + +# When the 2.5 version of configure.help goes away, the part of this that +# duplicates Documentation/filesystems/tmpfs.txt can drop out. +Virtual memory file system support +CONFIG_TMPFS + 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. If you reboot, everything in tmpfs will + be lost. + + In contrast to RAM disks, which get allocated a fixed amount of + physical RAM, tmpfs grows and shrinks to accommodate the files it + contains and is able to swap unneeded pages out to swap space. + + Everything is "virtual" in the sense that no files will be created + on your hard drive; if you reboot, everything in tmpfs will be + lost. + + You should mount the file system somewhere to be able to use + POSIX shared memory. Adding the following line to /etc/fstab should + take care of things: + + tmpfs /dev/shm tmpfs defaults 0 0 + + Remember to create the directory that you intend to mount tmpfs on + if necessary (/dev/shm is automagically created if you use devfs). + + You can set limits for the number of blocks and inodes used by the + file system with the mount options "size", "nr_blocks" and + "nr_inodes". These parameters accept a suffix k, m or g for kilo, + mega and giga and can be changed on remount. + + The initial permissions of the root directory can be set with the + mount option "mode". + + See <file:Documentation/filesystems/tmpfs.txt> for details. + +Simple RAM-based file system support +CONFIG_RAMFS + 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 usable file system. If + you need a file system which lives in RAM with limit checking use + tmpfs. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called ramfs.o. + +ISO 9660 CD-ROM file system support +CONFIG_ISO9660_FS + 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 + <file:Documentation/filesystems/isofs.txt> and the CD-ROM-HOWTO, + available from <http://www.tldp.org/docs.html#howto>), thereby + enlarging your kernel by about 27 KB; otherwise say N. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called isofs.o. + +Microsoft Joliet CD-ROM extensions +CONFIG_JOLIET + 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 + <http://www.unicode.org/> for more information). Say Y here if you + want to be able to read Joliet CD-ROMs under Linux. + +Transparent decompression extension +CONFIG_ZISOFS + 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 + <http://www.kernel.org/pub/linux/utils/fs/zisofs/> for the tools + necessary to create such a filesystem. Say Y here if you want to be + able to read such compressed CD-ROMs. + +UDF file system support (read-only) +CONFIG_UDF_FS + 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. This UDF + file system support is read-only. If you want to write to UDF + file systems on some media, you need to say Y to "UDF read-write + support" below in addition. Please read + <file:Documentation/filesystems/udf.txt>. + + This file system support is also available as a module ( = code + which can be inserted in and removed from the running kernel + whenever you want). The module is called udf.o. If you want to + compile it as a module, say M here and read + <file:Documentation/modules.txt>. + + If unsure, say N. + +UDF write support (DANGEROUS) +CONFIG_UDF_RW + Say Y if you want to test write support for UDF file systems. + Due to lack of support for writing to CDR/CDRW's, this option + is only supported for hard discs, DVD-RAM, and loopback files. + +DOS FAT fs support +CONFIG_FAT_FS + If you want to use one of the FAT-based file systems (the MS-DOS, + VFAT (Windows 95) and UMSDOS (used to run Linux on top of an + ordinary DOS partition) 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 <file:Documentation/filesystems/fat_cvf.txt> for + details. + + The FAT support will enlarge your kernel by about 37 KB. If unsure, + say Y. + + If you want to compile this as a module however ( = code which can + be inserted in and removed from the running kernel whenever you + want), say M here and read <file:Documentation/modules.txt>. The + module will be called fat.o. 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. + The file system of your root partition (the one containing the + directory /) cannot be a module, so don't say M here if you intend + to use UMSDOS as your root file system. + +MSDOS fs support +CONFIG_MSDOS_FS + 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 + <http://www.tldp.org/docs.html#howto>, or try dmsdosfs in + <ftp://ibiblio.org/pub/Linux/system/filesystems/dosfs/>. 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 want to use UMSDOS, the Unix-like file system on top of a + DOS file system, which allows you to run Linux from within a DOS + partition without repartitioning, you'll have to say Y or M here. + + 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. If you want to compile this as a module however ( = code + which can be inserted in and removed from the running kernel + whenever you want), say M here and read + <file:Documentation/modules.txt>. + The module will be called msdos.o. + +VFAT (Windows-95) fs support +CONFIG_VFAT_FS + 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. + + You cannot use the VFAT file system for your Linux root partition + (the one containing the directory /); use UMSDOS instead if you + want to run Linux from within a DOS partition (i.e. say Y to + "Unix like fs on top of std MSDOS fs", below). + + 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 <file:Documentation/filesystems/vfat.txt> for details. If + unsure, say Y. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called vfat.o. + +Unix-like file system on top of standard MSDOS fs +CONFIG_UMSDOS_FS + Say Y here if you want to run Linux from within an existing DOS + partition of your hard drive. The advantage of this is that you can + get away without repartitioning your hard drive (which often implies + backing everything up and restoring afterwards) and hence you're + able to quickly try out Linux or show it to your friends; the + disadvantage is that Linux becomes susceptible to DOS viruses and + that UMSDOS is somewhat slower than ext2fs. Another use of UMSDOS + is to write files with long unix filenames to MSDOS floppies; it + also allows Unix-style soft-links and owner/permissions of files on + MSDOS floppies. You will need a program called umssync in order to + make use of UMSDOS; read + <file:Documentation/filesystems/umsdos.txt>. + + To get utilities for initializing/checking UMSDOS file system, or + latest patches and/or information, visit the UMSDOS home page at + <http://www.voyager.hr/~mnalis/umsdos/>. + + This option enlarges your kernel by about 28 KB and it only works if + you said Y to both "DOS FAT fs support" and "MSDOS fs support" + above. If you want to compile this as a module ( = code which can + be inserted in and removed from the running kernel whenever you + want), say M here and read <file:Documentation/modules.txt>. The + module will be called umsdos.o. Note that the file system of your + root partition (the one containing the directory /) cannot be a + module, so saying M could be dangerous. If unsure, say N. + +/proc file system support +CONFIG_PROC_FS + 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 + <file:Documentation/filesystems/proc.txt> 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. + +Support for PReP Residual Data +CONFIG_PREP_RESIDUAL + Some PReP systems have residual data passed to the kernel by the + firmware. This allows detection of memory size, devices present and + other useful pieces of information. Sometimes this information is + not present or incorrect. + + Unless you expect to boot on a PReP system, there is no need to + select Y. + +PReP residual data available in /proc/residual +CONFIG_PROC_PREPRESIDUAL + Enabling this option will create a /proc/residual file which allows + you to get at the residual data on PReP systems. You will need a tool + (lsresidual) to parse it. If you aren't on a PReP system, you don't + want this. + +/dev file system support +CONFIG_DEVFS_FS + This is support for devfs, a virtual file system (like /proc) which + provides the file system interface to device drivers, normally found + in /dev. Devfs does not depend on major and minor number + allocations. Device drivers register entries in /dev which then + appear automatically, which means that the system administrator does + not have to create character and block special device files in the + /dev directory using the mknod command (or MAKEDEV script) anymore. + + This is work in progress. If you want to use this, you *must* read + the material in <file:Documentation/filesystems/devfs/>, especially + the file README there. + + If unsure, say N. + +Automatically mount devfs at boot time +CONFIG_DEVFS_MOUNT + This option appears if you have CONFIG_DEVFS_FS enabled. Setting + this to 'Y' will make the kernel automatically mount devfs onto /dev + when the system is booted, before the init thread is started. + You can override this with the "devfs=nomount" boot option. + + If unsure, say N. + +Debug devfs +CONFIG_DEVFS_DEBUG + If you say Y here, then the /dev file system code will generate + debugging messages. See the file + <file:Documentation/filesystems/devfs/boot-options> for more + details. + + If unsure, say N. + +NFS file system support +CONFIG_NFS_FS + 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 + <http://www.tldp.org/docs.html#guide>, 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. + + This file system is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called nfs.o. If you want to compile it as a module, + say M here and read <file:Documentation/modules.txt>. + + 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 + <http://ftp1.sourceforge.net/netboot/>, and Etherboot, + available from <http://ftp1.sourceforge.net/etherboot/>. + + If you don't know what all this is about, say N. + +Provide NFSv3 client support +CONFIG_NFS_V3 + Say Y here if you want your NFS client to be able to speak the newer + version 3 of the NFS protocol. + + If unsure, say N. + +Root file system on NFS +CONFIG_ROOT_NFS + 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 <file:Documentation/nfsroot.txt> 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. + +NFS server support +CONFIG_NFSD + 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 <file:Documentation/Changes> 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 + <http://www.tldp.org/docs.html#howto>. + + The NFS server is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called nfsd.o. If you want to compile it as a module, + say M here and read <file:Documentation/modules.txt>. If unsure, + say N. + +Provide NFSv3 server support +CONFIG_NFSD_V3 + If you would like to include the NFSv3 server as well as the NFSv2 + server, say Y here. If unsure, say Y. + +Provide NFS over TCP server support EXPERIMENTAL +CONFIG_NFSD_TCP + Enable NFS service over TCP connections. This the officially + still experimental, but seems to work well. + +OS/2 HPFS file system support +CONFIG_HPFS_FS + 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 + <file:Documentation/filesystems/hpfs.txt>. + + This file system is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called hpfs.o. If you want to compile it as a module, + say M here and read <file:Documentation/modules.txt>. If unsure, + say N. + +NTFS file system support (read-only) +CONFIG_NTFS_FS + NTFS is the file system of Microsoft Windows NT. Say Y if you want + to get read access to files on NTFS partitions of your hard drive. + The Linux NTFS driver supports most of the mount options of the VFAT + driver, see <file:Documentation/filesystems/ntfs.txt>. Saying Y here + will give you read-only access to NTFS partitions. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ntfs.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +NTFS write support (DANGEROUS) +CONFIG_NTFS_RW + If you say Y here, you will (maybe) be able to write to NTFS file + systems as well as read from them. The read-write support in NTFS + is far from being complete and is not well tested. If you say Y + here, back up your NTFS volume first, since it will probably get + damaged. Also, download the Linux-NTFS project distribution from + Sourceforge at <http://linux-ntfs.sf.net/> and always run the + included ntfsfix utility after writing to an NTFS partition from + Linux to fix some of the damage done by the driver. You should run + ntfsfix _after_ unmounting the partition in Linux but _before_ + rebooting into Windows. When Windows next boots, chkdsk will be + run automatically to fix the remaining damage. + Please note that write support is limited to Windows NT4 and + earlier versions. + + If unsure, say N. + +System V/Xenix/V7/Coherent file system support +CONFIG_SYSV_FS + 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 + <ftp://ftp.openlinux.org/pub/people/hch/linux-abi/>). + 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 + <file:Documentation/filesystems/sysv-fs.txt>. + Saying Y here will enlarge your kernel by about 27 KB. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called sysv.o. + + If you haven't heard about all of this before, it's safe to say N. + +Amiga FFS file system support +CONFIG_AFFS_FS + 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 <file:Documentation/filesystems/affs.txt> + and <file:fs/affs/Changes>. + + With this driver you can also mount disk files used by Bernd + Schmidt's Un*X Amiga Emulator + (<http://www.freiburg.linux.de/~uae/>). + If you want to do this, you will also need to say Y or M to "Loop + device support", above. + + This file system is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called affs.o. If you want to compile it as a module, + say M here and read <file:Documentation/modules.txt>. If unsure, + say N. + +Apple Macintosh file system support +CONFIG_HFS_FS + 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 <file:fs/hfs/HFS.txt> to learn about the available mount + options. + + This file system support is also available as a module ( = code + which can be inserted in and removed from the running kernel + whenever you want). The module is called hfs.o. If you want to + compile it as a module, say M here and read + <file:Documentation/modules.txt>. + +ROM file system support +CONFIG_ROMFS_FS + 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 + <file:Documentation/filesystems/romfs.txt> for details. + + This file system support is also available as a module ( = code + which can be inserted in and removed from the running kernel + whenever you want). The module is called romfs.o. If you want to + compile it as a module, say M here and read + <file:Documentation/modules.txt>. 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. + +QNX4 file system support (read only) +CONFIG_QNX4FS_FS + 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 <http://www.qnx.com/>. + 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. + + This file system support is also available as a module ( = code + which can be inserted in and removed from the running kernel + whenever you want). The module is called qnx4.o. If you want to + compile it as a module, say M here and read + <file:Documentation/modules.txt>. + + If you don't know whether you need it, then you don't need it: + answer N. + +QNX4FS write support (DANGEROUS) +CONFIG_QNX4FS_RW + Say Y if you want to test write support for QNX4 file systems. + + It's currently broken, so for now: + answer N. + +Kernel automounter support +CONFIG_AUTOFS_FS + 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 <file:Documentation/Changes>. + 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. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called autofs.o. + + If you are not a part of a fairly large, distributed network, you + probably do not need an automounter, and can say N here. + +Kernel automounter version 4 support (also supports v3) +CONFIG_AUTOFS4_FS + 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 + <ftp://ftp.kernel.org/pub/linux/daemons/autofs/testing-v4/>; you also + want to answer Y to "NFS file system support", below. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called autofs4.o. 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. + +EFS file system support (read-only) +CONFIG_EFS_FS + 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 <http://aeschi.ch.eu.org/efs/>. + + If you want to compile the EFS file system support as a module ( = + code which can be inserted in and removed from the running kernel + whenever you want), say M here and read + <file:Documentation/modules.txt>. The module will be called efs.o. + +Journalling Flash File System (JFFS) support +CONFIG_JFFS_FS + JFFS is the Journalling 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 (<http://developer.axis.com/software/jffs/>). + +JFFS debugging verbosity (0 = quiet, 3 = noisy) +CONFIG_JFFS_FS_VERBOSE + Determines the verbosity level of the JFFS debugging messages. + +Journalling Flash File System v2 (JFFS2) support +CONFIG_JFFS2_FS + 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 should be made available soon at + <http://sources.redhat.com/jffs2/>. + +JFFS2 debugging verbosity (0 = quiet, 2 = noisy) +CONFIG_JFFS2_FS_DEBUG + 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. + +JFFS stats available in /proc filesystem +CONFIG_JFFS_PROC_FS + Enabling this option will cause statistics from mounted JFFS file systems + to be made available to the user in the /proc/fs/jffs/ directory. + +UFS file system support (read-only) +CONFIG_UFS_FS + 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 <file:Documentation/filesystems/ufs.txt> for more information. + + 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. + + If you want to compile the UFS file system support as a module ( = + code which can be inserted in and removed from the running kernel + whenever you want), say M here and read + <file:Documentation/modules.txt>. The module will be called ufs.o. + + If you haven't heard about all of this before, it's safe to say N. + +UFS file system write support (DANGEROUS) +CONFIG_UFS_FS_WRITE + Say Y here if you want to try writing to UFS partitions. This is + experimental, so you should back up your UFS partitions beforehand. + +Advanced partition selection +CONFIG_PARTITION_ADVANCED + Say Y here if you would like to use hard disks under Linux which + were partitioned under an operating system running on a different + architecture than your Linux system. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about foreign partitioning schemes. + + If unsure, say N. + +Acorn partition support +CONFIG_ACORN_PARTITION + Support hard disks partitioned under Acorn operating systems. + +Native filecore partition support +CONFIG_ACORN_PARTITION_ADFS + 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 support disk partitions created under ADFS. + +PowerTec partition support +CONFIG_ACORN_PARTITION_POWERTEC + Support reading partition tables created on Acorn machines using + the PowerTec SCSI drive. + +RISCiX partition support +CONFIG_ACORN_PARTITION_RISCIX + Once upon a time, there was a native Unix port for the Acorn series + of machines called RISCiX. If you say 'Y' here, Linux will be able + to read disks partitioned under RISCiX. + +ICS partition support +CONFIG_ACORN_PARTITION_ICS + Say Y here if you would like to use hard disks under Linux which + were partitioned using the ICS interface on Acorn machines. + +Alpha OSF partition support +CONFIG_OSF_PARTITION + Say Y here if you would like to use hard disks under Linux which + were partitioned on an Alpha machine. + +Macintosh partition map support +CONFIG_MAC_PARTITION + Say Y here if you would like to use hard disks under Linux which + were partitioned on a Macintosh. + +Windows Logical Disk Manager (Dynamic Disk) support (EXPERIMENTAL) +CONFIG_LDM_PARTITION + Say Y here if you would like to use hard disks under Linux which + were partitioned using Windows 2000's or XP's Logical Disk Manager. + They are also known as "Dynamic Disks". + + Windows 2000 introduced the concept of Dynamic Disks to get around + the limitations of the PC's partitioning scheme. The Logical Disk + Manager allows the user to repartition a disk and create spanned, + mirrored, striped or RAID volumes, all without the need for + rebooting. + + Normal partitions are now called Basic Disks under Windows 2000 and + XP. + + Technical documentation to accompany this driver is available from: + <http://linux-ntfs.sf.net/ldm/>. + + If unsure, say N. + +Windows LDM extra logging +CONFIG_LDM_DEBUG + Say Y here if you would like LDM to log verbosely. This could be + helpful if the driver doesn't work as expected and you'd like to + report a bug. + + If unsure, say N. + +PC BIOS (MSDOS partition tables) support +CONFIG_MSDOS_PARTITION + Say Y here if you would like to use hard disks under Linux which + were partitioned on an x86 PC (not necessarily by DOS). + +Amiga partition table support +CONFIG_AMIGA_PARTITION + Say Y here if you would like to use hard disks under Linux which + were partitioned under AmigaOS. + +Atari partition table support +CONFIG_ATARI_PARTITION + Say Y here if you would like to use hard disks under Linux which + were partitioned under the Atari OS. + +BSD disklabel (FreeBSD partition tables) support +CONFIG_BSD_DISKLABEL + FreeBSD uses its own hard disk partition scheme on your PC. It + requires only one entry in the primary partition table of your disk + and manages it similarly to DOS extended partitions, putting in its + first sector a new partition table in BSD disklabel format. Saying Y + here allows you to read these disklabels and further mount FreeBSD + partitions from within Linux if you have also said Y to "UFS + file system support", above. If you don't know what all this is + about, say N. + +Minix subpartition support +CONFIG_MINIX_SUBPARTITION + Minix 2.0.0/2.0.2 subpartition table support for Linux. + Say Y here if you want to mount and use Minix 2.0.0/2.0.2 + subpartitions. + +Sun partition table support +CONFIG_SUN_PARTITION + Like most systems, SunOS uses its own hard disk partition table + format, incompatible with all others. Saying Y here allows you to + read these partition tables and further mount SunOS partitions from + within Linux if you have also said Y to "UFS file system support", + above. This is mainly used to carry data from a SPARC under SunOS to + your Linux box via a removable medium like magneto-optical or ZIP + drives; note however that 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"). If + you don't know what all this is about, say N. + +Solaris (x86) partition table support +CONFIG_SOLARIS_X86_PARTITION + Like most systems, Solaris x86 uses its own hard disk partition + table format, incompatible with all others. Saying Y here allows you + to read these partition tables and further mount Solaris x86 + partitions from within Linux if you have also said Y to "UFS + file system support", above. + +SGI partition support +CONFIG_SGI_PARTITION + Say Y here if you would like to be able to read the hard disk + partition table format used by SGI machines. + +Intel EFI GUID partition support +CONFIG_EFI_PARTITION + Say Y here if you would like to use hard disks under Linux which + were partitioned using EFI GPT. Presently only useful on the + IA-64 platform. + +Ultrix partition table support +CONFIG_ULTRIX_PARTITION + Say Y here if you would like to be able to read the hard disk + partition table format used by DEC (now Compaq) Ultrix machines. + Otherwise, say N. + +IBM disk label and partition support +CONFIG_IBM_PARTITION + You have to say Y here if you would like to be able to read volume + labels of IBM DASD disks. These can be ECKD DASD disks with + compatible disk layout (cdl) and standard Linux disk layout (ldl), + FBA DASD disks and CMS reserved minidisks. + Otherwise, say N and you will not be able to access these disks. + +ADFS file system support +CONFIG_ADFS_FS + 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 + <file:Documentation/filesystems/adfs.txt> for further details. + + This code is also available as a module called adfs.o ( = code which + can be inserted in and removed from the running kernel whenever you + want). If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. + + If unsure, say N. + +ADFS write support (DANGEROUS) +CONFIG_ADFS_FS_RW + 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. + +JFS filesystem support +CONFIG_JFS_FS + This is a port of IBM's Journalling Filesystem . More information is + available in the file Documentation/filesystems/jfs.txt. + + If you do not intend to use the JFS filesystem, say N. + +JFS Debugging +CONFIG_JFS_DEBUG + 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. + +JFS Statistics +CONFIG_JFS_STATISTICS + Enabling this option will cause statistics from the JFS file system + to be made available to the user in the /proc/fs/jfs/ directory. + +/dev/pts file system for Unix98 PTYs +CONFIG_DEVPTS_FS + You should say Y here if you said Y to "Unix98 PTY support" above. + You'll then get a virtual file system which can be mounted on + /dev/pts with "mount -t devpts". This, together with the pseudo + terminal master multiplexer /dev/ptmx, is used for pseudo terminal + support as described in The Open Group's Unix98 standard: in order + to acquire a pseudo terminal, a process opens /dev/ptmx; the number + of the pseudo terminal is then made available to the process and the + pseudo terminal slave can be accessed as /dev/pts/<number>. What was + traditionally /dev/ttyp2 will then be /dev/pts/2, for example. + + The GNU C library glibc 2.1 contains the requisite support for this + mode of operation; you also need client programs that use the Unix98 + API. Please read <file:Documentation/Changes> for more information + about the Unix98 pty devices. + + Note that the experimental "/dev file system support" + (CONFIG_DEVFS_FS) is a more general facility. + +FreeVxFS file system support (VERITAS VxFS(TM) compatible) +CONFIG_VXFS_FS + 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. + + This file system is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called freevxfs.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. If + unsure, say N. + +UnixWare slices support +CONFIG_UNIXWARE_DISKLABEL + Like some systems, UnixWare uses its own slice table inside a + partition (VTOC - Virtual Table of Contents). Its format is + incompatible with all other OSes. Saying Y here allows you to read + VTOC and further mount UnixWare partitions read-only from within + Linux if you have also said Y to "UFS file system support" or + "System V and Coherent file system support", above. + + This is mainly used to carry data from a UnixWare box to your + Linux box via a removable medium like magneto-optical, ZIP or + removable IDE drives. Note, however, that 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"). + + If you don't know what all this is about, say N. + +CIFS (Common Internet File System) support +CONFIG_CIFS + 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. CIFS is fully supported by current network + file servers such as Windows 2000, Windows 2003 (including + Windows XP) as well by Samba (which provides excellent CIFS + server support for Linux and many other operating systems). + The smbfs module should be used instead of this cifs module for + mounting to older SMB servers such as OS/2. The smbfs and cifs + modules can coexist and do not conflict. + + The intent of this module is to provide the most advanced network + file system function for CIFS compliant servers, including better + POSIX compliance, secure per-user session establishment, high + performance safe distributed caching (oplock), optional packet + signing, Unicode support and other internationalization improvements + For more information see the project page at + http://us1.samba.org/samba/Linux_CIFS_client.html + +CIFS Debugging +CONFIG_CIFS_DEBUG + If you are experiencing any problems with the CIFS 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. + +SMB file system support (to mount Windows shares etc.) +CONFIG_SMB_FS + 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 + <file:Documentation/filesystems/smbfs.txt> and the SMB-HOWTO, + available from <http://www.tldp.org/docs.html#howto>. + + 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 <ftp://ftp.samba.org/pub/samba/>) + for that. + + General information about how to connect Linux, Windows machines and + Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>. + + If you want to compile the SMB support as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want), say M here and read <file:Documentation/modules.txt>. The + module will be called smbfs.o. Most people say N, however. + +Use a default NLS +CONFIG_SMB_NLS_DEFAULT + 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. + +Default Remote NLS Option +CONFIG_SMB_NLS_REMOTE + 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. + +Coda file system support (advanced network fs) +CONFIG_CODA_FS + 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 + <file:Documentation/filesystems/coda.txt> and check out the Coda + home page <http://www.coda.cs.cmu.edu/>. + + If you want to compile the coda client support as a module ( = code + which can be inserted in and removed from the running kernel + whenever you want), say M here and read + <file:Documentation/modules.txt>. The module will be called coda.o. + +InterMezzo file system support (replicating fs) +CONFIG_INTERMEZZO_FS + InterMezzo is a networked file system with disconnected operation + and kernel level write back caching. It is most often used for + replicating potentially large trees or keeping laptop/desktop copies + in sync. + + If you say Y or M your kernel or module will provide InterMezzo + support. You will also need a file server daemon, which you can get + from <http://www.inter-mezzo.org/>. + +NCP file system support (to mount NetWare volumes) +CONFIG_NCP_FS + 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 + <file:Documentation/filesystems/ncpfs.txt> in the kernel source and + the IPX-HOWTO from <http://www.tldp.org/docs.html#howto>. + + 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 <http://www.eats.com/linux_mac_win.html>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called ncpfs.o. Say N unless you are connected to a Novell + network. + +Packet signatures +CONFIG_NCPFS_PACKET_SIGNING + NCP allows packets to be signed for stronger security. If you want + security, say Y. Normal users can leave it off. To be able to use + packet signing you must use ncpfs > 2.0.12. + +Proprietary file locking +CONFIG_NCPFS_IOCTL_LOCKING + Allows locking of records on remote volumes. Say N unless you have + special applications which are able to utilize this locking scheme. + +Clear remove/delete inhibit when needed +CONFIG_NCPFS_STRONG + Allows manipulation of files flagged as Delete or Rename Inhibit. + To use this feature you must mount volumes with the ncpmount + parameter "-s" (ncpfs-2.0.12 and newer). Say Y unless you are not + mounting volumes with -f 444. + +Use NFS namespace if available +CONFIG_NCPFS_NFS_NS + Allows you to utilize NFS namespace on NetWare servers. It brings + you case sensitive filenames. Say Y. You can disable it at + mount-time with the `-N nfs' parameter of ncpmount. + +Use LONG (OS/2) namespace if available +CONFIG_NCPFS_OS2_NS + Allows you to utilize OS2/LONG namespace on NetWare servers. + Filenames in this namespace are limited to 255 characters, they are + case insensitive, and case in names is preserved. Say Y. You can + disable it at mount time with the -N os2 parameter of ncpmount. + +Lowercase DOS filenames on LONG namespace volume +CONFIG_NCPFS_SMALLDOS + If you say Y here, every filename on a NetWare server volume using + the OS2/LONG namespace and created under DOS or on a volume using + DOS namespace will be converted to lowercase characters. + Saying N here will give you these filenames in uppercase. + + This is only a cosmetic option since the OS2/LONG namespace is case + insensitive. The only major reason for this option is backward + compatibility when moving from DOS to OS2/LONG namespace support. + Long filenames (created by Win95) will not be affected. + + This option does not solve the problem that filenames appear + differently under Linux and under Windows, since Windows does an + additional conversions on the client side. You can achieve similar + effects by saying Y to "Allow using of Native Language Support" + below. + +Use Native Language Support +CONFIG_NCPFS_NLS + Allows you to use codepages and I/O charsets for file name + translation between the server file system and input/output. This + may be useful, if you want to access the server with other operating + systems, e.g. Windows 95. See also NLS for more Information. + + To select codepages and I/O charsets use ncpfs-2.2.0.13 or newer. + +Symbolic links and mode permission bits +CONFIG_NCPFS_EXTRAS + This enables the use of symbolic links and an execute permission + bit on NCPFS. The file server need not have long name space or NFS + name space loaded for these to work. + + To use the new attributes, it is recommended to use the flags + '-f 600 -d 755' on the ncpmount command line. + +Default NLS Option +CONFIG_NLS_DEFAULT + The default NLS used when mounting file system. Note, that this is + the NLS used by your console, not the NLS used by a specific file + system (if different) to store data (filenames) on a disk. + Currently, the valid values are: + big5, cp437, cp737, cp775, cp850, cp852, cp855, cp857, cp860, cp861, + cp862, cp863, cp864, cp865, cp866, cp869, cp874, cp932, cp936, + cp949, cp950, cp1250, cp1251, cp1255, euc-jp, euc-kr, gb2312, iso8859-1, + iso8859-2, iso8859-3, iso8859-4, iso8859-5, iso8859-6, iso8859-7, + iso8859-8, iso8859-9, iso8859-13, iso8859-14, iso8859-15, + koi8-r, koi8-ru, koi8-u, sjis, tis-620, utf8. + If you specify a wrong value, it will use the built-in NLS; + compatible with iso8859-1. + + If unsure, specify it as "iso8859-1". + +Codepage 437 (United States, Canada) +CONFIG_NLS_CODEPAGE_437 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored + in so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage that is used in + the United States and parts of Canada. This is recommended. + +Codepage 737 (Greek) +CONFIG_NLS_CODEPAGE_737 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored + in so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage that is used for + Greek. If unsure, say N. + +Codepage 775 (Baltic Rim) +CONFIG_NLS_CODEPAGE_775 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored + in so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage that is used + for the Baltic Rim Languages (Latvian and Lithuanian). If unsure, + say N. + +Codepage 850 (Europe) +CONFIG_NLS_CODEPAGE_850 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage that is used for + much of Europe -- United Kingdom, Germany, Spain, Italy, and [add + more countries here]. It has some characters useful to many European + languages that are not part of the US codepage 437. + + If unsure, say Y. + +Codepage 852 (Central/Eastern Europe) +CONFIG_NLS_CODEPAGE_852 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the Latin 2 codepage used by DOS + for much of Central and Eastern Europe. It has all the required + characters for these languages: Albanian, Croatian, Czech, English, + Finnish, Hungarian, Irish, German, Polish, Rumanian, Serbian (Latin + transcription), Slovak, Slovenian, and Serbian. + +Codepage 855 (Cyrillic) +CONFIG_NLS_CODEPAGE_855 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Cyrillic. + +Codepage 857 (Turkish) +CONFIG_NLS_CODEPAGE_857 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Turkish. + +Codepage 860 (Portuguese) +CONFIG_NLS_CODEPAGE_860 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Portuguese. + +Codepage 861 (Icelandic) +CONFIG_NLS_CODEPAGE_861 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Icelandic. + +Codepage 862 (Hebrew) +CONFIG_NLS_CODEPAGE_862 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Hebrew. + +Codepage 863 (Canadian French) +CONFIG_NLS_CODEPAGE_863 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Canadian + French. + +Codepage 864 (Arabic) +CONFIG_NLS_CODEPAGE_864 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Arabic. + +Codepage 865 (Norwegian, Danish) +CONFIG_NLS_CODEPAGE_865 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for the Nordic + European countries. + +Codepage 866 (Cyrillic/Russian) +CONFIG_NLS_CODEPAGE_866 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for + Cyrillic/Russian. + +Codepage 869 (Greek) +CONFIG_NLS_CODEPAGE_869 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Greek. + +Thai charset (CP874, TIS-620) +CONFIG_NLS_CODEPAGE_874 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Thai. + +Windows CP1251 (Bulgarian, Belarusian) +CONFIG_NLS_CODEPAGE_1251 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Russian and + Bulgarian and Belarusian. + +Japanese charsets (Shift-JIS, EUC-JP) +CONFIG_NLS_CODEPAGE_932 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Shift-JIS + or EUC-JP. To use EUC-JP, you can use 'euc-jp' as mount option or + NLS Default value during kernel configuration, instead of 'cp932'. + +Simplified Chinese charset (CP936, GB2312) +CONFIG_NLS_CODEPAGE_936 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Simplified + Chinese(GBK). + +Korean charset (CP949, EUC-KR) +CONFIG_NLS_CODEPAGE_949 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for UHC. + +Traditional Chinese charset (Big5) +CONFIG_NLS_CODEPAGE_950 + The Microsoft FAT file system family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Traditional + Chinese(Big5). + +Central European (Codepage 1250) +CONFIG_NLS_CODEPAGE_1250 + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CDROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Windows CP-1250 + character set, which works for most Latin-written Slavic and Central + European languages: Czech, German, Hungarian, Polish, Rumanian, Croatian, + Slovak, Slovene. + +NLS ISO 8859-1 (Latin 1; Western European Languages) +CONFIG_NLS_ISO8859_1 + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CD-ROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Latin 1 character + set, which covers most West European languages such as Albanian, + Catalan, Danish, Dutch, English, Faeroese, Finnish, French, German, + Galician, Irish, Icelandic, Italian, Norwegian, Portuguese, Spanish, + and Swedish. It is also the default for the US. If unsure, say Y. + +NLS ISO 8859-2 (Latin 2; Slavic/Central European Languages) +CONFIG_NLS_ISO8859_2 + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CD-ROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Latin 2 character + set, which works for most Latin-written Slavic and Central European + languages: Czech, German, Hungarian, Polish, Rumanian, Croatian, + Slovak, Slovene. + +NLS ISO 8859-3 (Latin 3; Esperanto, Galician, Maltese, Turkish) +CONFIG_NLS_ISO8859_3 + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CD-ROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Latin 3 character + set, which is popular with authors of Esperanto, Galician, Maltese, + and Turkish. + +NLS ISO 8859-4 (Latin 4; old Baltic charset) +CONFIG_NLS_ISO8859_4 + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CD-ROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Latin 4 character + set which introduces letters for Estonian, Latvian, and + Lithuanian. It is an incomplete predecessor of Latin 7. + +NLS ISO 8859-5 (Cyrillic) +CONFIG_NLS_ISO8859_5 + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CD-ROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for ISO8859-5, a Cyrillic + character set with which you can type Bulgarian, Belarusian, + Macedonian, Russian, Serbian, and Ukrainian. Note that the charset + KOI8-R is preferred in Russia. + +NLS ISO 8859-6 (Arabic) +CONFIG_NLS_ISO8859_6 + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CD-ROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for ISO8859-6, the Arabic + character set. + +NLS ISO 8859-7 (Modern Greek) +CONFIG_NLS_ISO8859_7 + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CD-ROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for ISO8859-7, the Modern + Greek character set. + +Hebrew charsets (ISO-8859-8, CP1255) +CONFIG_NLS_ISO8859_8 + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CD-ROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for ISO8859-8, the Hebrew + character set. + +NLS ISO 8859-9 (Latin 5; Turkish) +CONFIG_NLS_ISO8859_9 + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CD-ROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Latin 5 character + set, and it replaces the rarely needed Icelandic letters in Latin 1 + with the Turkish ones. Useful in Turkey. + +NLS ISO 8859-10 (Latin 6; Nordic) +CONFIG_NLS_ISO8859_10 + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CD-ROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Latin 6 character + set, which adds the last Inuit (Greenlandic) and Sami (Lappish) + letters that were missing in Latin 4 to cover the entire Nordic + area. + +NLS ISO 8859-13 (Latin 7; Baltic) +CONFIG_NLS_ISO8859_13 + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CD-ROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Latin 7 character + set, which supports modern Baltic languages including Latvian + and Lithuanian. + +NLS ISO 8859-14 (Latin 8; Celtic) +CONFIG_NLS_ISO8859_14 + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CD-ROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Latin 8 character + set, which adds the last accented vowels for Welsh (aka Cymraeg) + (and Manx Gaelic) that were missing in Latin 1. + <http://linux.speech.cymru.org/> has further information. + +NLS ISO 8859-15 (Latin 9; Western European languages with Euro) +CONFIG_NLS_ISO8859_15 + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CD-ROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Latin 9 character + set, which covers most West European languages such as Albanian, + Catalan, Danish, Dutch, English, Estonian, Faeroese, Finnish, + French, German, Galician, Irish, Icelandic, Italian, Norwegian, + Portuguese, Spanish, and Swedish. Latin 9 is an update to + Latin 1 (ISO 8859-1) that removes a handful of rarely used + characters and instead adds support for Estonian, corrects the + support for French and Finnish, and adds the new Euro character. + If unsure, say Y. + +NLS KOI8-R (Russian) +CONFIG_NLS_KOI8_R + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CD-ROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the preferred Russian + character set. + +NLS KOI8-U/RU (Ukrainian, Belarusian) +CONFIG_NLS_KOI8_U + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CD-ROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the preferred Ukrainian + (koi8-u) and Belarusian (koi8-ru) character sets. + +NLS UTF8 +CONFIG_NLS_UTF8 + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CD-ROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the UTF-8 encoding of + the Unicode/ISO9646 universal character set. + +Virtual terminal +CONFIG_VT + If you say Y here, you will get support for terminal devices with + display and keyboard devices. These are called "virtual" because you + can run several virtual terminals (also called virtual consoles) on + one physical terminal. This is rather useful, for example one + virtual terminal can collect system messages and warnings, another + one can be used for a text-mode user session, and a third could run + an X session, all in parallel. Switching between virtual terminals + is done with certain key combinations, usually Alt-<function key>. + + The setterm command ("man setterm") can be used to change the + properties (such as colors or beeping) of a virtual terminal. The + man page console_codes(4) ("man console_codes") contains the special + character sequences that can be used to change those properties + directly. The fonts used on virtual terminals can be changed with + the setfont ("man setfont") command and the key bindings are defined + with the loadkeys ("man loadkeys") command. + + You need at least one virtual terminal device in order to make use + of your keyboard and monitor. Therefore, only people configuring an + embedded system would want to say N here in order to save some + memory; the only way to log into such a system is then via a serial + or network connection. + + If unsure, say Y, or else you won't be able to do much with your new + shiny Linux system :-) + +Support for console on virtual terminal +CONFIG_VT_CONSOLE + The system console is the device which receives all kernel messages + and warnings and which allows logins in single user mode. If you + answer Y here, a virtual terminal (the device used to interact with + a physical terminal) can be used as system console. This is the most + common mode of operations, so you should say Y here unless you want + the kernel messages be output only to a serial port (in which case + you should say Y to "Console on serial port", below). + + If you do say Y here, by default the currently visible virtual + terminal (/dev/tty0) will be used as system console. You can change + that with a kernel command line option such as "console=tty3" which + would use the third virtual terminal as system console. (Try "man + bootparam" or see the documentation of your boot loader (lilo or + loadlin) about how to pass options to the kernel at boot time.) + + If unsure, say Y. + +STI console +CONFIG_STI_CONSOLE + The STI console is the builtin display/keyboard on HP-PARISC + machines. Say Y here to build support for it into your kernel. + The alternative is to use your primary serial port as a console. + +Use MDIO for PHY configuration +CONFIG_USE_MDIO + On some boards the hardware configuration of the ethernet PHY can be + used without any software interaction over the MDIO interface, so + all MII code can be omitted. Say N here if unsure or if you don't + need link status reports. + +860T FEC Ethernet +CONFIG_FEC_ENET + Enable Ethernet support via the Fast Ethernet Controller (FCC) on + the Motorola MPC8260. + +Ethernet on FCC1 +CONFIG_FCC1_ENET + Use MPC8260 fast Ethernet controller 1 to drive Ethernet (default). + +Ethernet on FCC2 +CONFIG_FCC2_ENET + Use MPC8260 fast Ethernet controller 2 to drive Ethernet. + +Ethernet on FCC3 +CONFIG_FCC3_ENET + Use MPC8260 fast Ethernet controller 3 to drive Ethernet. + +CPM SCC Ethernet +CONFIG_SCC_ENET + Enable Ethernet support via the Motorola MPC8xx serial + communications controller. + +# Choice: scc_ethernet +Ethernet on SCC1 +CONFIG_SCC1_ENET + Use MPC8xx serial communications controller 1 to drive Ethernet + (default). + +Ethernet on SCC2 +CONFIG_SCC2_ENET + Use MPC8xx serial communications controller 2 to drive Ethernet. + +Ethernet on SCC3 +CONFIG_SCC3_ENET + Use MPC8xx serial communications controller 3 to drive Ethernet. + +Use Big CPM Ethernet Buffers +CONFIG_ENET_BIG_BUFFERS + Allocate large buffers for MPC8xx Ethernet. Increases throughput + and decreases the likelihood of dropped packets, but costs memory. + +Apple Desktop Bus (ADB) support +CONFIG_ADB + Apple Desktop Bus (ADB) support is for support of devices which + are connected to an ADB port. ADB devices tend to have 4 pins. + If you have an Apple Macintosh prior to the iMac, or a + "Blue and White G3", you probably want to say Y here. Otherwise + say N. + +Support for CUDA based PowerMacs +CONFIG_ADB_CUDA + This provides support for CUDA based Power Macintosh systems. This + includes most OldWorld PowerMacs, the first generation iMacs, the + Blue&White G3 and the Yikes G4 (PCI Graphics). All later models + should use CONFIG_ADB_PMU instead. + + If unsure say Y. + +Support for PMU-based PowerMacs +CONFIG_ADB_PMU + This provides support for PMU based Power Macintosh systems. This + includes all PowerBooks and all AGP-based machines. + + If unsure say Y. + +Include MacIO ADB driver +CONFIG_ADB_MACIO + Say Y here to include direct support for the ADB controller in the + Hydra chip used on PowerPC Macintoshes of the CHRP type. (The Hydra + also includes a MESH II SCSI controller, DBDMA controller, VIA chip, + OpenPIC controller and two RS422/Geoports.) + +Support for ADB keyboard (old driver) +CONFIG_ADB_KEYBOARD + This option allows you to use an ADB keyboard attached to your + machine. Note that this disables any other (ie. PS/2) keyboard + support, even if your machine is physically capable of using both at + the same time. + + If you use an ADB keyboard (4 pin connector), say Y here. + If you use a PS/2 keyboard (6 pin connector), say N here. + +HIL keyboard support +CONFIG_HIL + The "Human Interface Loop" is a older, 8-channel USB-like controller + used in Hewlett Packard PA-RISC based machines. There are a few + cases where it is seen on PC/MAC architectures as well, usually also + manufactured by HP. This driver is based off MACH and BSD drivers, + and implements support for a keyboard attached to the HIL port. + Full support for the USB-like functions and non-keyboard channels of + the HIL is not provided for in this driver. There are vestiges of + mouse support in the driver, but it is probably not working. The + necessary hardware documentation to fully support the HIL controller + and interface it to the linux-input API is lacking. + + Enable this option if you intend to use a HIL keyboard. + +Include IOP (IIfx/Quadra 9x0) ADB driver +CONFIG_ADB_IOP + The I/O Processor (IOP) is an Apple custom IC designed to provide + intelligent support for I/O controllers. It is described at + <http://www.angelfire.com/ca2/dev68k/iopdesc.html> to enable direct + support for it, say 'Y' here. + +Mac II style Apple Desktop Bus support +CONFIG_ADB_MACII + Say Y here if want your kernel to support Macintosh systems that use + the Mac II style ADB. This includes the II, IIx, IIcx, SE/30, IIci, + Quadra 610, Quadra 650, Quadra 700, Quadra 800, Centris 610 and + Centris 650. + +Mac IIsi style Apple Desktop Bus support +CONFIG_ADB_MACIISI + Say Y here if want your kernel to support Macintosh systems that use + the Mac IIsi style ADB. This includes the IIsi, IIvi, IIvx, Classic + II, LC, LC II, LC III, Performa 460, and the Performa 600. + +Apple 68K PowerBook Power Management and Desktop Bus support +CONFIG_ADB_PMU68K + Say Y here if want your kernel to support the m68k based Powerbooks. + This includes the PowerBook 140, PowerBook 145, PowerBook 150, + PowerBook 160, PowerBook 165, PowerBook 165c, PowerBook 170, + PowerBook 180, PowerBook, 180c, PowerBook 190cs, PowerBook 520, + PowerBook Duo 210, PowerBook Duo 230, PowerBook Duo 250, + PowerBook Duo 270c, PowerBook Duo 280 and PowerBook Duo 280c. + +Macintosh IIfx/Quadra 900/Quadra 950 floppy support +CONFIG_BLK_DEV_SWIM_IOP + Say Y here to support the SWIM (Super Woz Integrated Machine) IOP + floppy controller on the Macintosh IIfx and Quadra 900/950. + +Macintosh NS8390 based Ethernet support +CONFIG_MAC8390 + If you want to include a driver to support Nubus or LC-PDS + Ethernet cards using an NS8390 chipset or its equivalent, say Y + and read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + +Macintosh CS89x0 based Ethernet support +CONFIG_MAC89x0 + Support for CS89x0 chipset based Ethernet cards. If you have a + Nubus or LC-PDS network (Ethernet) card of this type, say Y and + read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt> as well as + <file:Documentation/networking/net-modules.txt>. This module will + be called mac89x0.o. + +Macintosh onboard AMD 79C940 MACE based Ethernet support +CONFIG_MACMACE + Support for the onboard AMD 79C940 MACE Ethernet controller used in + the 660AV and 840AV Macintosh. If you have one of these Macintoshes + say Y and read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + +Macintosh SONIC based Ethernet support (onboard, NuBus, LC, CS) +CONFIG_MACSONIC + Support for NatSemi SONIC based Ethernet devices. This includes + the onboard Ethernet in many Quadras as well as some LC-PDS, + a few Nubus and all known Comm Slot Ethernet cards. If you have + one of these say Y and read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt> as well as + <file:Documentation/networking/net-modules.txt>. This module will + be called macsonic.o. + +Macintosh NCR5380 SCSI support +CONFIG_MAC_SCSI + This is the NCR 5380 SCSI controller included on most of the 68030 + based Macintoshes. If you have one of these say Y and read the + SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + +Macintosh NCR53c9[46] SCSI support +CONFIG_SCSI_MAC_ESP + This is the NCR 53c9x SCSI controller found on most of the 68040 + based Macintoshes. If you have one of these say Y and read the + SCSI-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called mac_esp.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + +Standard/generic (8250/16550 and compatible UARTs) serial support +CONFIG_SERIAL + This selects whether you want to include the driver for the standard + serial ports. The standard answer is Y. People who might say N + here are those that are setting up dedicated Ethernet WWW/FTP + servers, or users that have one of the various bus mice instead of a + serial mouse and don't intend to use their machine's standard serial + port for anything. (Note that the Cyclades and Stallion multi + serial port drivers do not need this driver built in for them to + work.) + + If you want to compile this driver as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + serial.o. + [WARNING: Do not compile this driver as a module if you are using + non-standard serial ports, since the configuration information will + be lost when the driver is unloaded. This limitation may be lifted + in the future.] + + BTW1: If you have a mouseman serial mouse which is not recognized by + the X window system, try running gpm first. + + BTW2: If you intend to use a software modem (also called Winmodem) + under Linux, forget it. These modems are crippled and require + proprietary drivers which are only available under Windows. + + Most people will say Y or M here, so that they can use serial mice, + modems and similar devices connecting to the standard serial ports. + +Support for console on serial port +CONFIG_SERIAL_CONSOLE + If you say Y here, it will be possible to use a serial port as the + system console (the system console is the device which receives all + kernel messages and warnings and which allows logins in single user + mode). This could be useful if some terminal or printer is connected + to that serial port. + + Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttyS1". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time.) + + If you don't have a VGA card installed and you say Y here, the + kernel will automatically use the first serial line, /dev/ttyS0, as + system console. + + If unsure, say N. + +Support for PowerMac serial ports +CONFIG_MAC_SERIAL + If you have Macintosh style serial ports (8 pin mini-DIN), say Y + here. If you also have regular serial ports and enable the driver + for them, you can't currently use the serial console feature. + +Comtrol Rocketport support +CONFIG_ROCKETPORT + This is a driver for the Comtrol Rocketport cards which provide + multiple serial ports. You would need something like this to connect + more than two modems to your Linux box, for instance in order to + become a dial-in server. + + If you want to compile this driver as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + rocket.o. + +Digiboard Intelligent async support +CONFIG_DIGIEPCA + This is a driver for Digi International's Xx, Xeve, and Xem series + of cards which provide multiple serial ports. You would need + something like this to connect more than two modems to your Linux + box, for instance in order to become a dial-in server. This driver + supports the original PC (ISA) boards as well as PCI, and EISA. If + you have a card like this, say Y here and read the file + <file:Documentation/digiepca.txt>. + + NOTE: There is another, separate driver for the Digiboard PC boards: + "Digiboard PC/Xx Support" below. You should (and can) only select + one of the two drivers. + + If you want to compile this driver as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called epca.o. + +Digiboard PC/Xx Support +CONFIG_DIGI + This is a driver for the Digiboard PC/Xe, PC/Xi, and PC/Xeve cards + that give you many serial ports. You would need something like this + to connect more than two modems to your Linux box, for instance in + order to become a dial-in server. If you have a card like that, say + Y here and read the file <file:Documentation/digiboard.txt>. + + If you want to compile this driver as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called pcxx.o. + +SDL RISCom/8 card support +CONFIG_RISCOM8 + This is a driver for the SDL Communications RISCom/8 multiport card, + which gives you many serial ports. You would need something like + this to connect more than two modems to your Linux box, for instance + in order to become a dial-in server. If you have a card like that, + say Y here and read the file <file:Documentation/riscom8.txt>. + + Also it's possible to say M here and compile this driver as kernel + loadable module; the module will be called riscom8.o. + +Computone IntelliPort Plus serial support +CONFIG_COMPUTONE + This driver supports the entire family of Intelliport II/Plus + controllers with the exception of the MicroChannel controllers and + products previous to the Intelliport II. These are multiport cards, + which give you many serial ports. You would need something like this + to connect more than two modems to your Linux box, for instance in + order to become a dial-in server. If you have a card like that, say + Y here and read <file:Documentation/computone.txt>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. You will get + two modules called ip2.o and ip2main.o. + +Specialix IO8+ card support +CONFIG_SPECIALIX + This is a driver for the Specialix IO8+ multiport card (both the + ISA and the PCI version) which gives you many serial ports. You + would need something like this to connect more than two modems to + your Linux box, for instance in order to become a dial-in server. + + If you have a card like that, say Y here and read the file + <file:Documentation/specialix.txt>. Also it's possible to say M here + and compile this driver as kernel loadable module which will be + called specialix.o. + +Specialix DTR/RTS pin is RTS +CONFIG_SPECIALIX_RTSCTS + The Specialix IO8+ card can only support either RTS or DTR. If you + say N here, the driver will use the pin as "DTR" when the tty is in + software handshake mode. If you say Y here or hardware handshake is + on, it will always be RTS. Read the file + <file:Documentation/specialix.txt> for more information. + +Specialix RIO system support +CONFIG_RIO + This is a driver for the Specialix RIO, a smart serial card which + drives an outboard box that can support up to 128 ports. Product + information is at <http://www.sphinxcst.co.uk/perle/multi.htm>. + There are both ISA and PCI versions. + +Support really old RIO/PCI cards +CONFIG_RIO_OLDPCI + Older RIO PCI cards need some initialization-time configuration to + determine the IRQ and some control addresses. If you have a RIO and + this doesn't seem to work, try setting this to Y. + +Cyclades async mux support +CONFIG_CYCLADES + This is a driver for a card that gives you many serial ports. You + would need something like this to connect more than two modems to + your Linux box, for instance in order to become a dial-in server. + For information about the Cyclades-Z card, read + <file:drivers/char/README.cycladesZ>. + + As of 1.3.9x kernels, this driver's minor numbers start at 0 instead + of 32. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called cyclades.o. + + If you haven't heard about it, it's safe to say N. + +Cyclades-Z interrupt mode operation +CONFIG_CYZ_INTR + The Cyclades-Z family of multiport cards allows 2 (two) driver op + modes: polling and interrupt. In polling mode, the driver will check + the status of the Cyclades-Z ports every certain amount of time + (which is called polling cycle and is configurable). In interrupt + mode, it will use an interrupt line (IRQ) in order to check the + status of the Cyclades-Z ports. The default op mode is polling. If + unsure, say N. + +Stallion multiport serial support +CONFIG_STALDRV + Stallion cards give you many serial ports. You would need something + like this to connect more than two modems to your Linux box, for + instance in order to become a dial-in server. If you say Y here, + you will be asked for your specific card model in the next + questions. Make sure to read <file:Documentation/stallion.txt> in + this case. If you have never heard about all this, it's safe to + say N. + +Stallion EasyIO or EC8/32 support +CONFIG_STALLION + If you have an EasyIO or EasyConnection 8/32 multiport Stallion + card, then this is for you; say Y. Make sure to read + <file:Documentation/stallion.txt>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called stallion.o. + +Stallion EC8/64, ONboard, Brumby support +CONFIG_ISTALLION + If you have an EasyConnection 8/64, ONboard, Brumby or Stallion + serial multiport card, say Y here. Make sure to read + <file:Documentation/stallion.txt>. + + To compile it as a module ( = code which can be inserted in and + removed from the running kernel whenever you want), say M here and + read <file:Documentation/modules.txt>. The module will be called + istallion.o. + +Microgate SyncLink adapter support +CONFIG_SYNCLINK + Provides support for the SyncLink ISA and PCI multiprotocol serial + adapters. These adapters support asynchronous and HDLC bit + synchronous communication up to 10Mbps (PCI adapter). + + This driver can only be built as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called synclink.o. If you want to do that, say M + here. + +CONFIG_SYNCLINKMP + Enable support for the SyncLink Multiport (2 or 4 ports) + serial adapter, running asynchronous and HDLC communications up + to 2.048Mbps. Each ports is independently selectable for + RS-232, V.35, RS-449, RS-530, and X.21 + + This driver may be built as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called synclinkmp.o. If you want to do that, say M + here. + +Synchronous HDLC line discipline support +CONFIG_N_HDLC + Allows synchronous HDLC communications with tty device drivers that + support synchronous HDLC such as the Microgate SyncLink adapter. + + This driver can only be built as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called n_hdlc.o. If you want to do that, say M + here. + +Specialix SX (and SI) card support +CONFIG_SX + This is a driver for the SX and SI multiport serial cards. + Please read the file <file:Documentation/sx.txt> for details. + + This driver can only be built as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called sx.o. If you want to do that, say M here. + +Hayes ESP serial port support +CONFIG_ESPSERIAL + This is a driver which supports Hayes ESP serial ports. Both single + port cards and multiport cards are supported. Make sure to read + <file:Documentation/hayes-esp.txt>. + + To compile this driver as a module ( = code which can be inserted in + and removed from the running kernel whenever you want), say M here + and read <file:Documentation/modules.txt>. The module will be + called esp.o. If unsure, say N. + +Moxa Intellio support +CONFIG_MOXA_INTELLIO + Say Y here if you have a Moxa Intellio multiport serial card. + + This driver can also be built as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called moxa.o. If you want to do that, say M + here. + +Moxa SmartIO support +CONFIG_MOXA_SMARTIO + Say Y here if you have a Moxa SmartIO multiport serial card. + + This driver can also be built as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called mxser.o. If you want to do that, say M + here. + +Multi-Tech multiport card support +CONFIG_ISI + This is a driver for the Multi-Tech cards which provide several + serial ports. The driver is experimental and can currently only be + built as a module ( = code which can be inserted in and removed from + the running kernel whenever you want). Please read + <file:Documentation/modules.txt>. The module will be called + isicom.o. + +Unix98 PTY support +CONFIG_UNIX98_PTYS + A pseudo terminal (PTY) is a software device consisting of two + halves: a master and a slave. The slave device behaves identical to + a physical terminal; the master device is used by a process to + read data from and write data to the slave, thereby emulating a + terminal. Typical programs for the master side are telnet servers + and xterms. + + Linux has traditionally used the BSD-like names /dev/ptyxx for + masters and /dev/ttyxx for slaves of pseudo terminals. This scheme + has a number of problems. The GNU C library glibc 2.1 and later, + however, supports the Unix98 naming standard: in order to acquire a + pseudo terminal, a process opens /dev/ptmx; the number of the pseudo + terminal is then made available to the process and the pseudo + terminal slave can be accessed as /dev/pts/<number>. What was + traditionally /dev/ttyp2 will then be /dev/pts/2, for example. + + The entries in /dev/pts/ are created on the fly by a virtual + file system; therefore, if you say Y here you should say Y to + "/dev/pts file system for Unix98 PTYs" as well. + + If you want to say Y here, you need to have the C library glibc 2.1 + or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*"). + Read the instructions in <file:Documentation/Changes> pertaining to + pseudo terminals. It's safe to say N. + +Maximum number of Unix98 PTYs in use (0-2048) +CONFIG_UNIX98_PTY_COUNT + The maximum number of Unix98 PTYs that can be used at any one time. + The default is 256, and should be enough for desktop systems. Server + machines which support incoming telnet/rlogin/ssh connections and/or + serve several X terminals may want to increase this: every incoming + connection and every xterm uses up one PTY. + + When not in use, each additional set of 256 PTYs occupy + approximately 8 KB of kernel memory on 32-bit architectures. + +Parallel printer support +CONFIG_PRINTER + If you intend to attach a printer to the parallel port of your Linux + box (as opposed to using a serial printer; if the connector at the + printer has 9 or 25 holes ["female"], then it's serial), say Y. + Also read the Printing-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + It is possible to share one parallel port among several devices + (e.g. printer and ZIP drive) and it is safe to compile the + corresponding drivers into the kernel. If you want to compile this + driver as a module however ( = code which can be inserted in and + removed from the running kernel whenever you want), say M here and + read <file:Documentation/modules.txt> and + <file:Documentation/parport.txt>. The module will be called lp.o. + + If you have several parallel ports, you can specify which ports to + use with the "lp" kernel command line option. (Try "man bootparam" + or see the documentation of your boot loader (lilo or loadlin) about + how to pass options to the kernel at boot time.) The syntax of the + "lp" command line option can be found in <file:drivers/char/lp.c>. + + If you have more than 8 printers, you need to increase the LP_NO + macro in lp.c and the PARPORT_MAX macro in parport.h. + +Support for console on line printer +CONFIG_LP_CONSOLE + If you want kernel messages to be printed out as they occur, you + can have a console on the printer. This option adds support for + doing that; to actually get it to happen you need to pass the + option "console=lp0" to the kernel at boot time. + + If the printer is out of paper (or off, or unplugged, or too + busy..) the kernel will stall until the printer is ready again. + By defining CONSOLE_LP_STRICT to 0 (at your own risk) you + can make the kernel continue when this happens, + but it'll lose the kernel messages. + + If unsure, say N. + +Support for user-space parallel port device drivers +CONFIG_PPDEV + Saying Y to this adds support for /dev/parport device nodes. This + is needed for programs that want portable access to the parallel + port, for instance deviceid (which displays Plug-and-Play device + IDs). + + This is the parallel port equivalent of SCSI generic support (sg). + It is safe to say N to this -- it is not needed for normal printing + or parallel port CD-ROM/disk support. + + This support is also available as a module. If you want to compile + it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + ppdev.o. + + If unsure, say N. + +Cobalt Networks support +CONFIG_COBALT + Support for Cobalt Networks x86-based servers. + +Gen III (3000 series) system support +CONFIG_COBALT_GEN_III + This option enables support for the 3000 series of Cobalt Networks + systems. This includes the RaQ 3, RaQ 4, and Qube 3 product lines. + + This platform uses an AMD K6-2 processor, an ALI M1541/1533 chipset, + an optional NCR 53c875 SCSI controller, and two Intel 82559ER or + National Semiconductor DP83815 NICs. + + Getting this option wrong will likely result in a kernel that does + not boot. Selecting support for more than 1 system series will add + bloat to your kernel, but will not cause anything bad to happen. + + If you have a Cobalt Networks System, but aren't sure what kind, + say Y here. + +Gen V (5000 series) system support +CONFIG_COBALT_GEN_V + This option enables support for the 5000 series of Cobalt Networks + systems. This includes the RaQ XTR product line. + + This platform uses Intel Pentium III Coppermine FCPGA CPUs, the + ServerWorks LE chipset (with registered ECC DIMMs only!), two + HighPoint HPT370 IDE controllers, and two National Semiconductor + DP83815 NICs. + + Getting this option wrong will likely result in a kernel that does + not boot. Selecting support for more than 1 system series will add + bloat to your kernel, but will not cause anything bad to happen. + + If you have a Cobalt Networks System, but aren't sure what kind, + say Y here. + +Create legacy /proc files +CONFIG_COBALT_OLDPROC + This option forces some Cobalt Networks drivers to support legacy + files in /proc. Older versions of these drivers exported files + directly in /proc, as opposed to the newer /proc/cobalt. If you say + N to this option, the old filenames will no longer be exported. + Regardless of your selection here, files in /proc/cobalt will be + exported. Of course, you have to include support for /proc fs, too. + + It is safe to say Y here. + +Front panel LCD support +CONFIG_COBALT_LCD + This enables support for the Cobalt Networks front panel. This is + for the LCD panel and buttons. The primary method for connection is + via the parallel port (IO base 0x370), but newer systems use an + I2C bus. + + If you have a Cobalt Networks system, you should say Y here. + +Software controlled LED support +CONFIG_COBALT_LED + This enables support for the software-controlled LEDs on Cobalt + Networks systems. This includes the fault light and front panel + LEDs on the RaQ XTR, the lightbar on the Qube 3, and others. + + If you have a Cobalt Networks system, you should say Y here. + +Silicon serial number support +CONFIG_COBALT_SERNUM + This enables support for the on-board serial number on Cobalt + Networks systems. This is a universally-unique 64-bit serial + number. Some systems use a Dallas DS2401 chip, others have an I2C + based EEPROM. + + If you select Y here, the files /proc/cobalt/hostid and + /proc/cobalt/serialnumber will be created. The hostid file contains + a 32 bit integer generated from the serial number, in binary form. + The serialnumber file contains the hexadecimal representation of the + serial number, in ASCII. + + If you have a Cobalt Networks system, you should say Y here. + +Chipset watchdog timer support +CONFIG_COBALT_WDT + This enables support for the watchdog timer built into Cobalt + chipsets. The timer wakes up periodically, to make find out if + system has hung, or disabled interrupts too long. The result of + detecting a hang is a hard reboot. + + If you have a Cobalt Networks system, you should say Y here. + +Thermal sensor support +CONFIG_COBALT_THERMAL + This enables support for the thermal sensor(s) built into Cobalt + Networks systems. This driver exports /proc/cobalt/thermal_sensors. + + If you have a Cobalt Networks system, you should say Y here. + +Fan tachometer support +CONFIG_COBALT_FANS + This enables support for the fan tachometers built into some Cobalt + Networks systems. This driver exports /proc/cobalt/faninfo. Some + Cobalt software depends on this feature, and enabling it does not + cause any risks. + + If you have a Cobalt Networks system, you should say Y here, unless + you are absolutely sure. + +Disk drive ruler support +CONFIG_COBALT_RULER + This enables support for the cobalt hard drive ruler, found on some + Cobalt systems, including the RaQ XTR. This is the device that + enables swapping of drives. It is not needed for basic disk + operation. Enabling this on a system with no ruler will have no + adverse effects. + + If you have a Cobalt Networks system, you should say Y here, + unless you are absolutely sure. + +IT8172G Sound +CONFIG_SOUND_IT8172 + Say Y here to support the on-board sound generator on the Integrated + Technology Express, Inc. ITE8172 SBC. Vendor page at + <http://www.ite.com.tw/ia/brief_it8172bsp.htm>; picture of the + board at <http://www.mvista.com/allies/semiconductor/ite.html>. + +I2C support +CONFIG_I2C + I2C (pronounce: I-square-C) is a slow serial bus protocol used in + many micro controller applications and developed by Philips. SMBus, + or System Management Bus is a subset of the I2C protocol. More + information is contained in the directory <file:Documentation/i2c/>, + especially in the file called "summary" there. + + Both I2C and SMBus are supported here. You will need this for + hardware sensors support, and also for Video For Linux support. + Specifically, if you want to use a BT848 based frame grabber/overlay + boards under Linux, say Y here and also to "I2C bit-banging + interfaces", below. + + If you want I2C support, you should say Y here and also to the + specific driver for your bus adapter(s) below. If you say Y to + "/proc file system" below, you will then get a /proc interface which + is documented in <file:Documentation/i2c/proc-interface>. + + This I2C support is also available as a module. If you want to + compile it as a module, say M here and read + <file:Documentation/modules.txt>. + The module will be called i2c-core.o. + +UltraSPARC-III bootbus i2c controller driver +CONFIG_BBC_I2C + The BBC devices on the UltraSPARC III have two I2C controllers. The + first I2C controller connects mainly to configuration PROMs (NVRAM, + CPU configuration, DIMM types, etc.). The second I2C controller + connects to environmental control devices such as fans and + temperature sensors. The second controller also connects to the + smartcard reader, if present. Say Y to enable support for these. + +I2C bit-banging interfaces +CONFIG_I2C_ALGOBIT + This allows you to use a range of I2C adapters called bit-banging + adapters. Say Y if you own an I2C adapter belonging to this class + and then say Y to the specific driver for you adapter below. + + This support is also available as a module. If you want to compile + it as a module, say M here and read + <file:Documentation/modules.txt>. + The module will be called i2c-algo-bit.o. + +Philips style parallel port adapter +CONFIG_I2C_PHILIPSPAR + This supports parallel-port I2C adapters made by Philips. Say Y if + you own such an adapter. + + This driver is also available as a module. If you want to compile + it as a module, say M here and read + <file:Documentation/modules.txt>. + The module will be called i2c-philips-par.o. + + Note that if you want support for different parallel port devices, + life will be much easier if you compile them all as modules. + +ELV adapter +CONFIG_I2C_ELV + This supports parallel-port I2C adapters called ELV. Say Y if you + own such an adapter. + + This driver is also available as a module. If you want to compile + it as a module, say M here and read + <file:Documentation/modules.txt>. + The module will be called i2c-elv.o. + +Velleman K9000 adapter +CONFIG_I2C_VELLEMAN + This supports the Velleman K9000 parallel-port I2C adapter. Say Y + if you own such an adapter. + + This driver is also available as a module. If you want to compile + it as a module, say M here and read + <file:Documentation/modules.txt>. + The module will be called i2c-velleman.o. + +I2C PCF 8584 interfaces +CONFIG_I2C_ALGOPCF + This allows you to use a range of I2C adapters called PCF adapters. + Say Y if you own an I2C adapter belonging to this class and then say + Y to the specific driver for you adapter below. + + This support is also available as a module. If you want to compile + it as a module, say M here and read + <file:Documentation/modules.txt>. + The module will be called i2c-algo-pcf.o. + +Elektor ISA card +CONFIG_I2C_ELEKTOR + This supports the PCF8584 ISA bus I2C adapter. Say Y if you own + such an adapter. + + This driver is also available as a module. If you want to compile + it as a module, say M here and read + <file:Documentation/modules.txt>. + The module will be called i2c-elektor.o. + +ITE I2C Algorithm +CONFIG_ITE_I2C_ALGO + This supports the use the ITE8172 I2C interface found on some MIPS + systems. Say Y if you have one of these. You should also say Y for + the ITE I2C peripheral driver support below. + + This support is also available as a module. If you want to compile + it as a modules, say M here and read + <file:Documentation/modules.txt>. + The module will be called i2c-algo-ite.o. + +ITE I2C Adapter +CONFIG_ITE_I2C_ADAP + This supports the ITE8172 I2C peripheral found on some MIPS + systems. Say Y if you have one of these. You should also say Y for + the ITE I2C driver algorithm support above. + + This support is also available as a module. If you want to compile + it as a module, say M here and read + <file:Documentation/modules.txt>. + The module will be called i2c-adap-ite.o. + +I2C device interface +CONFIG_I2C_CHARDEV + Say Y here to use i2c-* device files, usually found in the /dev + directory on your system. They make it possible to have user-space + programs use the I2C bus. Information on how to do this is + contained in the file <file:Documentation/i2c/dev-interface>. + + This code is also available as a module. If you want to compile + it as a module, say M here and read + <file:Documentation/modules.txt>. + The module will be called i2c-dev.o. + +I2C /proc interface (required for hardware sensors) +CONFIG_I2C_PROC + This provides support for i2c device entries in the /proc filesystem. + The entries will be found in /proc/sys/dev/sensors. + + This code is also available as a module. If you want to compile + it as a module, say M here and read <file:Documentation/modules.txt>. + The module will be called i2c-proc.o. + +Bus Mouse Support +CONFIG_BUSMOUSE + Say Y here if your machine has a bus mouse as opposed to a serial + mouse. Most people have a regular serial MouseSystem or + Microsoft mouse (made by Logitech) that plugs into a COM port + (rectangular with 9 or 25 pins). These people say N here. + + If you have a laptop, you either have to check the documentation or + experiment a bit to find out whether the trackball is a serial mouse + or not; it's best to say Y here for you. + + This is the generic bus mouse driver code. If you have a bus mouse, + you will have to say Y here and also to the specific driver for your + mouse below. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called busmouse.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +Mouse Support (not serial and bus mice) +CONFIG_MOUSE + This is for machines with a mouse which is neither a serial nor a + bus mouse. Examples are PS/2 mice (such as the track balls on some + laptops) and some digitizer pads. Most people have a regular serial + MouseSystem or Microsoft mouse (made by Logitech) that plugs into a + COM port (rectangular with 9 or 25 pins). These people say N here. + If you have something else, read the Busmouse-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. This HOWTO contains + information about all non-serial mice, not just bus mice. + + If you have a laptop, you either have to check the documentation or + experiment a bit to find out whether the trackball is a serial mouse + or not; it's best to say Y here for you. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about non-serial mice. If unsure, say Y. + +Logitech busmouse support +CONFIG_LOGIBUSMOUSE + Logitech mouse connected to a proprietary interface card. It's + generally a round connector with 9 pins. Note that the newer mice + made by Logitech don't use the Logitech protocol anymore; for those, + you don't need this option. You want to read the Busmouse-HOWTO, + available from <http://www.tldp.org/docs.html#howto>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called busmouse.o. If you are unsure, say N and read the + HOWTO nevertheless: it will tell you what you have. + +PS/2 mouse (aka "auxiliary device") support +CONFIG_PSMOUSE + The PS/2 mouse connects to a special mouse port that looks much like + the keyboard port (small circular connector with 6 pins). This way, + the mouse does not use any serial ports. This port can also be used + for other input devices like light pens, tablets, keypads. Compaq, + AST and IBM all use this as their mouse port on currently shipping + machines. The trackballs of some laptops are PS/2 mice also. In + particular, the C&T 82C710 mouse on TI Travelmates is a PS/2 mouse. + + Although PS/2 mice are not technically bus mice, they are explained + in detail in the Busmouse-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + When using a PS/2 mouse, you can get problems if you want to use the + mouse both on the Linux console and under X. Using the "-R" option + of the Linux mouse managing program gpm (available from + <ftp://gnu.systemy.it/pub/gpm/>) solves this problem, or you can get + the "mconv2" utility from <ftp://ibiblio.org/pub/Linux/system/mouse/>. + +C&T 82C710 mouse port support (as on TI Travelmate) +CONFIG_82C710_MOUSE + This is a certain kind of PS/2 mouse used on the TI Travelmate. If + you are unsure, try first to say N here and come back if the mouse + doesn't work. Read the Busmouse-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + +PC110 digitizer pad support +CONFIG_PC110_PAD + This drives the digitizer pad on the IBM PC110 palmtop. It can turn + the digitizer pad into a PS/2 mouse emulation with tap gestures or + into an absolute pad. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called pc110pad.o. + +Microsoft busmouse support +CONFIG_MS_BUSMOUSE + These animals (also called Inport mice) are connected to an + expansion board using a round connector with 9 pins. If this is what + you have, say Y and read the Busmouse-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + If you are unsure, say N and read the HOWTO nevertheless: it will + tell you what you have. Also be aware that several vendors talk + about 'Microsoft busmouse' and actually mean PS/2 busmouse -- so + count the pins on the connector. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called msbusmouse.o. + +Apple Desktop Bus mouse support +CONFIG_ADBMOUSE + Say Y here if you have this type of bus mouse (4 pin connector) as + is common on Macintoshes. You may want to read the Busmouse-HOWTO, + available from <http://www.tldp.org/docs.html#howto>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called adbmouse.o. + +ATIXL busmouse support +CONFIG_ATIXL_BUSMOUSE + This is a rare type of busmouse that is connected to the back of an + ATI video card. Say Y if you have one of those. Note however that + most mice by ATI are actually Microsoft busmice; you should say Y to + "Microsoft busmouse support" above if you have one of those. Read + the Busmouse-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called atixlmouse.o. + + If you are unsure, say N and read the HOWTO nevertheless: it will + tell you what you have. + +QIC-02 tape support +CONFIG_QIC02_TAPE + If you have a non-SCSI tape drive like that, say Y. Or, if you want + to compile this driver as a module ( = code which can be inserted in + and removed from the running kernel whenever you want), say M here + and read <file:Documentation/modules.txt>. The module will be called + tpqic02.o. + +iSeries Virtual Tape Support +CONFIG_VIOTAPE + If you are running Linux on an iSeries system and you want Linux + to read and/or write a tape drive owned by OS/400, say Y here. + +Do you want runtime configuration for QIC-02 +CONFIG_QIC02_DYNCONF + You can either configure this driver once and for all by editing a + header file (<file:include/linux/tpqic02.h>), in which case you + should say N, or you can fetch a program via anonymous FTP which is + able to configure this driver during runtime. The program to do + this is called 'qic02conf' and it is part of the + tpqic02-support-X.Y.tar.gz support package. + + If you want to use the qic02conf program, say Y. + +Floppy tape drive (QIC-80/40/3010/3020/TR-1/TR-2/TR-3) support +CONFIG_FTAPE + If you have a tape drive that is connected to your floppy + controller, say Y here. + + Some tape drives (like the Seagate "Tape Store 3200" or the Iomega + "Ditto 3200" or the Exabyte "Eagle TR-3") come with a "high speed" + controller of their own. These drives (and their companion + controllers) are also supported if you say Y here. + + If you have a special controller (such as the CMS FC-10, FC-20, + Mountain Mach-II, or any controller that is based on the Intel 82078 + FDC like the high speed controllers by Seagate and Exabyte and + Iomega's "Ditto Dash") you must configure it by selecting the + appropriate entries from the "Floppy tape controllers" sub-menu + below and possibly modify the default values for the IRQ and DMA + channel and the IO base in ftape's configuration menu. + + If you want to use your floppy tape drive on a PCI-bus based system, + please read the file <file:drivers/char/ftape/README.PCI>. + + The ftape kernel driver is also available as a runtime loadable + module ( = code which can be inserted in and removed from the + running kernel whenever you want). If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. The + module will be called ftape.o. + + Note that the Ftape-HOWTO is out of date (sorry) and documents the + older version 2.08 of this software but still contains useful + information. There is a web page with more recent documentation at + <http://www.instmath.rwth-aachen.de/~heine/ftape/>. This page + always contains the latest release of the ftape driver and useful + information (backup software, ftape related patches and + documentation, FAQ). Note that the file system interface has + changed quite a bit compared to previous versions of ftape. Please + read <file:Documentation/ftape.txt>. + +VFS interface for ftape +CONFIG_ZFTAPE + Normally, you want to say Y or M. DON'T say N here or you + WON'T BE ABLE TO USE YOUR FLOPPY TAPE DRIVE. + + The ftape module itself no longer contains the routines necessary + to interface with the kernel VFS layer (i.e. to actually write data + to and read data from the tape drive). Instead the file system + interface (i.e. the hardware independent part of the driver) has + been moved to a separate module. + + If you say M zftape will be compiled as a runtime loadable + module ( = code which can be inserted in and removed from the + running kernel whenever you want). In this case you should read + <file:Documentation/modules.txt>. The module will be called + zftape.o. + + Regardless of whether you say Y or M here, an additional runtime + loadable module called `zft-compressor.o' which contains code to + support user transparent on-the-fly compression based on Ross + William's lzrw3 algorithm will be produced. If you have enabled the + kernel module loader (i.e. have said Y to "Kernel module loader + support", above) then `zft-compressor.o' will be loaded + automatically by zftape when needed. + + Despite its name, zftape does NOT use compression by default. The + file <file:Documentation/ftape.txt> contains a short description of + the most important changes in the file system interface compared to + previous versions of ftape. The ftape home page + <http://www.instmath.rwth-aachen.de/~heine/ftape/> contains + further information. + + IMPORTANT NOTE: zftape can read archives created by previous + versions of ftape and provide file mark support (i.e. fast skipping + between tape archives) but previous version of ftape will lack file + mark support when reading archives produced by zftape. + +Default block size for zftape +CONFIG_ZFT_DFLT_BLK_SZ + If unsure leave this at its default value, i.e. 10240. Note that + you specify only the default block size here. The block size can be + changed at run time using the MTSETBLK tape operation with the + MTIOCTOP ioctl (i.e. with "mt -f /dev/qft0 setblk #BLKSZ" from the + shell command line). + + The probably most striking difference between zftape and previous + versions of ftape is the fact that all data must be written or read + in multiples of a fixed block size. The block size defaults to + 10240 which is what GNU tar uses. The values for the block size + should be either 1 or multiples of 1024 up to a maximum value of + 63488 (i.e. 62 K). If you specify `1' then zftape's builtin + compression will be disabled. + + Reasonable values are `10240' (GNU tar's default block size), + `5120' (afio's default block size), `32768' (default block size some + backup programs assume for SCSI tape drives) or `1' (no restriction + on block size, but disables builtin compression). + +Number of DMA buffers +CONFIG_FT_NR_BUFFERS + Please leave this at `3' unless you REALLY know what you are doing. + It is not necessary to change this value. Values below 3 make the + proper use of ftape impossible, values greater than 3 are a waste of + memory. You can change the amount of DMA memory used by ftape at + runtime with "mt -f /dev/qft0 setdrvbuffer #NUMBUFFERS". Each buffer + wastes 32 KB of memory. Please note that this memory cannot be + swapped out. + +Enable procfs status report (+2kb) +CONFIG_FT_PROC_FS + Optional. Saying Y will result in creation of a directory + `/proc/ftape' under the /proc file system. The files can be viewed + with your favorite pager (i.e. use "more /proc/ftape/history" or + "less /proc/ftape/history" or simply "cat /proc/ftape/history"). The + file will contain some status information about the inserted + cartridge, the kernel driver, your tape drive, the floppy disk + controller and the error history for the most recent use of the + kernel driver. Saying Y will enlarge the size of the ftape driver + by approximately 2 KB. + + WARNING: When compiling ftape as a module (i.e. saying M to "Floppy + tape drive") it is dangerous to use ftape's /proc file system + interface. Accessing `/proc/ftape' while the module is unloaded will + result in a kernel Oops. This cannot be fixed from inside ftape. + +# Choice: ftdebug +Controlling the amount of debugging output of ftape +CONFIG_FT_NORMAL_DEBUG + This option controls the amount of debugging output the ftape driver + is ABLE to produce; it does not increase or diminish the debugging + level itself. If unsure, leave this at its default setting, + i.e. choose "Normal". + + Ftape can print lots of debugging messages to the system console + resp. kernel log files. Reducing the amount of possible debugging + output reduces the size of the kernel module by some KB, so it might + be a good idea to use "None" for emergency boot floppies. + + If you want to save memory then the following strategy is + recommended: leave this option at its default setting "Normal" until + you know that the driver works as expected, afterwards reconfigure + the kernel, this time specifying "Reduced" or "None" and recompile + and install the kernel as usual. Note that choosing "Excessive" + debugging output does not increase the amount of debugging output + printed to the console but only makes it possible to produce + "Excessive" debugging output. + + Please read <file:Documentation/ftape.txt> for a short description + how to control the amount of debugging output. + +Excessive +CONFIG_FT_FULL_DEBUG + Extremely verbose output for driver debugging purposes. + +Reduced +CONFIG_FT_NO_TRACE + Reduced tape driver debugging output. + +None +CONFIG_FT_NO_TRACE_AT_ALL + Suppress all debugging output from the tape drive. + +# Choice: ftcontroller +The floppy drive controller for ftape +CONFIG_FT_STD_FDC + Only change this setting if you have a special controller. If you + didn't plug any add-on card into your computer system but just + plugged the floppy tape cable into the already existing floppy drive + controller then you don't want to change the default setting, + i.e. choose "Standard". + + Choose "MACH-2" if you have a Mountain Mach-2 controller. + Choose "FC-10/FC-20" if you have a Colorado FC-10 or FC-20 + controller. + Choose "Alt/82078" if you have another controller that is located at + an IO base address different from the standard floppy drive + controller's base address of `0x3f0', or uses an IRQ (interrupt) + channel different from `6', or a DMA channel different from + `2'. This is necessary for any controller card that is based on + Intel's 82078 FDC such as Seagate's, Exabyte's and Iomega's "high + speed" controllers. + + If you choose something other than "Standard" then please make + sure that the settings for the IO base address and the IRQ and DMA + channel in the configuration menus below are correct. Use the manual + of your tape drive to determine the correct settings! + + If you are already successfully using your tape drive with another + operating system then you definitely should use the same settings + for the IO base, the IRQ and DMA channel that have proven to work + with that other OS. + + Note that this menu lets you specify only the default setting for + the hardware setup. The hardware configuration can be changed at + boot time (when ftape is compiled into the kernel, i.e. if you + have said Y to "Floppy tape drive") or module load time (i.e. if you + have said M to "Floppy tape drive"). + + Please read also the file <file:Documentation/ftape.txt> which + contains a short description of the parameters that can be set at + boot or load time. If you want to use your floppy tape drive on a + PCI-bus based system, please read the file + <file:drivers/char/ftape/README.PCI>. + +IO base for the floppy disk controller used with Ftape +CONFIG_FT_FDC_BASE + You don't need to specify a value if the following default + settings for the base IO address are correct: + <<< MACH-2 : 0x1E0 >>> + <<< FC-10/FC-20: 0x180 >>> + <<< Secondary : 0x370 >>> + Secondary refers to a secondary FDC controller like the "high speed" + controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash. + Please make sure that the setting for the IO base address + specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR + CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already + successfully using the tape drive with another operating system then + you definitely should use the same settings for the IO base that has + proven to work with that other OS. + + Note that this menu lets you specify only the default setting for + the IO base. The hardware configuration can be changed at boot time + (when ftape is compiled into the kernel, i.e. if you specified Y to + "Floppy tape drive") or module load time (i.e. if you have said M to + "Floppy tape drive"). + + Please read also the file <file:Documentation/ftape.txt> which + contains a short description of the parameters that can be set at + boot or load time. + +IRQ channel for the floppy disk controller used with Ftape +CONFIG_FT_FDC_IRQ + You don't need to specify a value if the following default + settings for the interrupt channel are correct: + <<< MACH-2 : 6 >>> + <<< FC-10/FC-20: 9 >>> + <<< Secondary : 6 >>> + Secondary refers to secondary a FDC controller like the "high speed" + controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash. + Please make sure that the setting for the IO base address + specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR + CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already + successfully using the tape drive with another operating system then + you definitely should use the same settings for the IO base that has + proven to work with that other OS. + + Note that this menu lets you specify only the default setting for + the IRQ channel. The hardware configuration can be changed at boot + time (when ftape is compiled into the kernel, i.e. if you said Y to + "Floppy tape drive") or module load time (i.e. if you said M to + "Floppy tape drive"). + + Please read also the file <file:Documentation/ftape.txt> which + contains a short description of the parameters that can be set at + boot or load time. + +DMA channel for the floppy disk controller used with Ftape +CONFIG_FT_FDC_DMA + You don't need to specify a value if the following default + settings for the DMA channel are correct: + <<< MACH-2 : 2 >>> + <<< FC-10/FC-20: 3 >>> + <<< Secondary : 2 >>> + Secondary refers to a secondary FDC controller like the "high speed" + controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash. + Please make sure that the setting for the IO base address + specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR + CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already + successfully using the tape drive with another operating system then + you definitely should use the same settings for the IO base that has + proven to work with that other OS. + + Note that this menu lets you specify only the default setting for + the DMA channel. The hardware configuration can be changed at boot + time (when ftape is compiled into the kernel, i.e. if you said Y to + "Floppy tape drive") or module load time (i.e. if you said M to + "Floppy tape drive"). + + Please read also the file <file:Documentation/ftape.txt> which + contains a short description of the parameters that can be set at + boot or load time. + +FDC FIFO Threshold before requesting DMA service +CONFIG_FT_FDC_THR + Set the FIFO threshold of the FDC. If this is higher the DMA + controller may serve the FDC after a higher latency time. If this is + lower, fewer DMA transfers occur leading to less bus contention. + You may try to tune this if ftape annoys you with "reduced data + rate because of excessive overrun errors" messages. However, this + doesn't seem to have too much effect. + + If unsure, don't touch the initial value, i.e. leave it at "8". + +FDC maximum data rate +CONFIG_FT_FDC_MAX_RATE + With some motherboard/FDC combinations ftape will not be able to + run your FDC/tape drive combination at the highest available + speed. If this is the case you'll encounter "reduced data rate + because of excessive overrun errors" messages and lots of retries + before ftape finally decides to reduce the data rate. + + In this case it might be desirable to tell ftape beforehand that + it need not try to run the tape drive at the highest available + speed. If unsure, leave this disabled, i.e. leave it at 2000 + bits/sec. + +Direct Rendering Manager (XFree86 DRI support) +CONFIG_DRM + Kernel-level support for the Direct Rendering Infrastructure (DRI) + introduced in XFree86 4.0. If you say Y here, you need to select + the module that's right for your graphics card from the list below. + These modules provide support for synchronization, security, and + DMA transfers. Please see <http://dri.sourceforge.net/> for more + details. You should also select and configure AGP + (/dev/agpgart) support. + +Build drivers for new (XFree 4.1) DRM +CONFIG_DRM_NEW + If you set this option, the new DRM version needed by XFree86 4.1 + will be used. Otherwise, the old DRM version will be used, + appropriate for XFree86 4.0. + +3dfx Banshee/Voodoo3+ +CONFIG_DRM_TDFX + Choose this option if you have a 3dfx Banshee or Voodoo3 (or later), + graphics card. If M is selected, the module will be called tdfx.o. + +3dlabs GMX 2000 +CONFIG_DRM_GAMMA + Choose this option if you have a 3dlabs GMX 2000 graphics card. + If M is selected, the module will be called gamma.o. + +ATI Rage 128 +CONFIG_DRM_R128 + Choose this option if you have an ATI Rage 128 graphics card. If M + is selected, the module will be called r128.o. AGP support for + this card is strongly suggested (unless you have a PCI version). + +ATI Radeon +CONFIG_DRM_RADEON + Choose this option if you have an ATI Radeon graphics card. There + are both PCI and AGP versions. You don't need to choose this to + run the Radeon in plain VGA mode. There is a product page at + <http://www.ati.com/na/pages/products/pc/radeon32/index.html>. + If M is selected, the module will be called radeon.o. + +Intel I810 +CONFIG_DRM_I810 + Choose this option if you have an Intel I810 graphics card. If M is + selected, the module will be called i810.o. AGP support is required + for this driver to work. + +Matrox G200/G400/G450 +CONFIG_DRM_MGA + Choose this option if you have a Matrox G200, G400 or G450 graphics + card. If M is selected, the module will be called mga.o. AGP + support is required for this driver to work. + +3dfx Banshee/Voodoo3+ +CONFIG_DRM40_TDFX + Choose this option if you have a 3dfx Banshee or Voodoo3 (or later), + graphics card. If M is selected, the module will be called tdfx.o. + +3dlabs GMX 2000 +CONFIG_DRM40_GAMMA + Choose this option if you have a 3dlabs GMX 2000 graphics card. + If M is selected, the module will be called gamma.o. + +ATI Rage 128 +CONFIG_DRM40_R128 + Choose this option if you have an ATI Rage 128 graphics card. If M + is selected, the module will be called r128.o. AGP support for + this card is strongly suggested (unless you have a PCI version). + +ATI Radeon +CONFIG_DRM40_RADEON + Choose this option if you have an ATI Radeon graphics card. There + are both PCI and AGP versions. You don't need to choose this to + run the Radeon in plain VGA mode. There is a product page at + <http://www.ati.com/na/pages/products/pc/radeon32/index.html>. + If M is selected, the module will be called radeon.o. + +Intel I810 +CONFIG_DRM40_I810 + Choose this option if you have an Intel I810 graphics card. If M is + selected, the module will be called i810.o. AGP support is required + for this driver to work. + +Matrox G200/G400/G450 +CONFIG_DRM40_MGA + Choose this option if you have a Matrox G200, G400 or G450 graphics + card. If M is selected, the module will be called mga.o. AGP + support is required for this driver to work. + +Creator/Creator3D/Elite3D +CONFIG_DRM_FFB + Choose this option if you have one of Sun's Creator3D-based graphics + and frame buffer cards. Product page at + <http://www.sun.com/desktop/products/Graphics/creator3d.html>. + +MTRR (Memory Type Range Register) support +CONFIG_MTRR + On Intel P6 family processors (Pentium Pro, Pentium II and later) + the Memory Type Range Registers (MTRRs) may be used to control + processor access to memory ranges. This is most useful if you have + a video (VGA) card on a PCI or AGP bus. Enabling write-combining + allows bus write transfers to be combined into a larger transfer + before bursting over the PCI/AGP bus. This can increase performance + of image write operations 2.5 times or more. Saying Y here creates a + /proc/mtrr file which may be used to manipulate your processor's + MTRRs. Typically the X server should use this. + + This code has a reasonably generic interface so that similar + control registers on other processors can be easily supported + as well: + + The Cyrix 6x86, 6x86MX and M II processors have Address Range + Registers (ARRs) which provide a similar functionality to MTRRs. For + these, the ARRs are used to emulate the MTRRs. + The AMD K6-2 (stepping 8 and above) and K6-3 processors have two + MTRRs. The Centaur C6 (WinChip) has 8 MCRs, allowing + write-combining. All of these processors are supported by this code + and it makes sense to say Y here if you have one of them. + + Saying Y here also fixes a problem with buggy SMP BIOSes which only + set the MTRRs for the boot CPU and not for the secondary CPUs. This + can lead to all sorts of problems, so it's good to say Y here. + + You can safely say Y even if your machine doesn't have MTRRs, you'll + just add about 9 KB to your kernel. + + See <file:Documentation/mtrr.txt> for more information. + +CPU clock frequency of your DEC Alpha +CONFIG_FT_ALPHA_CLOCK + On some DEC Alpha machines the CPU clock frequency cannot be + determined automatically, so you need to specify it here ONLY if + running a DEC Alpha, otherwise this setting has no effect. + +Double Talk PC internal speech card support +CONFIG_DTLK + This driver is for the DoubleTalk PC, a speech synthesizer + manufactured by RC Systems (<http://www.rcsys.com/>). It is also + called the `internal DoubleTalk'. If you want to compile this as a + module ( = code which can be inserted in and removed from the + running kernel whenever you want), say M here and read + <file:Documentation/modules.txt>. The module will be called dtlk.o. + +Siemens R3964 serial protocol support +CONFIG_R3964 + This driver allows synchronous communication with devices using the + Siemens R3964 packet protocol. Unless you are dealing with special + hardware like PLCs, you are unlikely to need this. + + To compile this driver as a module ( = code which can be inserted in + and removed from the running kernel whenever you want), say M here + and read <file:Documentation/modules.txt>. The module will be called + n_r3964.o. + + If unsure, say N. + +Applicom intelligent fieldbus card support +CONFIG_APPLICOM + This driver provides the kernel-side support for the intelligent + fieldbus cards made by Applicom International. More information + about these cards can be found on the WWW at the address + <http://www.applicom-int.com/>, or by email from David Woodhouse + <dwmw2@infradead.org>. + + To compile this driver as a module ( = code which can be inserted in + and removed from the running kernel whenever you want), say M here + and read <file:Documentation/modules.txt>. The module will be called + applicom.o. + + If unsure, say N. + +Sony Vaio Programmable I/O Control Device support +CONFIG_SONYPI + This driver enables access to the Sony Programmable I/O Control + Device which can be found in many (all ?) Sony Vaio laptops. + + If you have one of those laptops, read + <file:Documentation/sonypi.txt>, and say Y or M here. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called sonypi.o. + +Intel Random Number Generator support +CONFIG_INTEL_RNG + This driver provides kernel-side support for the Random Number + Generator hardware found on Intel i8xx-based motherboards. + + Both a character driver, used to read() entropy data, and a timer + function which automatically adds entropy directly into the + kernel pool, are exported by this driver. + + To compile this driver as a module ( = code which can be inserted in + and removed from the running kernel whenever you want), say M here + and read <file:Documentation/modules.txt>. The module will be called + i810_rng.o. + + If unsure, say N. + +Power Management support +CONFIG_PM + "Power Management" means that parts of your computer are shut + off or put into a power conserving "sleep" mode if they are not + being used. There are two competing standards for doing this: APM + and ACPI. If you want to use either one, say Y here and then also + to the requisite support below. + + Power Management is most important for battery powered laptop + computers; if you have a laptop, check out the Linux Laptop home + page on the WWW at + <http://www.cs.utexas.edu/users/kharker/linux-laptop/> and the + Battery Powered Linux mini-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + Note that, even if you say N here, Linux on the x86 architecture + will issue the hlt instruction if nothing is to be done, thereby + sending the processor to sleep and saving power. + +ACPI support +CONFIG_ACPI + ACPI/OSPM support for Linux is currently under development. As such, + this support is preliminary and EXPERIMENTAL. Configuring ACPI + support enables kernel interfaces that allow higher level software + (OSPM) to manipulate ACPI defined hardware and software interfaces, + including the evaluation of ACPI control methods. If unsure, choose + N here. Note, this option will enlarge your kernel by about 120K. + + This support requires an ACPI compliant platform (hardware/firmware). + If both ACPI and Advanced Power Management (APM) support are + configured, whichever is loaded first shall be used. + + This code DOES NOT currently provide a complete OSPM implementation + -- it has not yet reached APM's level of functionality. When fully + implemented, Linux ACPI/OSPM will provide a more robust functional + replacement for legacy configuration and power management + interfaces, including the Plug-and-Play BIOS specification (PnP + BIOS), the Multi-Processor Specification (MPS), and the Advanced + Power Management specification (APM). + + Linux support for ACPI/OSPM is based on Intel Corporation's ACPI + Component Architecture (ACPI CA). The latest ACPI CA source code, + documentation, debug builds, and implementation status information + can be downloaded from: + <http://developer.intel.com/technology/iapc/acpi/downloads.htm>. + + The ACPI Sourceforge project may also be of interest: + <http://sf.net/projects/acpi/> + +Enable ACPI 2.0 with errata 1.3 +CONFIG_ACPI20 + Enable support for the 2.0 version of the ACPI interpreter. See the + help for ACPI for caveats and discussion. + +ACPI kernel configuration manager +CONFIG_ACPI_KERNEL_CONFIG + If you say `Y' here, Linux's ACPI support will use the + hardware-level system descriptions found on IA64 machines. + +ACPI Debug Statements +CONFIG_ACPI_DEBUG + The ACPI driver can optionally report errors with a great deal + of verbosity. Saying Y enables these statements. This will increase + your kernel size by around 50K. + +ACPI Bus Manager +CONFIG_ACPI_BUSMGR + The ACPI Bus Manager enumerates devices in the ACPI namespace, and + handles PnP messages. All ACPI devices use its services, so using + them requires saying Y here. + +ACPI System Driver +CONFIG_ACPI_SYS + This driver will enable your system to shut down using ACPI, and + dump your ACPI DSDT table using /proc/acpi/dsdt. + +ACPI Processor Driver +CONFIG_ACPI_CPU + This driver installs ACPI as the idle handler for Linux, and uses + ACPI C2 and C3 processor states to save power, on systems that + support it. + +ACPI Button +CONFIG_ACPI_BUTTON + This driver registers for events based on buttons, such as the + power, sleep, and lid switch. In the future, a daemon will read + /proc/acpi/event and perform user-defined actions such as shutting + down the system. Until then, you can cat it, and see output when + a button is pressed. + +ACPI AC Adapter +CONFIG_ACPI_AC + This driver adds support for the AC Adapter object, which indicates + whether a system is on AC, or not. Typically, only laptops have + this object, since desktops are always on AC. + +ACPI Embedded Controller +CONFIG_ACPI_EC + This driver is required on some systems for the proper operation of + the battery and thermal drivers. If you are compiling for a laptop, + say Y. + +ACPI Control Method Battery +CONFIG_ACPI_CMBATT + This driver adds support for battery information through + /proc/acpi/battery. If you have a laptop with a battery, say Y. + +ACPI Thermal +CONFIG_ACPI_THERMAL + This driver handles overheating conditions on laptops. It is HIGHLY + recommended, as your laptop CPU may be damaged without it. + +Advanced Power Management BIOS support +CONFIG_APM + APM is a BIOS specification for saving power using several different + techniques. This is mostly useful for battery powered laptops with + APM compliant BIOSes. If you say Y here, the system time will be + reset after a RESUME operation, the /proc/apm device will provide + battery status information, and user-space programs will receive + notification of APM "events" (e.g. battery status change). + + If you select "Y" here, you can disable actual use of the APM + BIOS by passing the "apm=off" option to the kernel at boot time. + + Note that the APM support is almost completely disabled for + machines with more than one CPU. + + In order to use APM, you will need supporting software. For location + and more information, read <file:Documentation/pm.txt> and the + Battery Powered Linux mini-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + This driver does not spin down disk drives (see the hdparm(8) + manpage ("man 8 hdparm") for that), and it doesn't turn off + VESA-compliant "green" monitors. + + This driver does not support the TI 4000M TravelMate and the ACER + 486/DX4/75 because they don't have compliant BIOSes. Many "green" + desktop machines also don't have compliant BIOSes, and this driver + may cause those machines to panic during the boot phase. + + Generally, if you don't have a battery in your machine, there isn't + much point in using this driver and you should say N. If you get + random kernel OOPSes or reboots that don't seem to be related to + anything, try disabling/enabling this option (or disabling/enabling + APM in your BIOS). + + Some other things you should try when experiencing seemingly random, + "weird" problems: + + 1) make sure that you have enough swap space and that it is + enabled. + 2) pass the "no-hlt" option to the kernel + 3) switch on floating point emulation in the kernel and pass + the "no387" option to the kernel + 4) pass the "floppy=nodma" option to the kernel + 5) pass the "mem=4M" option to the kernel (thereby disabling + all but the first 4 MB of RAM) + 6) make sure that the CPU is not over clocked. + 7) read the sig11 FAQ at <http://www.bitwizard.nl/sig11/> + 8) disable the cache from your BIOS settings + 9) install a fan for the video card or exchange video RAM + 10) install a better fan for the CPU + 11) exchange RAM chips + 12) exchange the motherboard. + + To compile this driver as a module ( = code which can be inserted in + and removed from the running kernel whenever you want), say M here + and read <file:Documentation/modules.txt>. The module will be called + apm.o. + +Ignore USER SUSPEND +CONFIG_APM_IGNORE_USER_SUSPEND + This option will ignore USER SUSPEND requests. On machines with a + compliant APM BIOS, you want to say N. However, on the NEC Versa M + series notebooks, it is necessary to say Y because of a BIOS bug. + +Enable APM at boot time +CONFIG_APM_DO_ENABLE + Enable APM features at boot time. From page 36 of the APM BIOS + specification: "When disabled, the APM BIOS does not automatically + power manage devices, enter the Standby State, enter the Suspend + State, or take power saving steps in response to CPU Idle calls." + This driver will make CPU Idle calls when Linux is idle (unless this + feature is turned off -- see "Do CPU IDLE calls", below). This + should always save battery power, but more complicated APM features + will be dependent on your BIOS implementation. You may need to turn + this option off if your computer hangs at boot time when using APM + support, or if it beeps continuously instead of suspending. Turn + this off if you have a NEC UltraLite Versa 33/C or a Toshiba + T400CDT. This is off by default since most machines do fine without + this feature. + +Make CPU Idle calls when idle +CONFIG_APM_CPU_IDLE + Enable calls to APM CPU Idle/CPU Busy inside the kernel's idle loop. + On some machines, this can activate improved power savings, such as + a slowed CPU clock rate, when the machine is idle. These idle calls + are made after the idle loop has run for some length of time (e.g., + 333 mS). On some machines, this will cause a hang at boot time or + whenever the CPU becomes idle. (On machines with more than one CPU, + this option does nothing.) + +Enable console blanking using APM +CONFIG_APM_DISPLAY_BLANK + Enable console blanking using the APM. Some laptops can use this to + turn off the LCD backlight when the screen blanker of the Linux + virtual console blanks the screen. Note that this is only used by + the virtual console screen blanker, and won't turn off the backlight + when using the X Window system. This also doesn't have anything to + do with your VESA-compliant power-saving monitor. Further, this + option doesn't work for all laptops -- it might not turn off your + backlight at all, or it might print a lot of errors to the console, + especially if you are using gpm. + +RTC stores time in GMT +CONFIG_APM_RTC_IS_GMT + Say Y here if your RTC (Real Time Clock a.k.a. hardware clock) + stores the time in GMT (Greenwich Mean Time). Say N if your RTC + stores localtime. + + It is in fact recommended to store GMT in your RTC, because then you + don't have to worry about daylight savings time changes. The only + reason not to use GMT in your RTC is if you also run a broken OS + that doesn't understand GMT. + +Allow interrupts during APM BIOS calls +CONFIG_APM_ALLOW_INTS + Normally we disable external interrupts while we are making calls to + the APM BIOS as a measure to lessen the effects of a badly behaving + BIOS implementation. The BIOS should reenable interrupts if it + needs to. Unfortunately, some BIOSes do not -- especially those in + many of the newer IBM Thinkpads. If you experience hangs when you + suspend, try setting this to Y. Otherwise, say N. + +Use real mode APM BIOS call to power off +CONFIG_APM_REAL_MODE_POWER_OFF + Use real mode APM BIOS calls to switch off the computer. This is + a work-around for a number of buggy BIOSes. Switch this option on if + your computer crashes instead of powering off properly. + +Watchdog Timer Support +CONFIG_WATCHDOG + If you say Y here (and to one of the following options) and create a + character special file /dev/watchdog with major number 10 and minor + number 130 using mknod ("man mknod"), you will get a watchdog, i.e.: + subsequently opening the file and then failing to write to it for + longer than 1 minute will result in rebooting the machine. This + could be useful for a networked machine that needs to come back + online as fast as possible after a lock-up. There's both a watchdog + implementation entirely in software (which can sometimes fail to + reboot the machine) and a driver for hardware watchdog boards, which + are more robust and can also keep track of the temperature inside + your computer. For details, read <file:Documentation/watchdog.txt> + in the kernel source. + + The watchdog is usually used together with the watchdog daemon + which is available from + <ftp://ibiblio.org/pub/Linux/system/daemons/watchdog/>. This daemon can + also monitor NFS connections and can reboot the machine when the process + table is full. + + If unsure, say N. + +Disable watchdog shutdown on close +CONFIG_WATCHDOG_NOWAYOUT + The default watchdog behaviour (which you get if you say N here) is + to stop the timer if the process managing it closes the file + /dev/watchdog. It's always remotely possible that this process might + get killed. If you say Y here, the watchdog cannot be stopped once + it has been started. + +WDT Watchdog timer +CONFIG_WDT + If you have a WDT500P or WDT501P watchdog board, say Y here, + otherwise N. It is not possible to probe for this board, which means + that you have to inform the kernel about the IO port and IRQ using + the "wdt=" kernel option (try "man bootparam" or see the + documentation of your boot loader (lilo or loadlin) about how to + pass options to the kernel at boot time). + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called wdt.o. + +WDT PCI Watchdog timer +CONFIG_WDTPCI + If you have a PCI WDT500/501 watchdog board, say Y here, otherwise + N. It is not possible to probe for this board, which means that you + have to inform the kernel about the IO port and IRQ using the "wdt=" + kernel option (try "man bootparam" or see the documentation of your + boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time). + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read <file:Documentation/modules.txt>. The module + will be called wdt_pci.o. + +WDT501 features +CONFIG_WDT_501 + Saying Y here and creating a character special file /dev/temperature + with major number 10 and minor number 131 ("man mknod") will give + you a thermometer inside your computer: reading from + /dev/temperature yields one byte, the temperature in degrees + Fahrenheit. This works only if you have a WDT501P watchdog board + installed. + +Fan Tachometer +CONFIG_WDT_501_FAN + Enable the Fan Tachometer on the WDT501. Only do this if you have a + fan tachometer actually set up. + +Software Watchdog +CONFIG_SOFT_WATCHDOG + A software monitoring watchdog. This will fail to reboot your system + from some situations that the hardware watchdog will recover + from. Equally it's a lot cheaper to install. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + softdog.o. + +Berkshire Products PC Watchdog +CONFIG_PCWATCHDOG + This is the driver for the Berkshire Products PC Watchdog card. + This card simply watches your kernel to make sure it doesn't freeze, + and if it does, it reboots your computer after a certain amount of + time. This driver is like the WDT501 driver but for different + hardware. Please read <file:Documentation/pcwd-watchdog.txt>. The PC + watchdog cards can be ordered from <http://www.berkprod.com/>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called pcwd.o. If you want to compile it as a module, + say M here and read <file:Documentation/modules.txt>. + + Most people will say N. + +Acquire SBC Watchdog Timer +CONFIG_ACQUIRE_WDT + This is the driver for the hardware watchdog on the PSC-6x86 Single + Board Computer produced by Acquire Inc (and others). This watchdog + simply watches your kernel to make sure it doesn't freeze, and if + it does, it reboots your computer after a certain amount of time. + + This driver is like the WDT501 driver but for different hardware. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called pscwdt.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. Most + people will say N. + +Advantech SBC Watchdog Timer +CONFIG_ADVANTECH_WDT + If you are configuring a Linux kernel for the Advantech single-board + computer, say `Y' here to support its built-in watchdog timer + feature. See the help for CONFIG_WATCHDOG for discussion. + +ALi M7101 Watchdog Timer +CONFIG_ALIM7101_WDT + This is the driver for the hardware watchdog on the ALi M7101 PMU + as used in the x86 Cobalt servers. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called alim7101_wdt.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. Most + people will say N. + +IB700 SBC Watchdog Timer +CONFIG_IB700_WDT + This is the driver for the hardware watchdog on the IB700 Single + Board Computer produced by TMC Technology (www.tmc-uk.com). This watchdog + simply watches your kernel to make sure it doesn't freeze, and if + it does, it reboots your computer after a certain amount of time. + + This driver is like the WDT501 driver but for slightly different hardware. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called ib700wdt.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. Most people + will say N. + +Mixcom Watchdog +CONFIG_MIXCOMWD + This is a driver for the Mixcom hardware watchdog cards. This + watchdog simply watches your kernel to make sure it doesn't freeze, + and if it does, it reboots your computer after a certain amount of + time. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called mixcomwd.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. Most + people will say N. + +ZF MachZ Watchdog +CONFIG_MACHZ_WDT + If you are using a ZF Micro MachZ processor, say Y here, otherwise + N. This is the driver for the watchdog timer builtin on that + processor using ZF-Logic interface. This watchdog simply watches + your kernel to make sure it doesn't freeze, and if it does, it + reboots your computer after a certain amount of time. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called machzwd.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. + +CONFIG_SC1200_WDT + This is a driver for National Semiconductor PC87307/PC97307 hardware + watchdog cards as found on the SC1200. This watchdog is mainly used + for power management purposes and can be used to power down the device + during inactivity periods (includes interrupt activity monitoring). + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called sc1200wdt.o. If you want to compile it as a + module, say M here and read <file:Documentation/modules.txt>. Most + people will say N. + +SuperH Watchdog +CONFIG_SH_WDT + This driver adds watchdog support for the integrated watchdog in the + SuperH 3, 4 and 5 processors. If you have one of these processors, say + Y, otherwise say N. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called shwdt.o. If you want to compile it as a module, + say M here and read Documentation/modules.txt. + +Wafer 5823 Watchdog +CONFIG_WAFER_WDT + This is a driver for the hardware watchdog on the ICP Wafer 5823 + Single Board Computer (and probably other similar models). + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + wafer5823wdt.o + +Machine Check Exception +CONFIG_X86_MCE + Machine Check Exception support allows the processor to notify the + kernel if it detects a problem (e.g. overheating, component failure). + The action the kernel takes depends on the severity of the problem, + ranging from a warning message on the console, to halting the machine. + You can safely select this on machines that do not support this feature. + + For pentium machines the mce support defaults to off as the mainboard + support is not always present. You must activate it as a boot option. + +Toshiba Laptop support +CONFIG_TOSHIBA + This adds a driver to safely access the System Management Mode of + the CPU on Toshiba portables with a genuine Toshiba BIOS. It does + not work on models with a Phoenix BIOS. The System Management Mode + is used to set the BIOS and power saving options on Toshiba portables. + + For information on utilities to make use of this driver see the + Toshiba Linux utilities web site at: + <http://www.buzzard.org.uk/toshiba/>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + toshiba.o + + Say Y if you intend to run this kernel on a Toshiba portable. + Say N otherwise. + +Dell laptop support +CONFIG_I8K + This adds a driver to safely access the System Management Mode + of the CPU on the Dell Inspiron and Latitude laptops. The System + Management Mode is used to read cpu temperature, cooling fan + status and Fn-keys status on Dell laptops. It can also be used + to switch the fans on and off. + + The driver has been developed and tested on an Inspiron 8000 + but it should work on any Dell Inspiron or Latitude laptop. + You can force loading on unsupported models by passing the + parameter `force=1' to the module. Use at your own risk. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + i8k.o + + For more information on this driver and for utilities that make + use of the module see the I8K Linux Utilities web site at: + <http://www.debian.org/~dz/i8k/>. + + Say Y if you intend to run this kernel on a Dell laptop. + Say N otherwise. + +/dev/cpu/microcode - Intel IA32 CPU microcode support +CONFIG_MICROCODE + If you say Y here and also to "/dev file system support" in the + 'File systems' section, you will be able to update the microcode on + Intel processors in the IA32 family, e.g. Pentium Pro, Pentium II, + Pentium III, Pentium 4, Xeon etc. You will obviously need the + actual microcode binary data itself which is not shipped with the + Linux kernel. + + For latest news and information on obtaining all the required + ingredients for this driver, check: + <http://www.urbanmyth.org/microcode/>. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called microcode.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. If + you use modprobe or kmod you may also want to add the line + 'alias char-major-10-184 microcode' to your /etc/modules.conf file. + +/dev/cpu/*/msr - Model-specific register support CONFIG_X86_MSR This device gives privileged processes access to the x86 Model-Specific Registers (MSRs). It is a character device with @@ -5380,8 +19295,8 @@ CONFIG_60XX_WDT Eurotech CPU-1220/1410 Watchdog Timer CONFIG_EUROTECH_WDT - Enable support for the watchdog timer on the Eurotech CPU-1220 and - CPU-1410 cards. These are PC/104 SBCs. Spec sheets and product + Enable support for the watchdog timer on the Eurotech CPU-1220 and + CPU-1410 cards. These are PC/104 SBCs. Spec sheets and product information are at <http://www.eurotech.it/>. W83877F Watchdog Timer @@ -6509,7 +20424,7 @@ CONFIG_SOUND_CMPCI_SPDIFLOOP A userspace utility to control even more internal registers of these chips is available at <http://member.nifty.ne.jp/Breeze/softwares/unix/cmictl-e.html>. - This package will among other things help you enable SPDIF + This package will among other things help you enable SPDIF out/in/loop/monitor. Enable legacy FM @@ -6725,7 +20640,7 @@ CONFIG_SOUND_GUSMAX Intel ICH audio support CONFIG_SOUND_ICH Supports the following chipsets: - + Intel ICH 82801AA Intel ICH 82901AB Intel 440 MX @@ -6734,9 +20649,9 @@ CONFIG_SOUND_ICH SiS 7012 NVidia nForce AMD 768 - + These are audio drivers for integral audio in chipsets of motherboards. - + Intel's I/O Controller Hub (ICH) is used on 810/815/820/840/845/845D/850 motherboards. SiS 7012 is used on 645/735/745 motherboards. @@ -6773,7 +20688,7 @@ CONFIG_SOUND_YMFPCI_LEGACY RME Hammerfall (RME96XX) support CONFIG_SOUND_RME96XX - Say Y or M if you have a Hammerfall or Hammerfall light multichannel card + Say Y or M if you have a Hammerfall or Hammerfall light multichannel card from RME. If you want to acess advanced features of the card, read Documentation/sound/rme96xx. @@ -6879,6 +20794,13 @@ CONFIG_LL_DEBUG Currently used only by the time services code in the MIPS port. Don't turn this on unless you know what you are doing. +Enable run-time debugging +CONFIG_DEBUG + If you say Y here, some debugging macros will do run-time checking. + If you say N here, those macros will mostly turn to no-ops. For + MIPS boards only. See include/asm-mips/debug.h for debuging macros. + If unsure, say N. + Remote GDB kernel debugging CONFIG_REMOTE_DEBUG If you say Y here, it will be possible to remotely debug the MIPS @@ -7334,7 +21256,7 @@ CONFIG_HISAX_AMD7930 HiSax debugging CONFIG_HISAX_DEBUG This enables debugging code in the new-style HiSax drivers, i.e. - the ST5481 USB driver currently. + the ST5481 USB driver currently. If in doubt, say yes. ELSA PCMCIA MicroLink cards @@ -7778,8 +21700,8 @@ CONFIG_PARPORT_SUNBPP SPARC power management support CONFIG_SUN_PM - Enable power management and CPU standby features on supported - SPARC platforms. + Enable power management and CPU standby features on supported + SPARC platforms. /proc/hardware support CONFIG_PROC_HARDWARE @@ -7835,7 +21757,7 @@ CONFIG_BLUEZ_BNEP emulation layer on top of Bluetooth. BNEP is required for Bluetooth PAN (Personal Area Network). - To use BNEP, you will need user-space utilities provided in the + To use BNEP, you will need user-space utilities provided in the BlueZ-PAN package. For more information, see <http://bluez.sourceforge.net>. @@ -7846,18 +21768,18 @@ HCI UART driver CONFIG_BLUEZ_HCIUART Bluetooth HCI UART driver. This driver is required if you want to use Bluetooth devices with - serial port interface. You will also need this driver if you have - UART based Bluetooth PCMCIA and CF devices like Xircom Credit Card + serial port interface. You will also need this driver if you have + UART based Bluetooth PCMCIA and CF devices like Xircom Credit Card adapter and BrainBoxes Bluetooth PC Card. Say Y here to compile support for Bluetooth UART devices into the kernel or say M to compile it as module (hci_uart.o). -HCI UART (H4) protocol support +HCI UART (H4) protocol support CONFIG_BLUEZ_HCIUART_H4 - UART (H4) is serial protocol for communication between Bluetooth - device and host. This protocol is required for most UART based - Bluetooth device (including PCMCIA and CF). + UART (H4) is serial protocol for communication between Bluetooth + device and host. This protocol is required for most UART based + Bluetooth device (including PCMCIA and CF). Say Y here to compile support for HCI UART (H4) protocol. @@ -7873,8 +21795,8 @@ CONFIG_BLUEZ_HCIUSB HCI USB zero packet support CONFIG_BLUEZ_USB_ZERO_PACKET Support for USB zero packets. - This option is provided only as a work around for buggy Bluetooth USB - devices. Do _not_ enable it unless you know for sure that your device + This option is provided only as a work around for buggy Bluetooth USB + devices. Do _not_ enable it unless you know for sure that your device requires zero packets. Most people should say N here. @@ -7944,7 +21866,7 @@ CompactFlash Connection Area CONFIG_CF_AREA5 If your board has "Directly Connected" CompactFlash, You should select the area where your CF is connected to. - + - "Area5" if CompactFlash is connected to Area 5 (0x14000000) - "Area6" if it is connected to Area 6 (0x18000000) @@ -8035,11 +21957,11 @@ CONFIG_BLK_DEV_Q40IDE Sun 3 support CONFIG_SUN3 This option enables support for the Sun 3 series of workstations. - Note that if this option is enabled, support for all other m68k - platforms above must be disabled in order to produce a working + Note that if this option is enabled, support for all other m68k + platforms above must be disabled in order to produce a working kernel. - Also, you will want to enable 68020 support below, and disable + Also, you will want to enable 68020 support below, and disable all other CPU types. General Linux information on the Sun 3x series (now discontinued) is at <http://www.angelfire.com/ca2/tech68k/sun3.html>. @@ -8050,7 +21972,7 @@ Sun 3X support CONFIG_SUN3X This option enables support for the Sun 3x series of workstations. Currently, only the Sun 3/80 is supported within the Sun 3x family. - You will also want to enable 68030 support below + You will also want to enable 68030 support below General Linux information on the Sun 3x series (now discontinued) is at <http://www.angelfire.com/ca2/tech68k/sun3.html>. @@ -8862,10 +22784,10 @@ CONFIG_RPXLITE Embedded Planet RPX Lite. PC104 form-factor SBC based on the MPC823. RPX-Classic: - Embedded Planet RPX Classic Low-fat. Credit-card-size SBC based on + Embedded Planet RPX Classic Low-fat. Credit-card-size SBC based on the MPC 860 - BSE-IP: + BSE-IP: Bright Star Engineering ip-Engine. TQM823L: @@ -8907,7 +22829,7 @@ CONFIG_RPXLITE URL: <http://www.speech-design.de/> IVML24: - MPC860 based board used in the "Integrated Voice Mail System", + MPC860 based board used in the "Integrated Voice Mail System", Large Version (24 voice channels) Manufacturer: Speech Design, <http://www.speech-design.de/> Date of Release: March 2001 (?) @@ -8929,7 +22851,7 @@ CONFIG_RPXLITE End of life: - URL: <http://www.multidata.de/english/products/hpro.htm> - IP860: + IP860: VMEBus IP (Industry Pack) carrier board with MPC860 Manufacturer: MicroSys GmbH, <http://www.microsys.de/> Date of Release: ? @@ -9004,7 +22926,7 @@ CONFIG_FPS850 TQM860 CONFIG_TQM860 Say Y here to support the TQM860, one of an MPC8xx-based family of - SBCs (credit-card size) from TQ Components first released in + SBCs (credit-card size) from TQ Components first released in mid-1999 and discontinued mid-2000. SM850 @@ -9564,7 +23486,7 @@ CONFIG_RADIO_GEMTEK_PCI Choose Y here if you have this PCI FM radio card. In order to control your radio card, you will need to use programs - that are compatible with the Video for Linux API. Information on + that are compatible with the Video for Linux API. Information on this API and pointers to "v4l" programs may be found on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>. @@ -9810,7 +23732,7 @@ CONFIG_IPL_TAPE IPL from a virtual card reader emulated by VM/ESA CONFIG_IPL_VM - Select this option if you are running under VM/ESA and want + Select this option if you are running under VM/ESA and want to IPL the image from the emulated card reader. CONFIG_PFAULT @@ -9834,7 +23756,7 @@ Support for IBM-style disk-labels (S/390) CONFIG_S390_PARTITION Enable this option to assure standard IBM labels on the DASDs. You must enable it, if you are planning to access DASDs also - attached to another IBM mainframe operation system (OS/390, + attached to another IBM mainframe operation system (OS/390, VM/ESA, VSE/ESA). Support for DASD hard disks @@ -9845,13 +23767,13 @@ CONFIG_DASD Support for ECKD hard disks CONFIG_DASD_ECKD - ECKD (Extended Count Key Data) devices are the most commonly used - devices on S/390s. You should enable this option unless you are + ECKD (Extended Count Key Data) devices are the most commonly used + devices on S/390s. You should enable this option unless you are very sure you have no ECKD device. ECKD demand loading CONFIG_DASD_AUTO_ECKD - This option enables demand loading of the ECKD module. + This option enables demand loading of the ECKD module. Support for FBA hard disks CONFIG_DASD_FBA @@ -9860,7 +23782,7 @@ CONFIG_DASD_FBA FBA demand loading CONFIG_DASD_AUTO_FBA - This option enables demand loading of the FBA module. + This option enables demand loading of the FBA module. Support for DIAG access to CMS reserved Disks CONFIG_DASD_DIAG @@ -9870,7 +23792,7 @@ CONFIG_DASD_DIAG DIAG demand loading CONFIG_DASD_AUTO_DIAG - This option enables demand loading of the DIAG module. + This option enables demand loading of the DIAG module. Merge some code into the kernel to make the image IPLable CONFIG_IPLABLE @@ -10000,8 +23922,8 @@ CONFIG_IUCV Process warning machine checks CONFIG_MACHCHK_WARNING - Select this option if you want the machine check handler on IBM S/390 or - zSeries to process warning machine checks (e.g. on power failures). + Select this option if you want the machine check handler on IBM S/390 or + zSeries to process warning machine checks (e.g. on power failures). If unsure, say "Y". Use chscs for Common I/O @@ -10891,7 +24813,7 @@ CONFIG_USB_STORAGE_HP8200e you use this driver. If in doubt, select N. Lexar Jumpshot Compact Flash Reader -CONFIG_USB_STORAGE_JUMPSHOT +CONFIG_USB_STORAGE_JUMPSHOT This option enables a sub-driver of the USB Mass Storage driver. These sub-drivers are considered experimental, and should only be used by very brave people. System crashes and other bad things are likely to occur if @@ -10923,12 +24845,12 @@ CONFIG_NS83820 This is a driver for the National Semiconductor DP83820 series of gigabit ethernet MACs. Cards using this chipset include: - SMC 9452TX SMC SMC9462TX + SMC 9452TX SMC SMC9462TX D-Link DGE-500T PureData PDP8023Z-TG SOHO-GA2000T SOHO-GA2500T. NetGear GA621 - This driver supports the use of zero copy on tx, checksum + This driver supports the use of zero copy on tx, checksum validation on rx, and 64 bit addressing. If you want to compile the driver as a module ( = code which can be @@ -11073,7 +24995,7 @@ CONFIG_OLD_BELKIN_DONGLE and read <file:Documentation/modules.txt>. The module will be called old_belkin.o. Some information is contained in the comments at the top of <file:drivers/net/irda/old_belkin.c>. - + ACTiSYS IR-200L dongle (Experimental) CONFIG_ACT200L_DONGLE Say Y here if you want to build support for the ACTiSYS IR-200L @@ -12425,7 +26347,7 @@ Physical memory start address CONFIG_MEMORY_START Computers built with Hitachi SuperH processors always map the ROM starting at address zero. But the processor - does not specify the range that RAM takes. + does not specify the range that RAM takes. The physical memory (RAM) start address will be automatically set to 08000000, unless you selected one of the following @@ -12485,7 +26407,7 @@ CONFIG_HD64465_IOBASE The default setting of the HD64465 IO base address is 0xb0000000. Do not change this unless you know what you are doing. - + Early printk support CONFIG_SH_EARLY_PRINTK Say Y here to redirect kernel printk messages to the serial port @@ -12756,7 +26678,7 @@ CONFIG_SERIAL_SGI_L1_PROTOCOL SGI SN (Scalable NUMA) platform for IA64. If you are compiling for an SGI SN box then Y is the recommended value, otherwise say N. -New bus configuration (EXPERIMENTAL) +New bus configuration (EXPERIMENTAL) CONFIG_TULIP_MWI This configures your Tulip card specifically for the card and system cache line size type you are using. @@ -12765,6 +26687,26 @@ CONFIG_TULIP_MWI If unsure, say N. +CONFIG_IP_NF_MATCH_LAYER7 + Say Y if you want to be able to classify connections (and their + packets) based on regular expression matching of their application + layer data. This is one way to classify applications such as + peer-to-peer filesharing systems that do not always use the same + port. + + To compile it as a module, choose M here. If unsure, say N. + +CONFIG_IP_NF_MATCH_LAYER7_DEBUG + Say Y to get lots of debugging output. + +RTSP protocol support +CONFIG_IP_NF_RTSP + Support the RTSP protocol. This allows UDP transports to be setup + properly, including RTP and RDT. + + If you want to compile it as a module, say 'M' here and read + Documentation/modules.txt. If unsure, say 'Y'. + # # A couple of things I keep forgetting: # capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, diff --git a/release/src/linux/linux/Documentation/filesystems/00-INDEX b/release/src/linux/linux/Documentation/filesystems/00-INDEX index 7ce02316..15abefcb 100644 --- a/release/src/linux/linux/Documentation/filesystems/00-INDEX +++ b/release/src/linux/linux/Documentation/filesystems/00-INDEX @@ -10,6 +10,8 @@ befs.txt - info for the BeOS file system (BFS) bfs.txt - info for the SCO UnixWare Boot Filesystem (BFS). +cifs.txt + - info on the Common Internet File System (CIFS) coda.txt - description of the CODA filesystem. cramfs.txt diff --git a/release/src/linux/linux/Documentation/filesystems/cifs.txt b/release/src/linux/linux/Documentation/filesystems/cifs.txt new file mode 100644 index 00000000..49cc923a --- /dev/null +++ b/release/src/linux/linux/Documentation/filesystems/cifs.txt @@ -0,0 +1,51 @@ + 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. CIFS is fully supported by current network + file servers such as Windows 2000, Windows 2003 (including + Windows XP) as well by Samba (which provides excellent CIFS + server support for Linux and many other operating systems), so + this network filesystem client can mount to a wide variety of + servers. The smbfs module should be used instead of this cifs module + for mounting to older SMB servers such as OS/2. The smbfs and cifs + modules can coexist and do not conflict. The CIFS VFS filesystem + module is designed to work well with servers that implement the + newer versions (dialects) of the SMB/CIFS protocol such as Samba, + the program written by Andrew Tridgell that turns any Unix host + into a SMB/CIFS file server. + + The intent of this module is to provide the most advanced network + file system function for CIFS compliant servers, including better + POSIX compliance, secure per-user session establishment, high + performance safe distributed caching (oplock), optional packet + signing, large files, Unicode support and other internationalization + improvements. Since both Samba server and this filesystem client support + the CIFS Unix extensions, the combination can provide a reasonable + alternative to NFSv4 for fileserving in some Linux to Linux environments, + not just in Linux to Windows environments. + + This filesystem has an optional mount utility (mount.cifs) that can + be obtained from the project page and installed in the path in the same + directory with the other mount helpers (such as mount.smbfs). + Mounting using the cifs filesystem without installing the mount helper + requires specifying the server's ip address. + + For Linux 2.4: + mount //anything/here /mnt_target -o + user=username,pass=password,unc=//ip_address_of_server/sharename + + For Linux 2.5: + mount //ip_address_of_server/sharename /mnt_target -o user=username, pass=password + + + For more information on the module see the project page at + + http://us1.samba.org/samba/Linux_CIFS_client.html + + For more information on CIFS see: + + http://www.snia.org/tech_activities/CIFS + + or the Samba site: + + http://www.samba.org diff --git a/release/src/linux/linux/Makefile b/release/src/linux/linux/Makefile index b378a3ff..beb7b184 100644 --- a/release/src/linux/linux/Makefile +++ b/release/src/linux/linux/Makefile @@ -236,7 +236,9 @@ CLEAN_FILES = \ drivers/tc/lk201-map.c \ net/khttpd/make_times_h \ net/khttpd/times.h \ - submenu* + submenu* \ + drivers/net/hnd/shared_ksyms.c + # directories removed with 'make clean' CLEAN_DIRS = \ modules @@ -460,7 +462,7 @@ modules modules_install: dummy endif clean: archclean - find . \( -name '*.[oas]' -o -name core -o -name '.*.flags' \) -type f -print \ + find . \( -name '*.[oas]' -o -name core -o -name '.*.flags' \) -type f -not -name diag_led.o -not -name ctmisc.o -print \ | grep -v lxdialog/ | xargs rm -f rm -f $(CLEAN_FILES) rm -rf $(CLEAN_DIRS) diff --git a/release/src/linux/linux/arch/mips/Makefile b/release/src/linux/linux/arch/mips/Makefile index fb3caa33..34111451 100644 --- a/release/src/linux/linux/arch/mips/Makefile +++ b/release/src/linux/linux/arch/mips/Makefile @@ -636,10 +636,12 @@ archclean: $(MAKE) -C arch/$(ARCH)/tools clean $(MAKE) -C arch/mips/baget clean $(MAKE) -C arch/mips/lasat clean + $(MAKE) -C arch/mips/brcm-boards/bcm947xx/compressed clean archmrproper: @$(MAKEBOOT) mrproper $(MAKE) -C arch/$(ARCH)/tools mrproper + $(MAKE) -C arch/mips/brcm-boards/bcm947xx/compressed mrproper archdep: if [ ! -f $(TOPDIR)/include/asm-$(ARCH)/offset.h ]; then \ diff --git a/release/src/linux/linux/arch/mips/brcm-boards/bcm947xx/prom-orig.c b/release/src/linux/linux/arch/mips/brcm-boards/bcm947xx/prom-orig.c new file mode 100644 index 00000000..706dfbf1 --- /dev/null +++ b/release/src/linux/linux/arch/mips/brcm-boards/bcm947xx/prom-orig.c @@ -0,0 +1,41 @@ +/* + * Early initialization code for BCM94710 boards + * + * Copyright 2006, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * $Id$ + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <asm/bootinfo.h> + +void __init +prom_init(int argc, const char **argv) +{ + unsigned long mem; + + mips_machgroup = MACH_GROUP_BRCM; + mips_machtype = MACH_BCM947XX; + + /* Figure out memory size by finding aliases */ + for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) { + if (*(unsigned long *)((unsigned long)(prom_init) + mem) == + *(unsigned long *)(prom_init)) + break; + } + add_memory_region(0, mem, BOOT_MEM_RAM); +} + +void __init +prom_free_prom_memory(void) +{ +} diff --git a/release/src/linux/linux/arch/mips/brcm-boards/bcm947xx/prom.c b/release/src/linux/linux/arch/mips/brcm-boards/bcm947xx/prom.c index 242dafb9..cb35926d 100644 --- a/release/src/linux/linux/arch/mips/brcm-boards/bcm947xx/prom.c +++ b/release/src/linux/linux/arch/mips/brcm-boards/bcm947xx/prom.c @@ -1,7 +1,7 @@ /* * Early initialization code for BCM94710 boards * - * Copyright 2005, Broadcom Corporation + * Copyright 2006, Broadcom Corporation * All Rights Reserved. * * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY @@ -9,7 +9,7 @@ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. * - * $Id: prom.c,v 1.1.1.7 2005/03/07 07:30:37 kanki Exp $ + * $Id$ */ #include <linux/config.h> @@ -18,24 +18,39 @@ #include <linux/types.h> #include <asm/bootinfo.h> -void __init -prom_init(int argc, const char **argv) +void __init prom_init(int argc, char **argv, char **envp, int *prom_vec) { - unsigned long mem; + unsigned long mem, before, offset; - mips_machgroup = MACH_GROUP_BRCM; - mips_machtype = MACH_BCM947XX; + mips_machgroup = MACH_GROUP_BRCM; + mips_machtype = MACH_BCM947XX; - /* Figure out memory size by finding aliases */ - for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) { - if (*(unsigned long *)((unsigned long)(prom_init) + mem) == - *(unsigned long *)(prom_init)) + /* Figure out memory size by finding aliases. + * + * We assume that there will be no more than 128 MB of memory, + * and that the memory size will be a multiple of 1 MB. + * + * We set 'before' to be the amount of memory (in MB) before this + * function, i.e. one MB less than the number of MB of memory that we + * *know* we have. And we set 'offset' to be the address of 'prominit' + * minus 'before', so that KSEG0 or KSEG1 base + offset < 1 MB. + * This prevents us from overrunning 128 MB and causing a bus error. + */ + before = ((unsigned long) &prom_init) & (127 << 20); + offset = ((unsigned long) &prom_init) - before; + for (mem = before + (1 << 20); mem < (128 << 20); mem += (1 << 20)) + if (*(unsigned long *)(offset + mem) == + *(unsigned long *)(prom_init)) { + /* + * We may already be well past the end of memory at + * this point, so we'll have to compensate for it. + */ + mem -= before; break; - } + } add_memory_region(0, mem, BOOT_MEM_RAM); } -void __init -prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { } diff --git a/release/src/linux/linux/arch/mips/brcm-boards/bcm947xx/setup.c b/release/src/linux/linux/arch/mips/brcm-boards/bcm947xx/setup.c index c4983dc2..dc55be85 100644 --- a/release/src/linux/linux/arch/mips/brcm-boards/bcm947xx/setup.c +++ b/release/src/linux/linux/arch/mips/brcm-boards/bcm947xx/setup.c @@ -3,7 +3,7 @@ * * Copyright 2005, Broadcom Corporation * All Rights Reserved. - * + * * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS @@ -38,8 +38,6 @@ #include <sbutils.h> #include <trxhdr.h> -#include <cy_conf.h> - extern void bcm947xx_time_init(void); extern void bcm947xx_timer_setup(struct irqaction *irq); @@ -53,9 +51,6 @@ extern void breakpoint(void); extern struct ide_ops std_ide_ops; #endif -#ifdef MULTILANG_SUPPORT -#endif - /* Global SB handle */ void *bcm947xx_sbh = NULL; spinlock_t bcm947xx_sbh_lock = SPIN_LOCK_UNLOCKED; @@ -139,9 +134,9 @@ brcm_setup(void) /* Initialize clocks and interrupts */ sb_mips_init(sbh); - /* - * Now that the sbh is inited set the proper PFC value - */ + /* + * Now that the sbh is inited set the proper PFC value + */ pfc_val = sb_mips_get_pfc(sbh); printk("Setting the PFC value as 0x%x\n", pfc_val); check_enable_mips_pfc(pfc_val); @@ -184,197 +179,97 @@ bus_error_init(void) #ifdef CONFIG_MTD_PARTITIONS + +/* + new layout -- zzz 04/2006 + + +--------------+ + | boot | + +---+----------+ < search for HDR0 + | | | + | | (kernel) | + | l | | + | i +----------+ < + trx->offset[1] + | n | | + | u | rootfs | + | x | | + + +----------+ < + trx->len + | | jffs2 | + +--------------+ < size - NVRAM_SPACE + | nvram | + +--------------+ < size +*/ + static struct mtd_partition bcm947xx_parts[] = { - //{ name: "pmon", offset: 0, size: 0, /*mask_flags: MTD_WRITEABLE,*/ }, - { name: "boot", offset: 0, size: 0, /*mask_flags: MTD_WRITEABLE,*/ }, - { name: "linux", offset: 0, size: 0, }, - { name: "rootfs", offset: 0, size: 0, /*mask_flags: MTD_WRITEABLE,*/ }, -#ifdef MULTILANG_SUPPORT - { name: "lang", offset: 0, size: 0, /*mask_flags: MTD_WRITEABLE,*/ }, /* for multilang*/ -#endif - { name: "nvram", offset: 0, size: 0, }, + { name: "pmon", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, }, + { name: "linux", offset: 0, size: 0, }, + { name: "rootfs", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, }, + { name: "jffs2", offset: 0, size: 0, }, + { name: "nvram", offset: 0, size: 0, }, { name: NULL, }, }; +#define PART_BOOT 0 +#define PART_LINUX 1 +#define PART_ROOTFS 2 +#define PART_JFFS2 3 +#define PART_NVRAM 4 + struct mtd_partition * __init init_mtd_partitions(struct mtd_info *mtd, size_t size) { - struct minix_super_block *minixsb; - struct ext2_super_block *ext2sb; - struct romfs_super_block *romfsb; - struct cramfs_super *cramfsb; - struct squashfs_super_block *squashfsb; struct trx_header *trx; unsigned char buf[512]; - int off; -#ifdef MULTILANG_SUPPORT - struct lang_header *lang; /* for multilang */ - int off1; -#endif + size_t off; size_t len; + size_t trxsize; - minixsb = (struct minix_super_block *) buf; - ext2sb = (struct ext2_super_block *) buf; - romfsb = (struct romfs_super_block *) buf; - cramfsb = (struct cramfs_super *) buf; - squashfsb = (struct squashfs_super_block *) buf; - trx = (struct trx_header *) buf; -#ifdef MULTILANG_SUPPORT - lang = (struct lang_header *) buf; /* for multilang */ -#endif - - /* Look at every 64 KB boundary */ - for (off = 0; off < size; off += (64 * 1024)) { - memset(buf, 0xe5, sizeof(buf)); + bcm947xx_parts[PART_NVRAM].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize); + bcm947xx_parts[PART_NVRAM].size = size - bcm947xx_parts[PART_NVRAM].offset; - /* - * Read block 0 to test for romfs and cramfs superblock - */ - if (MTD_READ(mtd, off, sizeof(buf), &len, buf) || - len != sizeof(buf)) - continue; + trxsize = 0; + trx = (struct trx_header *) buf; + for (off = 0; off < size; off += mtd->erasesize) { + if ((MTD_READ(mtd, off, sizeof(buf), &len, buf)) || (len != sizeof(buf))) continue; - /* Try looking at TRX header for rootfs offset */ if (le32_to_cpu(trx->magic) == TRX_MAGIC) { - bcm947xx_parts[1].offset = off; - if (le32_to_cpu(trx->offsets[1]) > off) - off = le32_to_cpu(trx->offsets[1]); - continue; - } - - /* romfs is at block zero too */ - if (romfsb->word0 == ROMSB_WORD0 && - romfsb->word1 == ROMSB_WORD1) { - printk(KERN_NOTICE - "%s: romfs filesystem found at block %d\n", - mtd->name, off / BLOCK_SIZE); - goto done; - } - - /* so is cramfs */ - if (cramfsb->magic == CRAMFS_MAGIC) { - printk(KERN_NOTICE - "%s: cramfs filesystem found at block %d\n", - mtd->name, off / BLOCK_SIZE); - goto done; - } - - /* squashfs is at block zero too */ - if (squashfsb->s_magic == SQUASHFS_MAGIC) { - printk(KERN_NOTICE - "%s: squashfs filesystem found at block %d\n", - mtd->name, off / BLOCK_SIZE); - goto done; - } - - /* - * Read block 1 to test for minix and ext2 superblock - */ - if (MTD_READ(mtd, off + BLOCK_SIZE, sizeof(buf), &len, buf) || - len != sizeof(buf)) - continue; - - /* Try minix */ - if (minixsb->s_magic == MINIX_SUPER_MAGIC || - minixsb->s_magic == MINIX_SUPER_MAGIC2) { - printk(KERN_NOTICE - "%s: Minix filesystem found at block %d\n", - mtd->name, off / BLOCK_SIZE); - goto done; - } - - /* Try ext2 */ - if (ext2sb->s_magic == cpu_to_le16(EXT2_SUPER_MAGIC)) { - printk(KERN_NOTICE - "%s: ext2 filesystem found at block %d\n", - mtd->name, off / BLOCK_SIZE); - goto done; + bcm947xx_parts[PART_BOOT].size = off; + + bcm947xx_parts[PART_LINUX].offset = off; + bcm947xx_parts[PART_LINUX].size = bcm947xx_parts[PART_NVRAM].offset - off; + + trxsize = ROUNDUP(le32_to_cpu(trx->len), mtd->erasesize); // kernel + rootfs + + bcm947xx_parts[PART_ROOTFS].offset = trx->offsets[1] + off; + bcm947xx_parts[PART_ROOTFS].size = trxsize - trx->offsets[1]; + + bcm947xx_parts[PART_JFFS2].offset = off + trxsize; + bcm947xx_parts[PART_JFFS2].size = bcm947xx_parts[PART_NVRAM].offset - bcm947xx_parts[PART_JFFS2].offset; + break; } } - printk(KERN_NOTICE - "%s: Couldn't find valid ROM disk image\n", - mtd->name); - - done: -#if MULTILANG_SUPPORT -/* below for multilang */ - /* Look at every 64 KB boundary */ - for (off1 = 0; off1 < size; off1 += (64 * 1024)) { - memset(buf, 0xe5, sizeof(buf)); - - /* - * Read block 0 to test for romfs and cramfs superblock - */ - if (MTD_READ(mtd, off1, sizeof(buf), &len, buf) || - len != sizeof(buf)) - continue; - - /* Try looking at TRX header for rootfs offset */ - if (le32_to_cpu(trx->magic) == TRX_MAGIC) { - printk("le32_to_cpu(trx->magic)=0x%lx trx->magic=0x%lx\n", le32_to_cpu(trx->magic), trx->magic); - //bcm947xx_parts[1].offset = off1; - printk("bcm947xx_parts[1].offset=0x%lx trx->offsets[1]=0x%lx off\n", bcm947xx_parts[2].offset); - if (le32_to_cpu(trx->offsets[2]) > off1) { - off1 = le32_to_cpu(trx->offsets[2]); - printk("ok1 off1=0x%lx\n", off1); - } - continue; - } - - /* so is cramfs */ - if (cramfsb->magic == CRAMFS_MAGIC) { - printk(KERN_NOTICE - "%s: lang cramfs filesystem found at block %d (0x%lx)\n", - mtd->name, off1 / BLOCK_SIZE, off1); - goto done1; - } - - /* squashfs is at block zero too */ - if (squashfsb->s_magic == SQUASHFS_MAGIC) { - printk(KERN_NOTICE - "%s: lang squashfs filesystem found at block %d (0x%lx)\n", - mtd->name, off1 / BLOCK_SIZE, off1); - goto done1; - } - + if (trxsize == 0) { + // uh, now what... + printk(KERN_NOTICE "%s: Unable to find a valid linux partition\n", mtd->name); } -done1: - printk("off=0x%lx off1=0x%lx size=0x%lx\n", off, off1, size); - if(off1 == 0 || off1 == size ) - { - off1 = size - 0x60000; // 0x3d0000 only lang.js - printk("(Not Found Lang Block)off=0x%lx off1=0x%lx size=0x%lx\n", off, off1, size); + +#if 0 + int i; + for (i = 0; bcm947xx_parts[i].name; ++i) { + printk(KERN_NOTICE "%8x %8x (%8x) %s\n", + bcm947xx_parts[i].offset, + (bcm947xx_parts[i].offset + bcm947xx_parts[i].size) - 1, + bcm947xx_parts[i].size, + bcm947xx_parts[i].name); } -/* for multilang -> */ - bcm947xx_parts[4].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize); - bcm947xx_parts[4].size = size - bcm947xx_parts[4].offset; - printk("nvram: offset=0x%lx size=0x%lx\n", bcm947xx_parts[4].offset, bcm947xx_parts[4].size); - - bcm947xx_parts[3].offset = off1; - bcm947xx_parts[3].size = bcm947xx_parts[4].offset - bcm947xx_parts[3].offset; -/* <- for multilang */ -#else - /* Find and size nvram */ - bcm947xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize); - bcm947xx_parts[3].size = size - bcm947xx_parts[3].offset; #endif - /* Find and size rootfs */ - if (off < size) { - bcm947xx_parts[2].offset = off; - bcm947xx_parts[2].size = bcm947xx_parts[3].offset - bcm947xx_parts[2].offset; - } - - /* Size linux (kernel and rootfs) */ - bcm947xx_parts[1].size = bcm947xx_parts[3].offset - bcm947xx_parts[1].offset; - - /* Size pmon */ - bcm947xx_parts[0].size = bcm947xx_parts[1].offset - bcm947xx_parts[0].offset; return bcm947xx_parts; } + EXPORT_SYMBOL(init_mtd_partitions); #endif diff --git a/release/src/linux/linux/arch/mips/kernel/branch.c b/release/src/linux/linux/arch/mips/kernel/branch.c index 8165789c..738ae74f 100644 --- a/release/src/linux/linux/arch/mips/kernel/branch.c +++ b/release/src/linux/linux/arch/mips/kernel/branch.c @@ -170,7 +170,7 @@ int __compute_return_epc(struct pt_regs *regs) bit = (insn.i_format.rt >> 2); bit += (bit != 0); bit += 23; - switch (insn.i_format.rt) { + switch (insn.i_format.rt & 3) { case 0: /* bc1f */ case 2: /* bc1fl */ if (~fcr31 & (1 << bit)) diff --git a/release/src/linux/linux/arch/mips/kernel/mips_ksyms.c b/release/src/linux/linux/arch/mips/kernel/mips_ksyms.c index a76613d1..3f07ed47 100644 --- a/release/src/linux/linux/arch/mips/kernel/mips_ksyms.c +++ b/release/src/linux/linux/arch/mips/kernel/mips_ksyms.c @@ -52,6 +52,7 @@ EXPORT_SYMBOL(EISA_bus); */ EXPORT_SYMBOL_NOVERS(memcmp); EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL_NOVERS(memchr); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memmove); EXPORT_SYMBOL_NOVERS(strcat); diff --git a/release/src/linux/linux/arch/mips/math-emu/cp1emu.c b/release/src/linux/linux/arch/mips/math-emu/cp1emu.c index be1f732a..07f25d74 100644 --- a/release/src/linux/linux/arch/mips/math-emu/cp1emu.c +++ b/release/src/linux/linux/arch/mips/math-emu/cp1emu.c @@ -528,9 +528,8 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx) if (MIPSInst_FUNC(ir) != movc_op) return SIGILL; cond = fpucondbit[MIPSInst_RT(ir) >> 2]; - if (((ctx->sr & cond) != 0) != ((MIPSInst_RT(ir) & 1) != 0)) - return 0; - xcp->regs[MIPSInst_RD(ir)] = xcp->regs[MIPSInst_RS(ir)]; + if (((ctx->sr & cond) != 0) == ((MIPSInst_RT(ir) & 1) != 0)) + xcp->regs[MIPSInst_RD(ir)] = xcp->regs[MIPSInst_RS(ir)]; break; #endif diff --git a/release/src/linux/linux/drivers/char/serial.c b/release/src/linux/linux/drivers/char/serial.c index 287eda33..dd3d7de4 100644 --- a/release/src/linux/linux/drivers/char/serial.c +++ b/release/src/linux/linux/drivers/char/serial.c @@ -2861,9 +2861,9 @@ static void rs_close(struct tty_struct *tty, struct file * filp) info->event = 0; info->tty = 0; if (info->blocked_open) { - if (info->close_delay) { + if (state->close_delay) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(info->close_delay); + schedule_timeout(state->close_delay); } wake_up_interruptible(&info->open_wait); } diff --git a/release/src/linux/linux/drivers/mtd/chips/gen_probe.c b/release/src/linux/linux/drivers/mtd/chips/gen_probe.c index 4bed4f12..45ea742b 100644 --- a/release/src/linux/linux/drivers/mtd/chips/gen_probe.c +++ b/release/src/linux/linux/drivers/mtd/chips/gen_probe.c @@ -287,6 +287,7 @@ static struct mtd_info *check_cmd_set(struct map_info *map, int primary) #endif #ifdef CONFIG_MTD_CFI_AMDSTD case 0x0002: + case 0x0006: /* for Winbond W19L320SBT9C */ return cfi_cmdset_0002(map, primary); #endif #ifdef CONFIG_MTD_CFI_SSTSTD diff --git a/release/src/linux/linux/drivers/net/Config.in b/release/src/linux/linux/drivers/net/Config.in index 59de9c9e..9a79c778 100644 --- a/release/src/linux/linux/drivers/net/Config.in +++ b/release/src/linux/linux/drivers/net/Config.in @@ -8,6 +8,11 @@ source drivers/net/arcnet/Config.in tristate 'Dummy net driver support' CONFIG_DUMMY tristate 'Bonding driver support' CONFIG_BONDING tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER +if [ "$CONFIG_NETFILTER" = "y" ]; then + tristate 'IMQ (intermediate queueing device) support' CONFIG_IMQ +else + comment 'IMQ needs CONFIG_NETFILTER enabled' +fi tristate 'Universal TUN/TAP device driver support' CONFIG_TUN if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP diff --git a/release/src/linux/linux/drivers/net/Makefile b/release/src/linux/linux/drivers/net/Makefile index acdea2cf..adec92ce 100644 --- a/release/src/linux/linux/drivers/net/Makefile +++ b/release/src/linux/linux/drivers/net/Makefile @@ -30,13 +30,13 @@ subdir-m += diag #subdir-m += ext_io #subdir-m += ctmisc -ifeq ($(CONFIG_HW_QOS),y) -subdir-m += port_based_qos -else - ifeq ($(CONFIG_PERFORMANCE),y) - subdir-m += port_based_qos - endif -endif +# ifeq ($(CONFIG_HW_QOS),y) +# subdir-m += port_based_qos +# else +# ifeq ($(CONFIG_PERFORMANCE),y) +# subdir-m += port_based_qos +# endif +# endif ifeq ($(CONFIG_TULIP),y) obj-y += tulip/tulip.o @@ -174,6 +174,7 @@ endif obj-$(CONFIG_STRIP) += strip.o obj-$(CONFIG_DUMMY) += dummy.o +obj-$(CONFIG_IMQ) += imq.o obj-$(CONFIG_BONDING) += bonding.o obj-$(CONFIG_DE600) += de600.o obj-$(CONFIG_DE620) += de620.o diff --git a/release/src/linux/linux/drivers/net/hnd/shared_ksyms.sh b/release/src/linux/linux/drivers/net/hnd/shared_ksyms.sh index 7814f7f0..a4454bea 100644..100755 --- a/release/src/linux/linux/drivers/net/hnd/shared_ksyms.sh +++ b/release/src/linux/linux/drivers/net/hnd/shared_ksyms.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright 2005, Broadcom Corporation +# Copyright 2006, Broadcom Corporation # All Rights Reserved. # # THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY @@ -8,7 +8,7 @@ # SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. # -# $Id: shared_ksyms.sh,v 1.1.1.7 2005/03/07 07:30:48 kanki Exp $ +# $Id$ # cat <<EOF @@ -17,5 +17,5 @@ cat <<EOF EOF for file in $* ; do - ${NM} $file | sed -ne 's/[0-9A-Fa-f]* [DT] \([^ ]*\)/extern void \1; EXPORT_SYMBOL(\1);/p' + ${NM} $file | sed -ne 's/[0-9A-Fa-f]* [DRT] \([^ ]*\)/extern void \1; EXPORT_SYMBOL(\1);/p' done diff --git a/release/src/linux/linux/drivers/net/imq.c b/release/src/linux/linux/drivers/net/imq.c new file mode 100644 index 00000000..ac687dba --- /dev/null +++ b/release/src/linux/linux/drivers/net/imq.c @@ -0,0 +1,321 @@ +/* + * Pseudo-driver for the intermediate queue device. + * + * 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. + * + * Authors: Patrick McHardy, <kaber@trash.net> + * + * The first version was written by Martin Devera, <devik@cdi.cz> + * + * Credits: Jan Rafaj <imq2t@cedric.vabo.cz> + * - Update patch to 2.4.21 + * Sebastian Strollo <sstrollo@nortelnetworks.com> + * - Fix "Dead-loop on netdevice imq"-issue + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/config.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/rtnetlink.h> +#include <linux/if_arp.h> +#include <linux/netfilter.h> +#include <linux/netfilter_ipv4.h> +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) +#include <linux/netfilter_ipv6.h> +#endif +#include <linux/imq.h> +#include <net/pkt_sched.h> + +static nf_hookfn imq_nf_hook; + +static struct nf_hook_ops imq_ingress_ipv4 = { + { NULL, NULL}, + imq_nf_hook, + PF_INET, + NF_IP_PRE_ROUTING, + NF_IP_PRI_MANGLE + 1 +}; + +static struct nf_hook_ops imq_egress_ipv4 = { + { NULL, NULL}, + imq_nf_hook, + PF_INET, + NF_IP_POST_ROUTING, + NF_IP_PRI_LAST +}; + +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) +static struct nf_hook_ops imq_ingress_ipv6 = { + { NULL, NULL}, + imq_nf_hook, + PF_INET6, + NF_IP6_PRE_ROUTING, + NF_IP6_PRI_MANGLE + 1 +}; + +static struct nf_hook_ops imq_egress_ipv6 = { + { NULL, NULL}, + imq_nf_hook, + PF_INET6, + NF_IP6_POST_ROUTING, + NF_IP6_PRI_LAST +}; +#endif + +static unsigned int numdevs = 2; + +MODULE_PARM(numdevs, "i"); +MODULE_PARM_DESC(numdevs, "number of imq devices"); + +static struct net_device *imq_devs; + + +static struct net_device_stats *imq_get_stats(struct net_device *dev) +{ + return (struct net_device_stats *)dev->priv; +} + +/* called for packets kfree'd in qdiscs at places other than enqueue */ +static void imq_skb_destructor(struct sk_buff *skb) +{ + struct nf_info *info = skb->nf_info; + + if (info) { + if (info->indev) + dev_put(info->indev); + if (info->outdev) + dev_put(info->outdev); + kfree(info); + } +} + +static int imq_dev_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct net_device_stats *stats = (struct net_device_stats*) dev->priv; + + stats->tx_bytes += skb->len; + stats->tx_packets++; + + skb->imq_flags = 0; + skb->destructor = NULL; + + dev->trans_start = jiffies; + nf_reinject(skb, skb->nf_info, NF_ACCEPT); + return 0; +} + +static int imq_nf_queue(struct sk_buff *skb, struct nf_info *info, + void *data) +{ + struct net_device *dev; + struct net_device_stats *stats; + struct sk_buff *skb2 = NULL; + struct Qdisc *q; + unsigned int index = skb->imq_flags&IMQ_F_IFMASK; + int ret = -1; + + if (index > numdevs) + return -1; + + dev = imq_devs + index; + if (!(dev->flags & IFF_UP)) { + skb->imq_flags = 0; + nf_reinject(skb, info, NF_ACCEPT); + return 0; + } + dev->last_rx = jiffies; + + if (skb->destructor) { + skb2 = skb; + skb = skb_clone(skb, GFP_ATOMIC); + if (!skb) + return -1; + } + skb->nf_info = info; + + stats = (struct net_device_stats *)dev->priv; + stats->rx_bytes+= skb->len; + stats->rx_packets++; + + spin_lock_bh(&dev->queue_lock); + q = dev->qdisc; + if (q->enqueue) { + q->enqueue(skb_get(skb), q); + if (skb_shared(skb)) { + skb->destructor = imq_skb_destructor; + kfree_skb(skb); + ret = 0; + } + } + if (spin_is_locked(&dev->xmit_lock)) + netif_schedule(dev); + else + qdisc_run(dev); + spin_unlock_bh(&dev->queue_lock); + + if (skb2) + kfree_skb(ret ? skb : skb2); + + return ret; +} + +static unsigned int imq_nf_hook(unsigned int hook, struct sk_buff **pskb, + const struct net_device *indev, + const struct net_device *outdev, + int (*okfn)(struct sk_buff *)) +{ + if ((*pskb)->imq_flags & IMQ_F_ENQUEUE) + return NF_QUEUE; + + return NF_ACCEPT; +} + + +static int __init imq_init_hooks(void) +{ + int err; + + if ((err = nf_register_queue_handler(PF_INET, imq_nf_queue, NULL))) + goto err1; + if ((err = nf_register_hook(&imq_ingress_ipv4))) + goto err2; + if ((err = nf_register_hook(&imq_egress_ipv4))) + goto err3; +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) + if ((err = nf_register_queue_handler(PF_INET6, imq_nf_queue, NULL))) + goto err4; + if ((err = nf_register_hook(&imq_ingress_ipv6))) + goto err5; + if ((err = nf_register_hook(&imq_egress_ipv6))) + goto err6; +#endif + + return 0; + +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) +err6: + nf_unregister_hook(&imq_ingress_ipv6); +err5: + nf_unregister_queue_handler(PF_INET6); +err4: + nf_unregister_hook(&imq_egress_ipv4); +#endif +err3: + nf_unregister_hook(&imq_ingress_ipv4); +err2: + nf_unregister_queue_handler(PF_INET); +err1: + return err; +} + +static void __exit imq_unhook(void) +{ + nf_unregister_hook(&imq_ingress_ipv4); + nf_unregister_hook(&imq_egress_ipv4); + nf_unregister_queue_handler(PF_INET); +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) + nf_unregister_hook(&imq_ingress_ipv6); + nf_unregister_hook(&imq_egress_ipv6); + nf_unregister_queue_handler(PF_INET6); +#endif +} + +static int __init imq_dev_init(struct net_device *dev) +{ + dev->hard_start_xmit = imq_dev_xmit; + dev->type = ARPHRD_VOID; + dev->mtu = 1500; + dev->tx_queue_len = 30; + dev->flags = IFF_NOARP; + dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct net_device_stats)); + dev->get_stats = imq_get_stats; + + return 0; +} + +static void imq_dev_uninit(struct net_device *dev) +{ + kfree(dev->priv); +} + +static int __init imq_init_devs(void) +{ + struct net_device *dev; + int i; + + if (!numdevs || numdevs > IMQ_MAX_DEVS) { + printk(KERN_ERR "numdevs has to be betweed 1 and %u\n", + IMQ_MAX_DEVS); + return -EINVAL; + } + + imq_devs = kmalloc(sizeof(struct net_device) * numdevs, GFP_KERNEL); + if (!imq_devs) + return -ENOMEM; + memset(imq_devs, 0, sizeof(struct net_device) * numdevs); + + /* we start counting at zero */ + numdevs--; + + for (i = 0, dev = imq_devs; i <= numdevs; i++, dev++) { + SET_MODULE_OWNER(dev); + strcpy(dev->name, "imq%d"); + dev->init = imq_dev_init; + dev->uninit = imq_dev_uninit; + + if (register_netdev(dev) < 0) + goto err_register; + } + return 0; + +err_register: + for (; i; i--) + unregister_netdev(--dev); + kfree(imq_devs); + return -EIO; +} + +static void imq_cleanup_devs(void) +{ + int i; + struct net_device *dev = imq_devs; + + for (i = 0; i <= numdevs; i++) + unregister_netdev(dev++); + + kfree(imq_devs); +} + +static int __init imq_init_module(void) +{ + int err; + + if ((err = imq_init_devs())) + return err; + if ((err = imq_init_hooks())) { + imq_cleanup_devs(); + return err; + } + + printk(KERN_INFO "imq driver loaded.\n"); + + return 0; +} + +static void __exit imq_cleanup_module(void) +{ + imq_unhook(); + imq_cleanup_devs(); +} + +module_init(imq_init_module); +module_exit(imq_cleanup_module); +MODULE_LICENSE("GPL"); diff --git a/release/src/linux/linux/drivers/net/ppp_generic.c b/release/src/linux/linux/drivers/net/ppp_generic.c index 3a4e0fb8..ed4e243a 100644 --- a/release/src/linux/linux/drivers/net/ppp_generic.c +++ b/release/src/linux/linux/drivers/net/ppp_generic.c @@ -221,7 +221,7 @@ static atomic_t channel_count = ATOMIC_INIT(0); #define DST_PORT(skb) (((skb)->data[24] << 8) + (skb)->data[25]) #define MARK_LAN2WAN 0x100 //#define myprintk(fmt, args...) printk(fmt, ## args) -#define myprintk(fmt, args...) +#define myprintk(fmt, args...) /* We limit the length of ppp->file.rq to this (arbitrary) value */ @@ -301,7 +301,7 @@ static const int npindex_to_proto[NUM_NP] = { PPP_IPX, PPP_AT, }; - + /* Translates an ethertype into an NP index */ static inline int ethertype_to_npindex(int ethertype) { @@ -987,6 +987,34 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) ppp->last_xmit = jiffies; skb_pull(skb, 2); #else + +#if 1 // zzz + switch (IP_PROTO(skb)) { + case 6: // TCP + switch (DST_PORT(skb)) { + case 139: // netbios-ssn + case 445: // microsoft-ds + break; + default: + ppp->last_xmit = jiffies; + break; + } + break; + case 17: // UDP + switch (DST_PORT(skb)) { + case 137: // netbios-ns + case 138: // netbios-dgm + break; + default: + ppp->last_xmit = jiffies; + break; + } + break; + default: + ppp->last_xmit = jiffies; + break; + } +#else /* for data packets, record the time */ myprintk(KERN_DEBUG "PPP: (%ld) send nfmark=[%lx] proto[%d] port[%d -> %d]\n", jiffies, @@ -1007,7 +1035,8 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) } else myprintk(KERN_DEBUG "PPP: No reset timer\n"); - +#endif + #endif /* CONFIG_PPP_FILTER */ } @@ -1543,7 +1572,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) //else if(UDP_PORT(skb) == 138){ // printk(KERN_DEBUG " Skip NETBIOS Datagram Service packet\n"); //} - //else if(IP_PROTO(skb) == 2){ + //else if(IP_PROTO(skb) == 2){ // printk(KERN_DEBUG " Skip IGMP packet\n"); //} //else @@ -2053,7 +2082,7 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound) switch (CCP_CODE(dp)) { case CCP_CONFREQ: - /* A ConfReq starts negotiation of compression + /* A ConfReq starts negotiation of compression * in one direction of transmission, * and hence brings it down...but which way? * @@ -2063,16 +2092,16 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound) if(inbound) /* He is proposing what I should send */ ppp->xstate &= ~SC_COMP_RUN; - else + else /* I am proposing to what he should send */ ppp->rstate &= ~SC_DECOMP_RUN; - + break; - + case CCP_TERMREQ: case CCP_TERMACK: /* - * CCP is going down, both directions of transmission + * CCP is going down, both directions of transmission */ ppp->rstate &= ~SC_DECOMP_RUN; ppp->xstate &= ~SC_COMP_RUN; diff --git a/release/src/linux/linux/fs/Config.in b/release/src/linux/linux/fs/Config.in index 1c4628a6..f535df59 100644 --- a/release/src/linux/linux/fs/Config.in +++ b/release/src/linux/linux/fs/Config.in @@ -48,13 +48,20 @@ if [ "$CONFIG_JFFS2_FS" = "y" -o "$CONFIG_JFFS2_FS" = "m" ] ; then fi tristate 'Compressed ROM file system support' CONFIG_CRAMFS tristate 'Squashed file system support' CONFIG_SQUASHFS +if [ "$CONFIG_SQUASHFS" = "y" -o "$CONFIG_SQUASHFS" = "m" ] ; then +bool 'Additional options for memory constrained systems ' CONFIG_SQUASHFS_EMBEDDED +fi +if [ "$CONFIG_SQUASHFS_EMBEDDED" = "y" ] ; then +int 'Number of fragments cached' CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE 3 +bool 'Use Vmalloc rather than Kmalloc' CONFIG_SQUASHFS_VMALLOC +fi bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS define_bool CONFIG_RAMFS y -if [ "$CONFIG_CRAMFS" = "y" -o "$CONFIG_CRAMFS" = "m" ] ; then +if [ "$CONFIG_CRAMFS" = "y" -o "$CONFIG_CRAMFS" = "m" -o "$CONFIG_SQUASHFS" = "y" -o "$CONFIG_SQUASHFS" = "m" ] ; then choice 'Compression method' \ "ZLIB CONFIG_ZLIB_FS_INFLATE \ - LZMA CONFIG_LZMA_FS_INFLATE" ZLIB + LZMA CONFIG_LZMA_FS_INFLATE" LZMA fi tristate 'ISO 9660 CDROM file system support' CONFIG_ISO9660_FS @@ -131,6 +138,10 @@ if [ "$CONFIG_NET" = "y" ]; then define_bool CONFIG_LOCKD_V4 y fi + dep_tristate 'CIFS support (advanced network filesystem for Samba, Window and other CIFS compliant servers)' CONFIG_CIFS $CONFIG_INET + dep_mbool ' CIFS statistics' CONFIG_CIFS_STATS $CONFIG_CIFS + dep_mbool ' CIFS POSIX Protocol Extensions' CONFIG_CIFS_POSIX $CONFIG_CIFS + dep_tristate 'SMB file system support (to mount Windows shares etc.)' CONFIG_SMB_FS $CONFIG_INET if [ "$CONFIG_SMB_FS" != "n" ]; then bool ' Use a default NLS' CONFIG_SMB_NLS_DEFAULT diff --git a/release/src/linux/linux/fs/Makefile b/release/src/linux/linux/fs/Makefile index 7d05f77f..951a6125 100644 --- a/release/src/linux/linux/fs/Makefile +++ b/release/src/linux/linux/fs/Makefile @@ -40,6 +40,7 @@ subdir-$(CONFIG_MSDOS_FS) += msdos subdir-$(CONFIG_VFAT_FS) += vfat subdir-$(CONFIG_BFS_FS) += bfs subdir-$(CONFIG_ISO9660_FS) += isofs +subdir-$(CONFIG_CIFS) += cifs subdir-$(CONFIG_DEVFS_FS) += devfs subdir-$(CONFIG_HFS_FS) += hfs subdir-$(CONFIG_VXFS_FS) += freevxfs @@ -67,8 +68,8 @@ subdir-$(CONFIG_REISERFS_FS) += reiserfs subdir-$(CONFIG_DEVPTS_FS) += devpts subdir-$(CONFIG_SUN_OPENPROMFS) += openpromfs subdir-$(CONFIG_BEFS_FS) += befs -subdir-$(CONFIG_JFS_FS) += jfs subdir-$(CONFIG_SQUASHFS) += squashfs +subdir-$(CONFIG_JFS_FS) += jfs obj-$(CONFIG_BINFMT_AOUT) += binfmt_aout.o diff --git a/release/src/linux/linux/fs/buffer.c b/release/src/linux/linux/fs/buffer.c index 9ec1b055..3a691eeb 100644 --- a/release/src/linux/linux/fs/buffer.c +++ b/release/src/linux/linux/fs/buffer.c @@ -1824,7 +1824,7 @@ out: * We may have to extend the file. */ -int cont_prepare_write(struct page *page, unsigned offset, unsigned to, get_block_t *get_block, unsigned long *bytes) +int cont_prepare_write(struct page *page, unsigned offset, unsigned to, get_block_t *get_block, loff_t *bytes) { struct address_space *mapping = page->mapping; struct inode *inode = mapping->host; @@ -2808,6 +2808,8 @@ void wakeup_bdflush(void) wake_up_interruptible(&bdflush_wait); } +EXPORT_SYMBOL(wakeup_bdflush); + /* * Here we attempt to write back old buffers. We also try to flush inodes * and supers as well, since this function is essentially "update", and @@ -3009,4 +3011,3 @@ static int __init bdflush_init(void) } module_init(bdflush_init) - diff --git a/release/src/linux/linux/fs/cifs/AUTHORS b/release/src/linux/linux/fs/cifs/AUTHORS new file mode 100644 index 00000000..43a7b653 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/AUTHORS @@ -0,0 +1,37 @@ +Original Author +=============== +Steve French (sfrench@samba.org) + +The author wishes to express his appreciation and thanks to: +Andrew Tridgell (Samba team) for his early suggestions about smb/cifs VFS +improvements. Thanks to IBM for allowing me the time and test resources to pursue +this project. Jim McDonough from IBM (and the Samba Team) for his help. +The IBM Linux JFS team for explaining many esoteric Linux filesystem features. +Dave Boutcher of IBM Rochester (author of the OS/400 smb/cifs filesystem client) +for proving years ago that a very good smb/cifs client could be done on a Unix like +operating system. Volker Lendecke, Andrew Tridgell, Urban Widmark, John Newbigin +and others for their work on the Linux smbfs module over the years. Thanks to +the other members of the Storage Network Industry Association CIFS Technical +Workgroup for their work specifying this highly complex protocol and finally +thanks to the Samba team for their technical advice and encouragement. + +Patch Contributors +------------------ +Zwane Mwaikambo +Andi Kleen +Amrut Joshi +Shobhit Dayal +Sergey Vlasov +Richard Hughes +Yury Umanets + +Test case and Bug Report contributors +------------------------------------- +Thanks to those in the community who have submitted detailed bug reports +and debug of problems they have found: Jochen Dolze, David Blaine, +Rene Scharfe, Martin Josefsson, Alexander Wild, Anthony Liguori, +Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen, +Olaf Kirch, Kieron Briggs, Nick Millington and others. + +And thanks to the IBM LTC and Power test teams and SuSE testers for +finding multiple bugs during excellent stress test runs. diff --git a/release/src/linux/linux/fs/cifs/CHANGES b/release/src/linux/linux/fs/cifs/CHANGES new file mode 100644 index 00000000..3f166375 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/CHANGES @@ -0,0 +1,572 @@ +Version 1.20 +------------ +Make transaction counts more consistent. Merge /proc/fs/cifs/SimultaneousOps +info into /proc/fs/cifs/DebugData. Fix oops in rare oops in readdir +(in build_wildcard_path_from_dentry). Fix mknod to pass type field +(block/char/fifo) properly. Remove spurious mount warning log entry when +credentials passed as mount argument. Set major/minor device number in +inode for block and char devices when unix extensions enabled. + +Version 1.19 +------------ +Fix /proc/fs/cifs/Stats and DebugData display to handle larger +amounts of return data. Properly limit requests to MAX_REQ (50 +is the usual maximum active multiplex SMB/CIFS requests per server). +Do not kill cifsd (and thus hurt the other SMB session) when more than one +session to the same server (but with different userids) exists and one +of the two user's smb sessions is being removed while leaving the other. +Do not loop reconnecting in cifsd demultiplex thread when admin +kills the thread without going through unmount. + +Version 1.18 +------------ +Do not rename hardlinked files (since that should be a noop). Flush +cached write behind data when reopening a file after session abend, +except when already in write. Grab per socket sem during reconnect +to avoid oops in sendmsg if overlapping with reconnect. Do not +reset cached inode file size on readdir for files open for write on +client. + + +Version 1.17 +------------ +Update number of blocks in file so du command is happier (in Linux a fake +blocksize of 512 is required for calculating number of blocks in inode). +Fix prepare write of partial pages to read in data from server if possible. +Fix race on tcpStatus field between unmount and reconnection code, causing +cifsd process sometimes to hang around forever. Improve out of memory +checks in cifs_filldir + +Version 1.16 +------------ +Fix incorrect file size in file handle based setattr on big endian hardware. +Fix oops in build_path_from_dentry when out of memory. Add checks for invalid +and closing file structs in writepage/partialpagewrite. Add statistics +for each mounted share (new menuconfig option). Fix endianness problem in +volume information displayed in /proc/fs/cifs/DebugData (only affects +affects big endian architectures). Prevent renames while constructing +path names for open, mkdir and rmdir. + +Version 1.15 +------------ +Change to mempools for alloc smb request buffers and multiplex structs +to better handle low memory problems (and potential deadlocks). + +Version 1.14 +------------ +Fix incomplete listings of large directories on Samba servers when Unix +extensions enabled. Fix oops when smb_buffer can not be allocated. Fix +rename deadlock when writing out dirty pages at same time. + +Version 1.13 +------------ +Fix open of files in which O_CREATE can cause the mode to change in +some cases. Fix case in which retry of write overlaps file close. +Fix PPC64 build error. Reduce excessive stack usage in smb password +hashing. Fix overwrite of Linux user's view of file mode to Windows servers. + +Version 1.12 +------------ +Fixes for large file copy, signal handling, socket retry, buffer +allocation and low memory situations. + +Version 1.11 +------------ +Better port 139 support to Windows servers (RFC1001/RFC1002 Session_Initialize) +also now allowing support for specifying client netbiosname. NT4 support added. + +Version 1.10 +------------ +Fix reconnection (and certain failed mounts) to properly wake up the +blocked users thread so it does not seem hung (in some cases was blocked +until the cifs receive timeout expired). Fix spurious error logging +to kernel log when application with open network files killed. + +Version 1.09 +------------ +Fix /proc/fs module unload warning message (that could be logged +to the kernel log). Fix intermittent failure in connectathon +test7 (hardlink count not immediately refreshed in case in which +inode metadata can be incorrectly kept cached when time near zero) + +Version 1.08 +------------ +Allow file_mode and dir_mode (specified at mount time) to be enforced +locally (the server already enforced its own ACLs too) for servers +that do not report the correct mode (do not support the +CIFS Unix Extensions). + +Version 1.07 +------------ +Fix some small memory leaks in some unmount error paths. Fix major leak +of cache pages in readpages causing multiple read oriented stress +testcases (including fsx, and even large file copy) to fail over time. + +Version 1.06 +------------ +Send NTCreateX with ATTR_POSIX if Linux/Unix extensions negotiated with server. +This allows files that differ only in case and improves performance of file +creation and file open to such servers. Fix semaphore conflict which causes +slow delete of open file to Samba (which unfortunately can cause an oplock +break to self while vfs_unlink held i_sem) which can hang for 20 seconds. + +Version 1.05 +------------ +fixes to cifs_readpages for fsx test case + +Version 1.04 +------------ +Fix caching data integrity bug when extending file size especially when no +oplock on file. Fix spurious logging of valid already parsed mount options +that are parsed outside of the cifs vfs such as nosuid. + + +Version 1.03 +------------ +Connect to server when port number override not specified, and tcp port +unitialized. Reset search to restart at correct file when kernel routine +filldir returns error during large directory searches (readdir). + +Version 1.02 +------------ +Fix caching problem when files opened by multiple clients in which +page cache could contain stale data, and write through did +not occur often enough while file was still open when read ahead +(read oplock) not allowed. Treat "sep=" when first mount option +as an overrride of comma as the default separator between mount +options. + +Version 1.01 +------------ +Allow passwords longer than 16 bytes. Allow null password string. + +Version 1.00 +------------ +Gracefully clean up failed mounts when attempting to mount to servers such as +Windows 98 that terminate tcp sessions during prototocol negotiation. Handle +embedded commas in mount parsing of passwords. + +Version 0.99 +------------ +Invalidate local inode cached pages on oplock break and when last file +instance is closed so that the client does not continue using stale local +copy rather than later modified server copy of file. Do not reconnect +when server drops the tcp session prematurely before negotiate +protocol response. Fix oops in roepen_file when dentry freed. Allow +the support for CIFS Unix Extensions to be disabled via proc interface. + +Version 0.98 +------------ +Fix hang in commit_write during reconnection of open files under heavy load. +Fix unload_nls oops in a mount failure path. Serialize writes to same socket +which also fixes any possible races when cifs signatures are enabled in SMBs +being sent out of signature sequence number order. + +Version 0.97 +------------ +Fix byte range locking bug (endian problem) causing bad offset and +length. + +Version 0.96 +------------ +Fix oops (in send_sig) caused by CIFS unmount code trying to +wake up the demultiplex thread after it had exited. Do not log +error on harmless oplock release of closed handle. + +Version 0.95 +------------ +Fix unsafe global variable usage and password hash failure on gcc 3.3.1 +Fix problem reconnecting secondary mounts to same server after session +failure. Fix invalid dentry - race in mkdir when directory gets created +by another client between the lookup and mkdir. + +Version 0.94 +------------ +Fix to list processing in reopen_files. Fix reconnection when server hung +but tcpip session still alive. Set proper timeout on socket read. + +Version 0.93 +------------ +Add missing mount options including iocharset. SMP fixes in write and open. +Fix errors in reconnecting after TCP session failure. Fix module unloading +of default nls codepage + +Version 0.92 +------------ +Active smb transactions should never go negative (fix double FreeXid). Fix +list processing in file routines. Check return code on kmalloc in open. +Fix spinlock usage for SMP. + +Version 0.91 +------------ +Fix oops in reopen_files when invalid dentry. drop dentry on server rename +and on revalidate errors. Fix cases where pid is now tgid. Fix return code +on create hard link when server does not support them. + +Version 0.90 +------------ +Fix scheduling while atomic error in getting inode info on newly created file. +Fix truncate of existing files opened with O_CREAT but not O_TRUNC set. + +Version 0.89 +------------ +Fix oops on write to dead tcp session. Remove error log write for case when file open +O_CREAT but not O_EXCL + +Version 0.88 +------------ +Fix non-POSIX behavior on rename of open file and delete of open file by taking +advantage of trans2 SetFileInfo rename facility if available on target server. +Retry on ENOSPC and EAGAIN socket errors. + +Version 0.87 +------------ +Fix oops on big endian readdir. Set blksize to be even power of two (2**blkbits) to fix +allocation size miscalculation. After oplock token lost do not read through +cache. + +Version 0.86 +------------ +Fix oops on empty file readahead. Fix for file size handling for locally cached files. + +Version 0.85 +------------ +Fix oops in mkdir when server fails to return inode info. Fix oops in reopen_files +during auto reconnection to server after server recovered from failure. + +Version 0.84 +------------ +Finish support for Linux 2.5 open/create changes, which removes the +redundant NTCreate/QPathInfo/close that was sent during file create. +Enable oplock by default. Enable packet signing by default (needed to +access many recent Windows servers) + +Version 0.83 +------------ +Fix oops when mounting to long server names caused by inverted parms to kmalloc. +Fix MultiuserMount (/proc/fs/cifs configuration setting) so that when enabled +we will choose a cifs user session (smb uid) that better matches the local +uid if a) the mount uid does not match the current uid and b) we have another +session to the same server (ip address) for a different mount which +matches the current local uid. + +Version 0.82 +------------ +Add support for mknod of block or character devices. Fix oplock +code (distributed caching) to properly send response to oplock +break from server. + +Version 0.81 +------------ +Finish up CIFS packet digital signing for the default +NTLM security case. This should help Windows 2003 +network interoperability since it is common for +packet signing to be required now. Fix statfs (stat -f) +which recently started returning errors due to +invalid value (-1 instead of 0) being set in the +struct kstatfs f_ffiles field. + +Version 0.80 +----------- +Fix oops on stopping oplock thread when removing cifs when +built as module. + +Version 0.79 +------------ +Fix mount options for ro (readonly), uid, gid and file and directory mode. + +Version 0.78 +------------ +Fix errors displayed on failed mounts to be more understandable. +Fixed various incorrect or misleading smb to posix error code mappings. + +Version 0.77 +------------ +Fix display of NTFS DFS junctions to display as symlinks. +They are the network equivalent. Fix oops in +cifs_partialpagewrite caused by missing spinlock protection +of openfile linked list. Allow writebehind caching errors to +be returned to the application at file close. + +Version 0.76 +------------ +Clean up options displayed in /proc/mounts by show_options to +be more consistent with other filesystems. + +Version 0.75 +------------ +Fix delete of readonly file to Windows servers. Reflect +presence or absence of read only dos attribute in mode +bits for servers that do not support CIFS Unix extensions. +Fix shortened results on readdir of large directories to +servers supporting CIFS Unix extensions (caused by +incorrect resume key). + +Version 0.74 +------------ +Fix truncate bug (set file size) that could cause hangs e.g. running fsx + +Version 0.73 +------------ +unload nls if mount fails. + +Version 0.72 +------------ +Add resume key support to search (readdir) code to workaround +Windows bug. Add /proc/fs/cifs/LookupCacheEnable which +allows disabling caching of attribute information for +lookups. + +Version 0.71 +------------ +Add more oplock handling (distributed caching code). Remove +dead code. Remove excessive stack space utilization from +symlink routines. + +Version 0.70 +------------ +Fix oops in get dfs referral (triggered when null path sent in to +mount). Add support for overriding rsize at mount time. + +Version 0.69 +------------ +Fix buffer overrun in readdir which caused intermittent kernel oopses. +Fix writepage code to release kmap on write data. Allow "-ip=" new +mount option to be passed in on parameter distinct from the first part +(server name portion of) the UNC name. Allow override of the +tcp port of the target server via new mount option "-port=" + +Version 0.68 +------------ +Fix search handle leak on rewind. Fix setuid and gid so that they are +reflected in the local inode immediately. Cleanup of whitespace +to make 2.4 and 2.5 versions more consistent. + + +Version 0.67 +------------ +Fix signal sending so that captive thread (cifsd) exits on umount +(which was causing the warning in kmem_cache_free of the request buffers +at rmmod time). This had broken as a sideeffect of the recent global +kernel change to daemonize. Fix memory leak in readdir code which +showed up in "ls -R" (and applications that did search rewinding). + +Version 0.66 +------------ +Reconnect tids and fids after session reconnection (still do not +reconnect byte range locks though). Fix problem caching +lookup information for directory inodes, improving performance, +especially in deep directory trees. Fix various build warnings. + +Version 0.65 +------------ +Finish fixes to commit write for caching/readahead consistency. fsx +now works to Samba servers. Fix oops caused when readahead +was interrupted by a signal. + +Version 0.64 +------------ +Fix data corruption (in partial page after truncate) that caused fsx to +fail to Windows servers. Cleaned up some extraneous error logging in +common error paths. Add generic sendfile support. + +Version 0.63 +------------ +Fix memory leak in AllocMidQEntry. +Finish reconnection logic, so connection with server can be dropped +(or server rebooted) and the cifs client will reconnect. + +Version 0.62 +------------ +Fix temporary socket leak when bad userid or password specified +(or other SMBSessSetup failure). Increase maximum buffer size to slightly +over 16K to allow negotiation of up to Samba and Windows server default read +sizes. Add support for readpages + +Version 0.61 +------------ +Fix oops when username not passed in on mount. Extensive fixes and improvements +to error logging (strip redundant newlines, change debug macros to ensure newline +passed in and to be more consistent). Fix writepage wrong file handle problem, +a readonly file handle could be incorrectly used to attempt to write out +file updates through the page cache to multiply open files. This could cause +the iozone benchmark to fail on the fwrite test. Fix bug mounting two different +shares to the same Windows server when using different usernames +(doing this to Samba servers worked but Windows was rejecting it) - now it is +possible to use different userids when connecting to the same server from a +Linux client. Fix oops when treeDisconnect called during unmount on +previously freed socket. + +Version 0.60 +------------ +Fix oops in readpages caused by not setting address space operations in inode in +rare code path. + +Version 0.59 +------------ +Includes support for deleting of open files and renaming over existing files (per POSIX +requirement). Add readlink support for Windows junction points (directory symlinks). + +Version 0.58 +------------ +Changed read and write to go through pagecache. Added additional address space operations. +Memory mapped operations now working. + +Version 0.57 +------------ +Added writepage code for additional memory mapping support. Fixed leak in xids causing +the simultaneous operations counter (/proc/fs/cifs/SimultaneousOps) to increase on +every stat call. Additional formatting cleanup. + +Version 0.56 +------------ +Fix bigendian bug in order of time conversion. Merge 2.5 to 2.4 version. Formatting cleanup. + +Version 0.55 +------------ +Fixes from Zwane Mwaikambo for adding missing return code checking in a few places. +Also included a modified version of his fix to protect global list manipulation of +the smb session and tree connection and mid related global variables. + +Version 0.54 +------------ +Fix problem with captive thread hanging around at unmount time. Adjust to 2.5.42-pre +changes to superblock layout. Remove wasteful allocation of smb buffers (now the send +buffer is reused for responses). Add more oplock handling. Additional minor cleanup. + +Version 0.53 +------------ +More stylistic updates to better match kernel style. Add additional statistics +for filesystem which can be viewed via /proc/fs/cifs. Add more pieces of NTLMv2 +and CIFS Packet Signing enablement. + +Version 0.52 +------------ +Replace call to sleep_on with safer wait_on_event. +Make stylistic changes to better match kernel style recommendations. +Remove most typedef usage (except for the PDUs themselves). + +Version 0.51 +------------ +Update mount so the -unc mount option is no longer required (the ip address can be specified +in a UNC style device name. Implementation of readpage/writepage started. + +Version 0.50 +------------ +Fix intermittent problem with incorrect smb header checking on badly +fragmented tcp responses + +Version 0.49 +------------ +Fixes to setting of allocation size and file size. + +Version 0.48 +------------ +Various 2.5.38 fixes. Now works on 2.5.38 + +Version 0.47 +------------ +Prepare for 2.5 kernel merge. Remove ifdefs. + +Version 0.46 +------------ +Socket buffer management fixes. Fix dual free. + +Version 0.45 +------------ +Various big endian fixes for hardlinks and symlinks and also for dfs. + +Version 0.44 +------------ +Various big endian fixes for servers with Unix extensions such as Samba + +Version 0.43 +------------ +Various FindNext fixes for incorrect filenames on large directory searches on big endian +clients. basic posix file i/o tests now work on big endian machines, not just le + +Version 0.42 +------------ +SessionSetup and NegotiateProtocol now work from Big Endian machines. +Various Big Endian fixes found during testing on the Linux on 390. Various fixes for compatibility with older +versions of 2.4 kernel (now builds and works again on kernels at least as early as 2.4.7). + +Version 0.41 +------------ +Various minor fixes for Connectathon Posix "basic" file i/o test suite. Directory caching fixed so hardlinked +files now return the correct rumber of links on fstat as they are repeatedly linked and unlinked. + +Version 0.40 +------------ +Implemented "Raw" (i.e. not encapsulated in SPNEGO) NTLMSSP (i.e. the Security Provider Interface used to negotiate +session advanced session authentication). Raw NTLMSSP is preferred by Windows 2000 Professional and Windows XP. +Began implementing support for SPNEGO encapsulation of NTLMSSP based session authentication blobs +(which is the mechanism preferred by Windows 2000 server in the absence of Kerberos). + +Version 0.38 +------------ +Introduced optional mount helper utility mount.cifs and made coreq changes to cifs vfs to enable +it. Fixed a few bugs in the DFS code (e.g. bcc two bytes too short and incorrect uid in PDU). + +Version 0.37 +------------ +Rewrote much of connection and mount/unmount logic to handle bugs with +multiple uses to same share, multiple users to same server etc. + +Version 0.36 +------------ +Fixed major problem with dentry corruption (missing call to dput) + +Version 0.35 +------------ +Rewrite of readdir code to fix bug. Various fixes for bigendian machines. +Begin adding oplock support. Multiusermount and oplockEnabled flags added to /proc/fs/cifs +although corresponding function not fully implemented in the vfs yet + +Version 0.34 +------------ +Fixed dentry caching bug, misc. cleanup + +Version 0.33 +------------ +Fixed 2.5 support to handle build and configure changes as well as misc. 2.5 changes. Now can build +on current 2.5 beta version (2.5.24) of the Linux kernel as well as on 2.4 Linux kernels. +Support for STATUS codes (newer 32 bit NT error codes) added. DFS support begun to be added. + +Version 0.32 +------------ +Unix extensions (symlink, readlink, hardlink, chmod and some chgrp and chown) implemented +and tested against Samba 2.2.5 + + +Version 0.31 +------------ +1) Fixed lockrange to be correct (it was one byte too short) + +2) Fixed GETLK (i.e. the fcntl call to test a range of bytes in a file to see if locked) to correctly +show range as locked when there is a conflict with an existing lock. + +3) default file perms are now 2767 (indicating support for mandatory locks) instead of 777 for directories +in most cases. Eventually will offer optional ability to query server for the correct perms. + +3) Fixed eventual trap when mounting twice to different shares on the same server when the first succeeded +but the second one was invalid and failed (the second one was incorrectly disconnecting the tcp and smb +session) + +4) Fixed error logging of valid mount options + +5) Removed logging of password field. + +6) Moved negotiate, treeDisconnect and uloggoffX (only tConx and SessSetup remain in connect.c) to cifssmb.c +and cleaned them up and made them more consistent with other cifs functions. + +7) Server support for Unix extensions is now fully detected and FindFirst is implemented both ways +(with or without Unix exentions) but FindNext and QueryPathInfo with the Unix extensions are not completed, +nor is the symlink support using the Unix extensions + +8) Started adding the readlink and follow_link code + +Version 0.3 +----------- +Initial drop + diff --git a/release/src/linux/linux/fs/cifs/Makefile b/release/src/linux/linux/fs/cifs/Makefile new file mode 100644 index 00000000..892af0ce --- /dev/null +++ b/release/src/linux/linux/fs/cifs/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for Linux CIFS VFS client +# +O_TARGET := cifs.o + +obj-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o cifsencrypt.o + +obj-m := $(O_TARGET) + +include $(TOPDIR)/Rules.make diff --git a/release/src/linux/linux/fs/cifs/README b/release/src/linux/linux/fs/cifs/README new file mode 100644 index 00000000..59a00eea --- /dev/null +++ b/release/src/linux/linux/fs/cifs/README @@ -0,0 +1,356 @@ +The CIFS VFS support for Linux supports many advanced network filesystem +features such as heirarchical dfs like namespace, hardlinks, locking and more. +It was designed to comply with the SNIA CIFS Technical Reference (which +supersedes the 1992 X/Open SMB Standard) as well as to perform best practice +practical interoperability with Windows 2000, Windows XP, Samba and equivalent +servers. + +For questions or bug reports please contact: + sfrench@samba.org (sfrench@us.ibm.com) + +Build instructions: +================== +For Linux 2.4: +1) Get the kernel source (e.g.from http://www.kernel.org) +and download the cifs vfs source (see the project page +at http://us1.samba.org/samba/Linux_CIFS_client.html) +and change directory into the top of the kernel directory +then patch the kernel (e.g. "patch -p1 < cifs_24.patch") +to add the cifs vfs to your kernel configure options if +it has not already been added (e.g. current SuSE and UL +users do not need to apply the cifs_24.patch since the cifs vfs is +already in the kernel configure menu) and then +mkdir linux/fs/cifs and then copy the current cifs vfs files from +the cifs download to your kernel build directory e.g. + + cp <cifs_download_dir>/fs/cifs/* to <kernel_download_dir>/fs/cifs + +2) make menuconfig (or make xconfig) +3) select cifs from within the network filesystem choices +4) save and exit +5) make dep +6) make modules (or "make" if CIFS VFS not to be built as a module) + +For Linux 2.5: +1) Download the kernel (e.g. from http://www.kernel.org or from bitkeeper +at bk://linux.bkbits.net/linux-2.5) and change directory into the top +of the kernel directory tree (e.g. /usr/src/linux-2.5.73) +2) make menuconfig (or make xconfig) +3) select cifs from within the network filesystem choices +4) save and exit +5) make + + +Installation instructions: +========================= +If you have built the CIFS vfs as module (successfully) simply +type "make modules_install" (or if you prefer, manually copy the file to +the modules directory e.g. /lib/modules/2.4.10-4GB/kernel/fs/cifs/cifs.o). + +If you have built the CIFS vfs into the kernel itself, follow the instructions +for your distribution on how to install a new kernel (usually you +would simply type "make install"). + +If you do not have the utility mount.cifs (in the Samba 3.0 source tree and on +the CIFS VFS web site) copy it to the same directory in which mount.smbfs and +similar files reside (usually /sbin). Although the helper software is not +required, mount.cifs is recommended. Eventually the Samba 3.0 utility program +"net" may also be helpful since it may someday provide easier mount syntax for +users who are used to Windows e.g. net use <mount point> <UNC name or cifs URL> +Note that running the Winbind pam/nss module (logon service) on all of your +Linux clients is useful in mapping Uids and Gids consistently across the +domain to the proper network user. The mount.cifs mount helper can be +trivially built from Samba 3.0 or later source e.g. by executing: + + gcc samba/source/client/mount.cifs.c -o mount.cifs + +Note that when the mount.cifs utility is run suid (allowing user mounts), +in order to reduce risks, the "nosuid" mount flag is passed in on mount to +disallow execution of an suid program mounted on the remote target. +When mount is executed as root, nosuid is not passed in by default, +and execution of suid programs on the remote target would be enabled +by default. This can be changed, as with nfs and other filesystems, +by simply specifying "nosuid" among the mount options. For user mounts +though to be able to pass the suid flag to mount requires rebuilding +mount.cifs with the following flag: + + gcc samba/source/client/mount.cifs.c -DCIFS_ALLOW_USR_SUID -o mount.cifs + +There is a corresponding manual page for cifs mounting in the Samba 3.0 and +later source tree in docs/manpages/mount.cifs.8 + +Samba Considerations +==================== +To get the maximum benefit from the CIFS VFS, we recommend using a server that +supports the SNIA CIFS Unix Extensions standard (e.g. Samba 2.2.5 or later or +Samba 3.0) but the CIFS vfs works fine with a wide variety of CIFS servers. +Note that uid, gid and file permissions will display default values if you do +not have a server that supports the Unix extensions for CIFS (such as Samba +2.2.5 or later). To enable the Unix CIFS Extensions in the Samba server, add +the line: + + unix extensions = yes + +to your smb.conf file on the server. Note that the following smb.conf settings +are also useful (on the Samba server) when the majority of clients are Unix or +Linux: + + case sensitive = yes + delete readonly = yes + ea support = yes + +Note that ea support is required for supporting Linux xattrs. +Some administrators also change the "map archive" and the "create mask" +parameters from their default values. Creating special devices (mknod) +remotely may require specifying a mkdev function to Samba if you are not using +Samba 3.0.5 or later. For more information on these see the manual pages +("man smb.conf") on the Samba server system. Note that the cifs vfs, +unlike the smbfs vfs, does not read the smb.conf on the client system +(the few optional settings are passed in on mount via -o parameters instead). +Note that Samba 2.2.7 or later includes a fix that allows the CIFS VFS to delete +open files (required for strict POSIX compliance). Windows Servers already +supported this feature. Samba server does not allow symlinks that refer to files +outside of the share, so in Samba versions prior to 3.0.5, most symlinks to +files with absolute paths (ie beginning with slash) such as: + ln -s /mnt/foo bar +would be forbidden. Samba 3.0.5 server or later includes the ability to create +such symlinks safely by converting unsafe symlinks (ie symlinks to server +files that are outside of the share) to a samba specific format on the server +that is ignored by local server applications and non-cifs clients and that will +not be traversed by the Samba server). This is opaque to the Linux client +application using the cifs vfs. Absolute symlinks will work to Samba 3.0.5 or +later, but only for remote clients using the CIFS Unix extensions, and will +be invisbile to Windows clients and typically will not affect local +applications running on the same server as Samba. + +Use instructions: +================ +Once the CIFS VFS support is built into the kernel or installed as a module +(cifs.o), you can use mount syntax like the following to access Samba or Windows +servers: + + mount -t cifs //9.53.216.11/e$ /mnt -o user=myname,pass=mypassword + +Before -o the option -v may be specified to make the mount.cifs +mount helper display the mount steps more verbosely. +After -o the following commonly used cifs vfs specific options +are supported: + + user=<username> + pass=<password> + domain=<domain name> + +Other cifs mount options are described below. Use of TCP names (in addition to +ip addresses) is available if the mount helper (mount.cifs) is installed. If +you do not trust the server to which are mounted, or if you do not have +cifs signing enabled (and the physical network is insecure), consider use +of the standard mount options "noexec" and "nosuid" to reduce the risk of +running an altered binary on your local system (downloaded from a hostile server +or altered by a hostile router). + +When using the mount helper mount.cifs, passwords may be specified via alternate +mechanisms, instead of specifying it after -o using the normal "pass=" syntax +on the command line: +1) By including it in a credential file. Specify credentials=filename as one +of the mount options. Credential files contain two lines + username=someuser + password=your_password +2) By specifying the password in the PASSWD environment variable (similarly +the user name can be taken from the USER environment variable). +3) By specifying the password in a file by name via PASSWD_FILE +4) By specifying the password in a file by file descriptor via PASSWD_FD + +If no password is provided, mount.cifs will prompt for password entry + +Restrictions +============ +Servers must support the NTLM SMB dialect (which is the most recent, supported +by Samba and Windows NT version 4, 2000 and XP and many other SMB/CIFS servers) +Servers must support either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC +1001/1002 support for "Netbios-Over-TCP/IP." Neither of these is likely to be a +problem as most servers support this. IPv6 support is planned for the future. + +CIFS VFS Mount Options +====================== +A partial list of the supported mount options follows: + user The user name to use when trying to establish + the CIFS session. + password The user password. If the mount helper is + installed, the user will be prompted for password + if it is not supplied. + ip The ip address of the target server + unc The target server Universal Network Name (export) to + mount. + domain Set the SMB/CIFS workgroup name prepended to the + username during CIFS session establishment + uid If CIFS Unix extensions are not supported by the server + this overrides the default uid for inodes. For mounts to + servers which do support the CIFS Unix extensions, such + as a properly configured Samba server, the server provides + the uid, gid and mode. For servers which do not support + the Unix extensions, the default uid (and gid) returned on + lookup of existing files is the uid (gid) of the person + who executed the mount (root, except when mount.cifs + is configured setuid for user mounts) unless the "uid=" + (gid) mount option is specified. For the uid (gid) of newly + created files and directories, ie files created since + the last mount of the server share, the expected uid + (gid) is cached as as long as the inode remains in + memory on the client. Also note that permission + checks (authorization checks) on accesses to a file occur + at the server, but there are cases in which an administrator + may want to restrict at the client as well. For those + servers which do not report a uid/gid owner + (such as Windows), permissions can also be checked at the + client, and a crude form of client side permission checking + can be enabled by specifying file_mode and dir_mode on + the client + gid If CIFS Unix extensions are not supported by the server + this overrides the default gid for inodes. + file_mode If CIFS Unix extensions are not supported by the server + this overrides the default mode for file inodes. + dir_mode If CIFS Unix extensions are not supported by the server + this overrides the default mode for directory inodes. + port attempt to contact the server on this tcp port, before + trying the usual ports (port 445, then 139). + iocharset Codepage used to convert local path names to and from + Unicode. Unicode is used by default for network path + names if the server supports it. If iocharset is + not specified then the nls_default specified + during the local client kernel build will be used. + If server does not support Unicode, this parameter is + unused. + rsize default read size + wsize default write size + rw mount the network share read-write (note that the + server may still consider the share read-only) + ro mount network share read-only + version used to distinguish different versions of the + mount helper utility (not typically needed) + sep if first mount option (after the -o), overrides + the comma as the separator between the mount + parms. e.g. + -o user=myname,password=mypassword,domain=mydom + could be passed instead with period as the separator by + -o sep=.user=myname.password=mypassword.domain=mydom + this might be useful when comma is contained within username + or password or domain. This option is less important + when the cifs mount helper cifs.mount (version 1.1 or later) + is used. + nosuid Do not allow remote executables with the suid bit + program to be executed. This is only meaningful for mounts + to servers such as Samba which support the CIFS Unix Extensions. + If you do not trust the servers in your network (your mount + targets) it is recommended that you specify this option for + greater security. + suid Allow remote files on this mountpoint with suid enabled to + be executed (default for mounts when executed as root, + nosuid is default for user mounts). + credentials Although ignored by the cifs kernel component, it is used by + the mount helper, mount.cifs. When mount.cifs is installed it + opens and reads the credential file specified in order + to obtain the userid and password arguments which are passed to + the cifs vfs. + guest Although ignored by the kernel component, the mount.cifs + mount helper will not prompt the user for a password + if guest is specified on the mount options. If no + password is specified a null password will be used. + +The mount.cifs mount helper also accepts a few mount options before -o +including: + + -S take password from stdin (equivalent to setting the environment + variable "PASSWD_FD=0" + -V print mount.cifs version + -? display simple usage information + +With recent 2.6 kernel versions of modutils, the version of the cifs kernel +module can be displayed via modinfo. + +Misc /proc/fs/cifs Flags and Debug Info +======================================= +Informational pseudo-files: +DebugData Displays information about active CIFS sessions + and shares. +Stats Lists summary resource usage information as well as per + share statistics, if CONFIG_CIFS_STATS in enabled + in the kernel configuration. + +Configuration pseudo-files: +MultiuserMount If set to one, more than one CIFS session to + the same server ip address can be established + if more than one uid accesses the same mount + point and if the uids user/password mapping + information is available. (default is 0) +PacketSigningEnabled If set to one, cifs packet signing is enabled + and will be used if the server requires + it. If set to two, cifs packet signing is + required even if the server considers packet + signing optional. (default 1) +cifsFYI If set to one, additional debug information is + logged to the system error log. (default 0) +ExtendedSecurity If set to one, SPNEGO session establishment + is allowed which enables more advanced + secure CIFS session establishment (default 0) +NTLMV2Enabled If set to one, more secure password hashes + are used when the server supports them and + when kerberos is not negotiated (default 0) +traceSMB If set to one, debug information is logged to the + system error log with the start of smb requests + and responses (default 0) +LookupCacheEnable If set to one, inode information is kept cached + for one second improving performance of lookups + (default 1) +OplockEnabled If set to one, safe distributed caching enabled. + (default 1) +LinuxExtensionsEnabled If set to one then the client will attempt to + use the CIFS "UNIX" extensions which are optional + protocol enhancements that allow CIFS servers + to return accurate UID/GID information as well + as support symbolic links. If you use servers + such as Samba that support the CIFS Unix + extensions but do not want to use symbolic link + support and want to map the uid and gid fields + to values supplied at mount (rather than the + actual values, then set this to zero. (default 1) + +These experimental features and tracing can be enabled by changing flags in +/proc/fs/cifs (after the cifs module has been installed or built into the +kernel, e.g. insmod cifs). To enable a feature set it to 1 e.g. to enable +tracing to the kernel message log type: + + echo 1 > /proc/fs/cifs/cifsFYI + +and for more extensive tracing including the start of smb requests and responses + + echo 1 > /proc/fs/cifs/traceSMB + +Three other experimental features are under development and to test +require enabling an ifdef (e.g. by adding "#define CIFS_FCNTL" in cifsglob.h) + + CONFIG_CIFS_QUOTA + + CONFIG_CIFS_XATTR + + CONFIG_CIFS_FCNTL (fcntl needed for support of directory change + notification and perhaps later for file leases) + +Per share (per client mount) statistics are available in /proc/fs/cifs/DebugData +if the kernel was configured with cifs statistics enabled. The statistics +represent the number of successful (ie non-zero return code from the server) +SMB responses to some of the more common commands (open, delete, mkdir etc.). +Also recorded is the total bytes read and bytes written to the server for +that share. Note that due to client caching effects this can be less than the +number of bytes read and written by the application running on the client. +The statistics for the number of total SMBs and oplock breaks are different in +that they represent all for that share, not just those for which the server +returned success. + +Also note that "cat /proc/fs/cifs/DebugData" will display information about +the active sessions and the shares that are mounted. Note: NTLMv2 enablement +will not work since they its implementation is not quite complete yet. +Do not alter these configuration values unless you are doing specific testing. +Enabling extended security works to Windows 2000 Workstations and XP but not to +Windows 2000 server or Samba since it does not usually send "raw NTLMSSP" +(instead it sends NTLMSSP encapsulated in SPNEGO/GSSAPI, which support is not +complete in the CIFS VFS yet). diff --git a/release/src/linux/linux/fs/cifs/TODO b/release/src/linux/linux/fs/cifs/TODO new file mode 100644 index 00000000..51b230e0 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/TODO @@ -0,0 +1,106 @@ +version 1.16 May 27, 2004 + +A Partial List of Missing Features +================================== + +Contributions are welcome. There are plenty of opportunities +for visible, important contributions to this module. Here +is a partial list of the known problems and missing features: + +a) Support for SecurityDescriptors for chmod/chgrp/chown so +these can be supported for Windows servers + +b) Better pam/winbind integration + +c) multi-user mounts - multiplexed sessionsetups over single vc +(ie tcp session) - prettying up needed + +d) Kerberos/SPNEGO session setup support - (started) + +e) NTLMv2 authentication (mostly implemented) + +f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup +used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM +and raw NTLMSSP already. This is important when enabling +extended security and mounting to Windows 2003 Servers + +f) Directory entry caching relies on a 1 second timer, rather than +using FindNotify or equivalent. - (started) + +g) A few byte range testcases fail due to POSIX vs. Windows/CIFS +style byte range lock differences + +h) quota support + +i) support for the Linux 2.5 kernel new feature get_xattr and set_xattr +which will allow us to expose dos attributes as well as real +ACLs. This support has been started in the current code, but is +ifdeffed out. + +k) finish writepages support (multi-page write behind for improved +performance) and syncpage + +l) hook lower into the sockets api (as NFS/SunRPC does) to avoid the +extra copy in/out of the socket buffers in some cases. + +m) finish support for IPv6. This is mostly complete but +needs a simple inet_pton like function to convert ipv6 +addresses in string representation. + +o) Better optimize open (and pathbased setfilesize) to reduce the +oplock breaks coming from windows srv. Piggyback identical file +opens on top of each other by incrementing reference count rather +than resending (helps reduce server resource utilization and avoid +spurious oplock breaks). + +p) Improve performance of readpages by sending more than one read +at a time when 8 pages or more are requested. Evaluate whether +reads larger than 16K would be helpful. + +q) For support of Windows9x/98 we need to retry failed mounts +to *SMBSERVER (default server name) with the uppercase hostname +in the RFC1001 session_init request. + +r) Add Extended Attributed support (for storing UID/GID info +to Windows servers) + +s) Finish fcntl D_NOTIFY support so kde and gnome file list windows +will autorefresh + +t) Add GUI tool to configure /proc/fs/cifs settings and for display of +the CIFS statistics + +KNOWN BUGS (updated May 27, 2004) +==================================== +1) existing symbolic links (Windows reparse points) are recognized but +can not be created remotely. They are implemented for Samba and those that +support the CIFS Unix extensions but Samba has a bug currently handling +symlink text beginning with slash +2) follow_link and readdir code does not follow dfs junctions +but recognizes them +3) create of new files to FAT partitions on Windows servers can +succeed but still return access denied (appears to be Windows +server not cifs client problem) and has not been reproduced recently. +NTFS partitions do not have this problem. +4) debug connectathon lock test case 10 which fails against +Samba (may be unmappable due to POSIX to Windows lock model +differences but worth investigating). Also debug Samba to +see why lock test case 7 takes longer to complete to Samba +than to Windows. + +Misc testing to do +================== +1) check out max path names and max path name components against various server +types. Try nested symlinks. Return max path name in stat -f information + +2) Modify file portion of ltp so it can run against a mounted network +share and run it against cifs vfs. + +3) Additional performance testing and optimization using iozone and similar - +there are some easy changes that can be done to parallelize sequential writes, +and when signing is disabled to request larger read sizes (larger than +negotiated size) and send larger write sizes to modern servers. + +4) More exhaustively test the recently added NT4 support against various +NT4 service pack levels. + diff --git a/release/src/linux/linux/fs/cifs/asn1.c b/release/src/linux/linux/fs/cifs/asn1.c new file mode 100644 index 00000000..cf3c0276 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/asn1.c @@ -0,0 +1,614 @@ +/* + * The ASB.1/BER parsing code is derived from ip_nat_snmp_basic.c which was in + * turn derived from the gxsnmp package by Gregory McLean & Jochen Friedrich + * + * Copyright (c) 2000 RP Internet (www.rpi.net.au). + * + * 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 + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifs_debug.h" + +/***************************************************************************** + * + * Basic ASN.1 decoding routines (gxsnmp author Dirk Wisse) + * + *****************************************************************************/ + +/* Class */ +#define ASN1_UNI 0 /* Universal */ +#define ASN1_APL 1 /* Application */ +#define ASN1_CTX 2 /* Context */ +#define ASN1_PRV 3 /* Private */ + +/* Tag */ +#define ASN1_EOC 0 /* End Of Contents or N/A */ +#define ASN1_BOL 1 /* Boolean */ +#define ASN1_INT 2 /* Integer */ +#define ASN1_BTS 3 /* Bit String */ +#define ASN1_OTS 4 /* Octet String */ +#define ASN1_NUL 5 /* Null */ +#define ASN1_OJI 6 /* Object Identifier */ +#define ASN1_OJD 7 /* Object Description */ +#define ASN1_EXT 8 /* External */ +#define ASN1_SEQ 16 /* Sequence */ +#define ASN1_SET 17 /* Set */ +#define ASN1_NUMSTR 18 /* Numerical String */ +#define ASN1_PRNSTR 19 /* Printable String */ +#define ASN1_TEXSTR 20 /* Teletext String */ +#define ASN1_VIDSTR 21 /* Video String */ +#define ASN1_IA5STR 22 /* IA5 String */ +#define ASN1_UNITIM 23 /* Universal Time */ +#define ASN1_GENTIM 24 /* General Time */ +#define ASN1_GRASTR 25 /* Graphical String */ +#define ASN1_VISSTR 26 /* Visible String */ +#define ASN1_GENSTR 27 /* General String */ + +/* Primitive / Constructed methods*/ +#define ASN1_PRI 0 /* Primitive */ +#define ASN1_CON 1 /* Constructed */ + +/* + * Error codes. + */ +#define ASN1_ERR_NOERROR 0 +#define ASN1_ERR_DEC_EMPTY 2 +#define ASN1_ERR_DEC_EOC_MISMATCH 3 +#define ASN1_ERR_DEC_LENGTH_MISMATCH 4 +#define ASN1_ERR_DEC_BADVALUE 5 + +#define SPNEGO_OID_LEN 7 +#define NTLMSSP_OID_LEN 10 +unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 }; +unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 }; + +/* + * ASN.1 context. + */ +struct asn1_ctx { + int error; /* Error condition */ + unsigned char *pointer; /* Octet just to be decoded */ + unsigned char *begin; /* First octet */ + unsigned char *end; /* Octet after last octet */ +}; + +/* + * Octet string (not null terminated) + */ +struct asn1_octstr { + unsigned char *data; + unsigned int len; +}; + +static void +asn1_open(struct asn1_ctx *ctx, unsigned char *buf, unsigned int len) +{ + ctx->begin = buf; + ctx->end = buf + len; + ctx->pointer = buf; + ctx->error = ASN1_ERR_NOERROR; +} + +static unsigned char +asn1_octet_decode(struct asn1_ctx *ctx, unsigned char *ch) +{ + if (ctx->pointer >= ctx->end) { + ctx->error = ASN1_ERR_DEC_EMPTY; + return 0; + } + *ch = *(ctx->pointer)++; + return 1; +} + +static unsigned char +asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag) +{ + unsigned char ch; + + *tag = 0; + + do { + if (!asn1_octet_decode(ctx, &ch)) + return 0; + *tag <<= 7; + *tag |= ch & 0x7F; + } while ((ch & 0x80) == 0x80); + return 1; +} + +static unsigned char +asn1_id_decode(struct asn1_ctx *ctx, + unsigned int *cls, unsigned int *con, unsigned int *tag) +{ + unsigned char ch; + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *cls = (ch & 0xC0) >> 6; + *con = (ch & 0x20) >> 5; + *tag = (ch & 0x1F); + + if (*tag == 0x1F) { + if (!asn1_tag_decode(ctx, tag)) + return 0; + } + return 1; +} + +static unsigned char +asn1_length_decode(struct asn1_ctx *ctx, unsigned int *def, unsigned int *len) +{ + unsigned char ch, cnt; + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + if (ch == 0x80) + *def = 0; + else { + *def = 1; + + if (ch < 0x80) + *len = ch; + else { + cnt = (unsigned char) (ch & 0x7F); + *len = 0; + + while (cnt > 0) { + if (!asn1_octet_decode(ctx, &ch)) + return 0; + *len <<= 8; + *len |= ch; + cnt--; + } + } + } + return 1; +} + +static unsigned char +asn1_header_decode(struct asn1_ctx *ctx, + unsigned char **eoc, + unsigned int *cls, unsigned int *con, unsigned int *tag) +{ + unsigned int def, len; + + if (!asn1_id_decode(ctx, cls, con, tag)) + return 0; + + if (!asn1_length_decode(ctx, &def, &len)) + return 0; + + if (def) + *eoc = ctx->pointer + len; + else + *eoc = NULL; + return 1; +} + +static unsigned char +asn1_eoc_decode(struct asn1_ctx *ctx, unsigned char *eoc) +{ + unsigned char ch; + + if (eoc == 0) { + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + if (ch != 0x00) { + ctx->error = ASN1_ERR_DEC_EOC_MISMATCH; + return 0; + } + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + if (ch != 0x00) { + ctx->error = ASN1_ERR_DEC_EOC_MISMATCH; + return 0; + } + return 1; + } else { + if (ctx->pointer != eoc) { + ctx->error = ASN1_ERR_DEC_LENGTH_MISMATCH; + return 0; + } + return 1; + } +} + +/* static unsigned char asn1_null_decode(struct asn1_ctx *ctx, + unsigned char *eoc) +{ + ctx->pointer = eoc; + return 1; +} + +static unsigned char asn1_long_decode(struct asn1_ctx *ctx, + unsigned char *eoc, long *integer) +{ + unsigned char ch; + unsigned int len; + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *integer = (signed char) ch; + len = 1; + + while (ctx->pointer < eoc) { + if (++len > sizeof(long)) { + ctx->error = ASN1_ERR_DEC_BADVALUE; + return 0; + } + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *integer <<= 8; + *integer |= ch; + } + return 1; +} + +static unsigned char asn1_uint_decode(struct asn1_ctx *ctx, + unsigned char *eoc, + unsigned int *integer) +{ + unsigned char ch; + unsigned int len; + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *integer = ch; + if (ch == 0) + len = 0; + else + len = 1; + + while (ctx->pointer < eoc) { + if (++len > sizeof(unsigned int)) { + ctx->error = ASN1_ERR_DEC_BADVALUE; + return 0; + } + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *integer <<= 8; + *integer |= ch; + } + return 1; +} + +static unsigned char asn1_ulong_decode(struct asn1_ctx *ctx, + unsigned char *eoc, + unsigned long *integer) +{ + unsigned char ch; + unsigned int len; + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *integer = ch; + if (ch == 0) + len = 0; + else + len = 1; + + while (ctx->pointer < eoc) { + if (++len > sizeof(unsigned long)) { + ctx->error = ASN1_ERR_DEC_BADVALUE; + return 0; + } + + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *integer <<= 8; + *integer |= ch; + } + return 1; +} + +static unsigned char +asn1_octets_decode(struct asn1_ctx *ctx, + unsigned char *eoc, + unsigned char **octets, unsigned int *len) +{ + unsigned char *ptr; + + *len = 0; + + *octets = kmalloc(eoc - ctx->pointer, GFP_ATOMIC); + if (*octets == NULL) { + return 0; + } + + ptr = *octets; + while (ctx->pointer < eoc) { + if (!asn1_octet_decode(ctx, (unsigned char *) ptr++)) { + kfree(*octets); + *octets = NULL; + return 0; + } + (*len)++; + } + return 1; +} */ + +static unsigned char +asn1_subid_decode(struct asn1_ctx *ctx, unsigned long *subid) +{ + unsigned char ch; + + *subid = 0; + + do { + if (!asn1_octet_decode(ctx, &ch)) + return 0; + + *subid <<= 7; + *subid |= ch & 0x7F; + } while ((ch & 0x80) == 0x80); + return 1; +} + +static unsigned char +asn1_oid_decode(struct asn1_ctx *ctx, + unsigned char *eoc, unsigned long **oid, unsigned int *len) +{ + unsigned long subid; + unsigned int size; + unsigned long *optr; + + size = eoc - ctx->pointer + 1; + *oid = kmalloc(size * sizeof (unsigned long), GFP_ATOMIC); + if (*oid == NULL) { + return 0; + } + + optr = *oid; + + if (!asn1_subid_decode(ctx, &subid)) { + kfree(*oid); + *oid = NULL; + return 0; + } + + if (subid < 40) { + optr[0] = 0; + optr[1] = subid; + } else if (subid < 80) { + optr[0] = 1; + optr[1] = subid - 40; + } else { + optr[0] = 2; + optr[1] = subid - 80; + } + + *len = 2; + optr += 2; + + while (ctx->pointer < eoc) { + if (++(*len) > size) { + ctx->error = ASN1_ERR_DEC_BADVALUE; + kfree(*oid); + *oid = NULL; + return 0; + } + + if (!asn1_subid_decode(ctx, optr++)) { + kfree(*oid); + *oid = NULL; + return 0; + } + } + return 1; +} + +static int +compare_oid(unsigned long *oid1, unsigned int oid1len, + unsigned long *oid2, unsigned int oid2len) +{ + unsigned int i; + + if (oid1len != oid2len) + return 0; + else { + for (i = 0; i < oid1len; i++) { + if (oid1[i] != oid2[i]) + return 0; + } + return 1; + } +} + + /* BB check for endian conversion issues here */ + +int +decode_negTokenInit(unsigned char *security_blob, int length, + enum securityEnum *secType) +{ + struct asn1_ctx ctx; + unsigned char *end; + unsigned char *sequence_end; + unsigned long *oid; + unsigned int cls, con, tag, oidlen, rc; + int use_ntlmssp = FALSE; + + *secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default */ + + /* cifs_dump_mem(" Received SecBlob ", security_blob, length); */ + + asn1_open(&ctx, security_blob, length); + + if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { + cFYI(1, ("Error decoding negTokenInit header ")); + return 0; + } else if ((cls != ASN1_APL) || (con != ASN1_CON) + || (tag != ASN1_EOC)) { + cFYI(1, ("cls = %d con = %d tag = %d", cls, con, tag)); + return 0; + } else { + /* remember to free obj->oid */ + rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); + if (rc) { + if ((tag == ASN1_OJI) && (cls == ASN1_PRI)) { + rc = asn1_oid_decode(&ctx, end, &oid, &oidlen); + if (rc) { + rc = compare_oid(oid, oidlen, + SPNEGO_OID, + SPNEGO_OID_LEN); + kfree(oid); + } + } else + rc = 0; + } + + if (!rc) { + cFYI(1, ("Error decoding negTokenInit header")); + return 0; + } + + if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { + cFYI(1, ("Error decoding negTokenInit ")); + return 0; + } else if ((cls != ASN1_CTX) || (con != ASN1_CON) + || (tag != ASN1_EOC)) { + cFYI(1,("cls = %d con = %d tag = %d end = %p (%d) exit 0", + cls, con, tag, end, *end)); + return 0; + } + + if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { + cFYI(1, ("Error decoding negTokenInit ")); + return 0; + } else if ((cls != ASN1_UNI) || (con != ASN1_CON) + || (tag != ASN1_SEQ)) { + cFYI(1,("cls = %d con = %d tag = %d end = %p (%d) exit 1", + cls, con, tag, end, *end)); + return 0; + } + + if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { + cFYI(1, ("Error decoding 2nd part of negTokenInit ")); + return 0; + } else if ((cls != ASN1_CTX) || (con != ASN1_CON) + || (tag != ASN1_EOC)) { + cFYI(1, + ("cls = %d con = %d tag = %d end = %p (%d) exit 0", + cls, con, tag, end, *end)); + return 0; + } + + if (asn1_header_decode + (&ctx, &sequence_end, &cls, &con, &tag) == 0) { + cFYI(1, ("Error decoding 2nd part of negTokenInit ")); + return 0; + } else if ((cls != ASN1_UNI) || (con != ASN1_CON) + || (tag != ASN1_SEQ)) { + cFYI(1, + ("cls = %d con = %d tag = %d end = %p (%d) exit 1", + cls, con, tag, end, *end)); + return 0; + } + + while (!asn1_eoc_decode(&ctx, sequence_end)) { + rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); + if (!rc) { + cFYI(1, + ("Error 1 decoding negTokenInit header exit 2")); + return 0; + } + if ((tag == ASN1_OJI) && (con == ASN1_PRI)) { + asn1_oid_decode(&ctx, end, &oid, &oidlen); + cFYI(1, + ("OID len = %d oid = 0x%lx 0x%lx 0x%lx 0x%lx", + oidlen, *oid, *(oid + 1), *(oid + 2), + *(oid + 3))); + rc = compare_oid(oid, oidlen, NTLMSSP_OID, + NTLMSSP_OID_LEN); + kfree(oid); + if (rc) + use_ntlmssp = TRUE; + } else { + cFYI(1,("This should be an oid what is going on? ")); + } + } + + if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { + cFYI(1, + ("Error decoding last part of negTokenInit exit 3")); + return 0; + } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { /* tag = 3 indicating mechListMIC */ + cFYI(1, + ("Exit 4 cls = %d con = %d tag = %d end = %p (%d)", + cls, con, tag, end, *end)); + return 0; + } + if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { + cFYI(1, + ("Error decoding last part of negTokenInit exit 5")); + return 0; + } else if ((cls != ASN1_UNI) || (con != ASN1_CON) + || (tag != ASN1_SEQ)) { + cFYI(1, + ("Exit 6 cls = %d con = %d tag = %d end = %p (%d)", + cls, con, tag, end, *end)); + } + + if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { + cFYI(1, + ("Error decoding last part of negTokenInit exit 7")); + return 0; + } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { + cFYI(1, + ("Exit 8 cls = %d con = %d tag = %d end = %p (%d)", + cls, con, tag, end, *end)); + return 0; + } + if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { + cFYI(1, + ("Error decoding last part of negTokenInit exit 9")); + return 0; + } else if ((cls != ASN1_UNI) || (con != ASN1_PRI) + || (tag != ASN1_GENSTR)) { + cFYI(1, + ("Exit 10 cls = %d con = %d tag = %d end = %p (%d)", + cls, con, tag, end, *end)); + return 0; + } + cFYI(1, ("Need to call asn1_octets_decode() function for this %s", ctx.pointer)); /* is this UTF-8 or ASCII? */ + } + + /* if (use_kerberos) + *secType = Kerberos + else */ + if (use_ntlmssp) { + *secType = NTLMSSP; + } + + return 1; +} diff --git a/release/src/linux/linux/fs/cifs/cifs_debug.c b/release/src/linux/linux/fs/cifs/cifs_debug.c new file mode 100644 index 00000000..bdcca609 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/cifs_debug.c @@ -0,0 +1,797 @@ +/* + * fs/cifs_debug.c + * + * Copyright (C) International Business Machines Corp., 2000,2003 + * + * Modified by Steve French (sfrench@us.ibm.com) + * + * 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 + */ +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/ctype.h> +#include <linux/module.h> +#include <linux/proc_fs.h> +#include <asm/uaccess.h> +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_debug.h" + +void +cifs_dump_mem(char *label, void *data, int length) +{ + int i, j; + int *intptr = data; + char *charptr = data; + char buf[10], line[80]; + + printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n\n", + label, length, data); + for (i = 0; i < length; i += 16) { + line[0] = 0; + for (j = 0; (j < 4) && (i + j * 4 < length); j++) { + sprintf(buf, " %08x", intptr[i / 4 + j]); + strcat(line, buf); + } + buf[0] = ' '; + buf[2] = 0; + for (j = 0; (j < 16) && (i + j < length); j++) { + buf[1] = isprint(charptr[i + j]) ? charptr[i + j] : '.'; + strcat(line, buf); + } + printk(KERN_DEBUG "%s\n", line); + } +} + +#ifdef CONFIG_PROC_FS +int +cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, + int count, int *eof, void *data) +{ + struct list_head *tmp; + struct list_head *tmp1; + struct mid_q_entry * mid_entry; + struct cifsSesInfo *ses; + struct cifsTconInfo *tcon; + int i; + int length = 0; + char * original_buf = buf; + + *beginBuffer = buf + offset; + + + length = + sprintf(buf, + "Display Internal CIFS Data Structures for Debugging\n" + "---------------------------------------------------\n"); + buf += length; + + length = sprintf(buf, "Servers:\n"); + buf += length; + + i = 0; + read_lock(&GlobalSMBSeslock); + list_for_each(tmp, &GlobalSMBSessionList) { + i++; + ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); + length = + sprintf(buf, + "\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\tTCP status: %d", + i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse), + ses->serverOS, ses->serverNOS, ses->capabilities,ses->status,ses->server->tcpStatus); + buf += length; + if(ses->server) { + buf += sprintf(buf, "\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d", + atomic_read(&ses->server->socketUseCount), + ses->server->secMode, + atomic_read(&ses->server->inFlight)); + + length = sprintf(buf, "\nMIDs: \n"); + buf += length; + + spin_lock(&GlobalMid_Lock); + list_for_each(tmp1, &ses->server->pending_mid_q) { + mid_entry = list_entry(tmp1, struct + mid_q_entry, + qhead); + if(mid_entry) { + length = sprintf(buf,"State: %d com: %d pid: %d tsk: %p mid %d\n",mid_entry->midState,mid_entry->command,mid_entry->pid,mid_entry->tsk,mid_entry->mid); + buf += length; + } + } + spin_unlock(&GlobalMid_Lock); + } + + } + read_unlock(&GlobalSMBSeslock); + sprintf(buf, "\n"); + buf++; + + length = sprintf(buf, "\nShares:\n"); + buf += length; + + i = 0; + read_lock(&GlobalSMBSeslock); + list_for_each(tmp, &GlobalTreeConnectionList) { + i++; + tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); + length = + sprintf(buf, + "\n%d) %s Uses: %d Type: %s Characteristics: 0x%x Attributes: 0x%x\nPathComponentMax: %d Status: %d", + i, tcon->treeName, + atomic_read(&tcon->useCount), + tcon->nativeFileSystem, + tcon->fsDevInfo.DeviceCharacteristics, + tcon->fsAttrInfo.Attributes, + tcon->fsAttrInfo.MaxPathNameComponentLength,tcon->tidStatus); + buf += length; + if (tcon->fsDevInfo.DeviceType == FILE_DEVICE_DISK) + length = sprintf(buf, " type: DISK "); + else if (tcon->fsDevInfo.DeviceType == FILE_DEVICE_CD_ROM) + length = sprintf(buf, " type: CDROM "); + else + length = + sprintf(buf, " type: %d ", + tcon->fsDevInfo.DeviceType); + buf += length; + if(tcon->tidStatus == CifsNeedReconnect) { + buf += sprintf(buf, "\tDISCONNECTED "); + length += 14; + } + } + read_unlock(&GlobalSMBSeslock); + + length = sprintf(buf, "\n"); + buf += length; + + /* BB add code to dump additional info such as TCP session info now */ + /* Now calculate total size of returned data */ + length = buf - original_buf; + + if(offset + count >= length) + *eof = 1; + if(length < offset) { + *eof = 1; + return 0; + } else { + length = length - offset; + } + if (length > count) + length = count; + + return length; +} + +#ifdef CONFIG_CIFS_STATS +int +cifs_stats_read(char *buf, char **beginBuffer, off_t offset, + int count, int *eof, void *data) +{ + int item_length,i,length; + struct list_head *tmp; + struct cifsTconInfo *tcon; + + *beginBuffer = buf + offset; + + length = sprintf(buf, + "Resources in use\nCIFS Session: %d\n", + sesInfoAllocCount.counter); + buf += length; + item_length = + sprintf(buf,"Share (unique mount targets): %d\n", + tconInfoAllocCount.counter); + length += item_length; + buf += item_length; + item_length = + sprintf(buf,"SMB Request/Response Buffer: %d\n", + bufAllocCount.counter); + length += item_length; + buf += item_length; + item_length = + sprintf(buf,"Operations (MIDs): %d\n", + midCount.counter); + length += item_length; + buf += item_length; + item_length = sprintf(buf, + "\n%d session %d share reconnects\n", + tcpSesReconnectCount.counter,tconInfoReconnectCount.counter); + length += item_length; + buf += item_length; + + item_length = sprintf(buf, + "Total vfs operations: %d maximum at one time: %d\n", + GlobalCurrentXid,GlobalMaxActiveXid); + length += item_length; + buf += item_length; + + i = 0; + read_lock(&GlobalSMBSeslock); + list_for_each(tmp, &GlobalTreeConnectionList) { + i++; + tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); + item_length = sprintf(buf,"\n%d) %s",i, tcon->treeName); + buf += item_length; + length += item_length; + if(tcon->tidStatus == CifsNeedReconnect) { + buf += sprintf(buf, "\tDISCONNECTED "); + length += 14; + } + item_length = sprintf(buf,"\nSMBs: %d Oplock Breaks: %d", + atomic_read(&tcon->num_smbs_sent), + atomic_read(&tcon->num_oplock_brks)); + buf += item_length; + length += item_length; + item_length = sprintf(buf,"\nReads: %d Bytes %lld", + atomic_read(&tcon->num_reads), + (long long)(tcon->bytes_read)); + buf += item_length; + length += item_length; + item_length = sprintf(buf,"\nWrites: %d Bytes: %lld", + atomic_read(&tcon->num_writes), + (long long)(tcon->bytes_written)); + buf += item_length; + length += item_length; + item_length = sprintf(buf, + "\nOpens: %d Deletes: %d\nMkdirs: %d Rmdirs: %d", + atomic_read(&tcon->num_opens), + atomic_read(&tcon->num_deletes), + atomic_read(&tcon->num_mkdirs), + atomic_read(&tcon->num_rmdirs)); + buf += item_length; + length += item_length; + item_length = sprintf(buf, + "\nRenames: %d T2 Renames %d", + atomic_read(&tcon->num_renames), + atomic_read(&tcon->num_t2renames)); + buf += item_length; + length += item_length; + } + read_unlock(&GlobalSMBSeslock); + + buf += sprintf(buf,"\n"); + length++; + + if(offset + count >= length) + *eof = 1; + if(length < offset) { + *eof = 1; + return 0; + } else { + length = length - offset; + } + if (length > count) + length = count; + + return length; +} +#endif + +struct proc_dir_entry *proc_fs_cifs; +read_proc_t cifs_txanchor_read; +static read_proc_t cifsFYI_read; +static write_proc_t cifsFYI_write; +static read_proc_t oplockEnabled_read; +static write_proc_t oplockEnabled_write; +static read_proc_t lookupFlag_read; +static write_proc_t lookupFlag_write; +static read_proc_t traceSMB_read; +static write_proc_t traceSMB_write; +static read_proc_t multiuser_mount_read; +static write_proc_t multiuser_mount_write; +static read_proc_t extended_security_read; +static write_proc_t extended_security_write; +static read_proc_t ntlmv2_enabled_read; +static write_proc_t ntlmv2_enabled_write; +static read_proc_t packet_signing_enabled_read; +static write_proc_t packet_signing_enabled_write; +static read_proc_t quotaEnabled_read; +static write_proc_t quotaEnabled_write; +static read_proc_t linuxExtensionsEnabled_read; +static write_proc_t linuxExtensionsEnabled_write; + +void +cifs_proc_init(void) +{ + struct proc_dir_entry *pde; + + proc_fs_cifs = proc_mkdir("cifs", proc_root_fs); + if (proc_fs_cifs == NULL) + return; + + proc_fs_cifs->owner = THIS_MODULE; + create_proc_read_entry("DebugData", 0, proc_fs_cifs, + cifs_debug_data_read, NULL); + +#ifdef CONFIG_CIFS_STATS + create_proc_read_entry("Stats", 0, proc_fs_cifs, + cifs_stats_read, NULL); +#endif + pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs, + cifsFYI_read, NULL); + if (pde) + pde->write_proc = cifsFYI_write; + + pde = + create_proc_read_entry("traceSMB", 0, proc_fs_cifs, + traceSMB_read, NULL); + if (pde) + pde->write_proc = traceSMB_write; + + pde = create_proc_read_entry("OplockEnabled", 0, proc_fs_cifs, + oplockEnabled_read, NULL); + if (pde) + pde->write_proc = oplockEnabled_write; + + pde = create_proc_read_entry("QuotaEnabled", 0, proc_fs_cifs, + quotaEnabled_read, NULL); + if (pde) + pde->write_proc = quotaEnabled_write; + + pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs, + linuxExtensionsEnabled_read, NULL); + if (pde) + pde->write_proc = linuxExtensionsEnabled_write; + + pde = + create_proc_read_entry("MultiuserMount", 0, proc_fs_cifs, + multiuser_mount_read, NULL); + if (pde) + pde->write_proc = multiuser_mount_write; + + pde = + create_proc_read_entry("ExtendedSecurity", 0, proc_fs_cifs, + extended_security_read, NULL); + if (pde) + pde->write_proc = extended_security_write; + + pde = + create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs, + lookupFlag_read, NULL); + if (pde) + pde->write_proc = lookupFlag_write; + + pde = + create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs, + ntlmv2_enabled_read, NULL); + if (pde) + pde->write_proc = ntlmv2_enabled_write; + + pde = + create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs, + packet_signing_enabled_read, NULL); + if (pde) + pde->write_proc = packet_signing_enabled_write; +} + +void +cifs_proc_clean(void) +{ + if (proc_fs_cifs == NULL) + return; + + remove_proc_entry("DebugData", proc_fs_cifs); + remove_proc_entry("cifsFYI", proc_fs_cifs); + remove_proc_entry("traceSMB", proc_fs_cifs); +#ifdef CONFIG_CIFS_STATS + remove_proc_entry("Stats", proc_fs_cifs); +#endif + remove_proc_entry("MultiuserMount", proc_fs_cifs); + remove_proc_entry("OplockEnabled", proc_fs_cifs); + remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); + remove_proc_entry("ExtendedSecurity",proc_fs_cifs); + remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); + remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); + remove_proc_entry("QuotaEnabled",proc_fs_cifs); + remove_proc_entry("LookupCacheEnabled",proc_fs_cifs); + remove_proc_entry("cifs", proc_root_fs); +} + +static int +cifsFYI_read(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", cifsFYI); + + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +cifsFYI_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + cifsFYI = 0; + else if (c == '1' || c == 'y' || c == 'Y') + cifsFYI = 1; + + return count; +} + +static int +oplockEnabled_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", oplockEnabled); + + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +oplockEnabled_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + oplockEnabled = 0; + else if (c == '1' || c == 'y' || c == 'Y') + oplockEnabled = 1; + + return count; +} + +static int +quotaEnabled_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", quotaEnabled); +/* could also check if quotas are enabled in kernel + as a whole first */ + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +quotaEnabled_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + quotaEnabled = 0; + else if (c == '1' || c == 'y' || c == 'Y') + quotaEnabled = 1; + + return count; +} + +static int +linuxExtensionsEnabled_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", linuxExtEnabled); +/* could also check if quotas are enabled in kernel + as a whole first */ + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +linuxExtensionsEnabled_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + linuxExtEnabled = 0; + else if (c == '1' || c == 'y' || c == 'Y') + linuxExtEnabled = 1; + + return count; +} + + +static int +lookupFlag_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", lookupCacheEnabled); + + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +lookupFlag_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + lookupCacheEnabled = 0; + else if (c == '1' || c == 'y' || c == 'Y') + lookupCacheEnabled = 1; + + return count; +} +static int +traceSMB_read(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", traceSMB); + + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +traceSMB_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + traceSMB = 0; + else if (c == '1' || c == 'y' || c == 'Y') + traceSMB = 1; + + return count; +} + +static int +multiuser_mount_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", multiuser_mount); + + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +multiuser_mount_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + multiuser_mount = 0; + else if (c == '1' || c == 'y' || c == 'Y') + multiuser_mount = 1; + + return count; +} + +static int +extended_security_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", extended_security); + + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +extended_security_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + extended_security = 0; + else if (c == '1' || c == 'y' || c == 'Y') + extended_security = 1; + + return count; +} + +static int +ntlmv2_enabled_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", ntlmv2_support); + + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +ntlmv2_enabled_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + ntlmv2_support = 0; + else if (c == '1' || c == 'y' || c == 'Y') + ntlmv2_support = 1; + + return count; +} + +static int +packet_signing_enabled_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", sign_CIFS_PDUs); + + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +packet_signing_enabled_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + sign_CIFS_PDUs = 0; + else if (c == '1' || c == 'y' || c == 'Y') + sign_CIFS_PDUs = 1; + else if (c == '2') + sign_CIFS_PDUs = 2; + + return count; +} + + +#endif diff --git a/release/src/linux/linux/fs/cifs/cifs_debug.h b/release/src/linux/linux/fs/cifs/cifs_debug.h new file mode 100644 index 00000000..bf24d282 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/cifs_debug.h @@ -0,0 +1,66 @@ +/* + * + * Copyright (c) International Business Machines Corp., 2000,2002 + * Modified by Steve French (sfrench@us.ibm.com) + * + * 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 + * +*/ +#define CIFS_DEBUG /* BB temporary */ + +#ifndef _H_CIFS_DEBUG +#define _H_CIFS_DEBUG + +void cifs_dump_mem(char *label, void *data, int length); +extern int traceSMB; /* flag which enables the function below */ +void dump_smb(struct smb_hdr *, int); + +/* + * debug ON + * -------- + */ +#ifdef CIFS_DEBUG + + +/* information message: e.g., configuration, major event */ +extern int cifsFYI; +#define cifsfyi(format,arg...) if (cifsFYI) printk(KERN_DEBUG " " __FILE__ ": " format "\n" "" , ## arg) + +#define cFYI(button,prspec) if (button) cifsfyi prspec + +#define cifswarn(format, arg...) printk(KERN_WARNING ": " format "\n" , ## arg) + +/* debug event message: */ +extern int cifsERROR; + +#define cEVENT(format,arg...) if (cifsERROR) printk(KERN_EVENT __FILE__ ": " format "\n" , ## arg) + +/* error event message: e.g., i/o error */ +#define cifserror(format,arg...) if (cifsERROR) printk(KERN_ERR " CIFS VFS: " format "\n" "" , ## arg) + +#define cERROR(button, prspec) if (button) cifserror prspec + +/* + * debug OFF + * --------- + */ +#else /* _CIFS_DEBUG */ +#define cERROR(button,prspec) +#define cEVENT(format,arg...) +#define cFYI(button, prspec) +#define cifserror(format,arg...) +#endif /* _CIFS_DEBUG */ + +#endif /* _H_CIFS_DEBUG */ diff --git a/release/src/linux/linux/fs/cifs/cifs_fs_sb.h b/release/src/linux/linux/fs/cifs/cifs_fs_sb.h new file mode 100644 index 00000000..8007c2e9 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/cifs_fs_sb.h @@ -0,0 +1,32 @@ +/* + * fs/cifs/cifs_fs_sb.h + * + * Copyright (c) International Business Machines Corp., 2002 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + */ +#ifndef _CIFS_FS_SB_H +#define _CIFS_FS_SB_H + +struct cifs_sb_info { + struct cifsTconInfo *tcon; /* primary mount */ + struct list_head nested_tcon_q; + struct nls_table *local_nls; + unsigned int rsize; + unsigned int wsize; + uid_t mnt_uid; + gid_t mnt_gid; + mode_t mnt_file_mode; + mode_t mnt_dir_mode; +}; +#endif /* _CIFS_FS_SB_H */ diff --git a/release/src/linux/linux/fs/cifs/cifs_unicode.c b/release/src/linux/linux/fs/cifs/cifs_unicode.c new file mode 100644 index 00000000..a17adf4c --- /dev/null +++ b/release/src/linux/linux/fs/cifs/cifs_unicode.c @@ -0,0 +1,87 @@ +/* + * fs/cifs/cifs_unicode.c + * + * Copyright (c) International Business Machines Corp., 2000,2002 + * Modified by Steve French (sfrench@us.ibm.com) + * + * 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 + */ +#include <linux/fs.h> +#include "cifs_unicode.h" +#include "cifs_uniupr.h" +#include "cifspdu.h" +#include "cifs_debug.h" + +/* + * NAME: cifs_strfromUCS() + * + * FUNCTION: Convert little-endian unicode string to character string + * + */ +int +cifs_strfromUCS_le(char *to, const wchar_t * from, /* LITTLE ENDIAN */ + int len, const struct nls_table *codepage) +{ + int i; + int outlen = 0; + + for (i = 0; (i < len) && from[i]; i++) { + int charlen; + /* 2.4.0 kernel or greater */ + charlen = + codepage->uni2char(le16_to_cpu(from[i]), &to[outlen], + NLS_MAX_CHARSET_SIZE); + if (charlen > 0) { + outlen += charlen; + } else { + to[outlen++] = '?'; + } + } + to[outlen] = 0; + return outlen; +} + +/* + * NAME: cifs_strtoUCS() + * + * FUNCTION: Convert character string to unicode string + * + */ +int +cifs_strtoUCS(wchar_t * to, const char *from, int len, + const struct nls_table *codepage) +{ + int charlen; + int i; + + for (i = 0; len && *from; i++, from += charlen, len -= charlen) { + + /* works for 2.4.0 kernel or later */ + charlen = codepage->char2uni(from, len, &to[i]); + if (charlen < 1) { + cERROR(1, + ("cifs_strtoUCS: char2uni returned %d", + charlen)); + to[i] = cpu_to_le16(0x003f); /* a question mark */ + charlen = 1; + } + to[i] = cpu_to_le16(to[i]); + + } + + to[i] = 0; + return i; +} + diff --git a/release/src/linux/linux/fs/cifs/cifs_unicode.h b/release/src/linux/linux/fs/cifs/cifs_unicode.h new file mode 100644 index 00000000..da8dde96 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/cifs_unicode.h @@ -0,0 +1,353 @@ +/* + * cifs_unicode: Unicode kernel case support + * + * Function: + * Convert a unicode character to upper or lower case using + * compressed tables. + * + * Copyright (c) International Business Machines Corp., 2000,2002 + * + * 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 + * + * + * Notes: + * These APIs are based on the C library functions. The semantics + * should match the C functions but with expanded size operands. + * + * The upper/lower functions are based on a table created by mkupr. + * This is a compressed table of upper and lower case conversion. + * + */ + +#include <asm/byteorder.h> +#include <linux/types.h> +#include <linux/nls.h> + +#define UNIUPR_NOLOWER /* Example to not expand lower case tables */ + +/* Just define what we want from uniupr.h. We don't want to define the tables + * in each source file. + */ +#ifndef UNICASERANGE_DEFINED +struct UniCaseRange { + wchar_t start; + wchar_t end; + signed char *table; +}; +#endif /* UNICASERANGE_DEFINED */ + +#ifndef UNIUPR_NOUPPER +extern signed char CifsUniUpperTable[512]; +extern const struct UniCaseRange CifsUniUpperRange[]; +#endif /* UNIUPR_NOUPPER */ + +#ifndef UNIUPR_NOLOWER +extern signed char UniLowerTable[512]; +extern struct UniCaseRange UniLowerRange[]; +#endif /* UNIUPR_NOLOWER */ + +#ifdef __KERNEL__ +int cifs_strfromUCS_le(char *, const wchar_t *, int, const struct nls_table *); +int cifs_strtoUCS(wchar_t *, const char *, int, const struct nls_table *); +#endif + +/* + * UniStrcat: Concatenate the second string to the first + * + * Returns: + * Address of the first string + */ +static inline wchar_t * +UniStrcat(wchar_t * ucs1, const wchar_t * ucs2) +{ + wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */ + + while (*ucs1++) ; /* To end of first string */ + ucs1--; /* Return to the null */ + while ((*ucs1++ = *ucs2++)) ; /* copy string 2 over */ + return anchor; +} + +/* + * UniStrchr: Find a character in a string + * + * Returns: + * Address of first occurrence of character in string + * or NULL if the character is not in the string + */ +static inline wchar_t * +UniStrchr(const wchar_t * ucs, wchar_t uc) +{ + while ((*ucs != uc) && *ucs) + ucs++; + + if (*ucs == uc) + return (wchar_t *) ucs; + return NULL; +} + +/* + * UniStrcmp: Compare two strings + * + * Returns: + * < 0: First string is less than second + * = 0: Strings are equal + * > 0: First string is greater than second + */ +static inline int +UniStrcmp(const wchar_t * ucs1, const wchar_t * ucs2) +{ + while ((*ucs1 == *ucs2) && *ucs1) { + ucs1++; + ucs2++; + } + return (int) *ucs1 - (int) *ucs2; +} + +/* + * UniStrcpy: Copy a string + */ +static inline wchar_t * +UniStrcpy(wchar_t * ucs1, const wchar_t * ucs2) +{ + wchar_t *anchor = ucs1; /* save the start of result string */ + + while ((*ucs1++ = *ucs2++)) ; + return anchor; +} + +/* + * UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes) + */ +static inline size_t +UniStrlen(const wchar_t * ucs1) +{ + int i = 0; + + while (*ucs1++) + i++; + return i; +} + +/* + * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a string (length limited) + */ +static inline size_t +UniStrnlen(const wchar_t * ucs1, int maxlen) +{ + int i = 0; + + while (*ucs1++) { + i++; + if (i >= maxlen) + break; + } + return i; +} + +/* + * UniStrncat: Concatenate length limited string + */ +static inline wchar_t * +UniStrncat(wchar_t * ucs1, const wchar_t * ucs2, size_t n) +{ + wchar_t *anchor = ucs1; /* save pointer to string 1 */ + + while (*ucs1++) ; + ucs1--; /* point to null terminator of s1 */ + while (n-- && (*ucs1 = *ucs2)) { /* copy s2 after s1 */ + ucs1++; + ucs2++; + } + *ucs1 = 0; /* Null terminate the result */ + return (anchor); +} + +/* + * UniStrncmp: Compare length limited string + */ +static inline int +UniStrncmp(const wchar_t * ucs1, const wchar_t * ucs2, size_t n) +{ + if (!n) + return 0; /* Null strings are equal */ + while ((*ucs1 == *ucs2) && *ucs1 && --n) { + ucs1++; + ucs2++; + } + return (int) *ucs1 - (int) *ucs2; +} + +/* + * UniStrncmp_le: Compare length limited string - native to little-endian + */ +static inline int +UniStrncmp_le(const wchar_t * ucs1, const wchar_t * ucs2, size_t n) +{ + if (!n) + return 0; /* Null strings are equal */ + while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) { + ucs1++; + ucs2++; + } + return (int) *ucs1 - (int) __le16_to_cpu(*ucs2); +} + +/* + * UniStrncpy: Copy length limited string with pad + */ +static inline wchar_t * +UniStrncpy(wchar_t * ucs1, const wchar_t * ucs2, size_t n) +{ + wchar_t *anchor = ucs1; + + while (n-- && *ucs2) /* Copy the strings */ + *ucs1++ = *ucs2++; + + n++; + while (n--) /* Pad with nulls */ + *ucs1++ = 0; + return anchor; +} + +/* + * UniStrncpy_le: Copy length limited string with pad to little-endian + */ +static inline wchar_t * +UniStrncpy_le(wchar_t * ucs1, const wchar_t * ucs2, size_t n) +{ + wchar_t *anchor = ucs1; + + while (n-- && *ucs2) /* Copy the strings */ + *ucs1++ = __le16_to_cpu(*ucs2++); + + n++; + while (n--) /* Pad with nulls */ + *ucs1++ = 0; + return anchor; +} + +/* + * UniStrstr: Find a string in a string + * + * Returns: + * Address of first match found + * NULL if no matching string is found + */ +static inline wchar_t * +UniStrstr(const wchar_t * ucs1, const wchar_t * ucs2) +{ + const wchar_t *anchor1 = ucs1; + const wchar_t *anchor2 = ucs2; + + while (*ucs1) { + if (*ucs1 == *ucs2) { /* Partial match found */ + ucs1++; + ucs2++; + } else { + if (!*ucs2) /* Match found */ + return (wchar_t *) anchor1; + ucs1 = ++anchor1; /* No match */ + ucs2 = anchor2; + } + } + + if (!*ucs2) /* Both end together */ + return (wchar_t *) anchor1; /* Match found */ + return NULL; /* No match */ +} + +#ifndef UNIUPR_NOUPPER +/* + * UniToupper: Convert a unicode character to upper case + */ +static inline wchar_t +UniToupper(register wchar_t uc) +{ + register const struct UniCaseRange *rp; + + if (uc < sizeof (CifsUniUpperTable)) { /* Latin characters */ + return uc + CifsUniUpperTable[uc]; /* Use base tables */ + } else { + rp = CifsUniUpperRange; /* Use range tables */ + while (rp->start) { + if (uc < rp->start) /* Before start of range */ + return uc; /* Uppercase = input */ + if (uc <= rp->end) /* In range */ + return uc + rp->table[uc - rp->start]; + rp++; /* Try next range */ + } + } + return uc; /* Past last range */ +} + +/* + * UniStrupr: Upper case a unicode string + */ +static inline wchar_t * +UniStrupr(register wchar_t * upin) +{ + register wchar_t *up; + + up = upin; + while (*up) { /* For all characters */ + *up = UniToupper(*up); + up++; + } + return upin; /* Return input pointer */ +} +#endif /* UNIUPR_NOUPPER */ + +#ifndef UNIUPR_NOLOWER +/* + * UniTolower: Convert a unicode character to lower case + */ +static inline wchar_t +UniTolower(wchar_t uc) +{ + register struct UniCaseRange *rp; + + if (uc < sizeof (UniLowerTable)) { /* Latin characters */ + return uc + UniLowerTable[uc]; /* Use base tables */ + } else { + rp = UniLowerRange; /* Use range tables */ + while (rp->start) { + if (uc < rp->start) /* Before start of range */ + return uc; /* Uppercase = input */ + if (uc <= rp->end) /* In range */ + return uc + rp->table[uc - rp->start]; + rp++; /* Try next range */ + } + } + return uc; /* Past last range */ +} + +/* + * UniStrlwr: Lower case a unicode string + */ +static inline wchar_t * +UniStrlwr(register wchar_t * upin) +{ + register wchar_t *up; + + up = upin; + while (*up) { /* For all characters */ + *up = UniTolower(*up); + up++; + } + return upin; /* Return input pointer */ +} + +#endif diff --git a/release/src/linux/linux/fs/cifs/cifs_uniupr.h b/release/src/linux/linux/fs/cifs/cifs_uniupr.h new file mode 100644 index 00000000..272d72df --- /dev/null +++ b/release/src/linux/linux/fs/cifs/cifs_uniupr.h @@ -0,0 +1,253 @@ +/* + * Copyright (c) International Business Machines Corp., 2000,2002 + * + * 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 + * + * uniupr.h - Unicode compressed case ranges + * +*/ + +#ifndef UNIUPR_NOUPPER +/* + * Latin upper case + */ +signed char CifsUniUpperTable[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 040-04f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 050-05f */ + 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 060-06f */ + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, 0, 0, 0, 0, 0, /* 070-07f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0c0-0cf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0d0-0df */ + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 0e0-0ef */ + -32, -32, -32, -32, -32, -32, -32, 0, -32, -32, -32, -32, -32, -32, -32, 121, /* 0f0-0ff */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 100-10f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 110-11f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 120-12f */ + 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 130-13f */ + -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, /* 140-14f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 150-15f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 160-16f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 170-17f */ + 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, /* 180-18f */ + 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, /* 190-19f */ + 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, /* 1a0-1af */ + -1, 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, /* 1b0-1bf */ + 0, 0, 0, 0, 0, -1, -2, 0, -1, -2, 0, -1, -2, 0, -1, 0, /* 1c0-1cf */ + -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, -79, 0, -1, /* 1d0-1df */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */ + 0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1, /* 1f0-1ff */ +}; + +/* Upper case range - Greek */ +static signed char UniCaseRangeU03a0[47] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -38, -37, -37, -37, /* 3a0-3af */ + 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 3b0-3bf */ + -32, -32, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -64, + -63, -63, +}; + +/* Upper case range - Cyrillic */ +static signed char UniCaseRangeU0430[48] = { + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 430-43f */ + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 440-44f */ + 0, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, 0, -80, -80, /* 450-45f */ +}; + +/* Upper case range - Extended cyrillic */ +static signed char UniCaseRangeU0490[61] = { + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 490-49f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4a0-4af */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4b0-4bf */ + 0, 0, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, +}; + +/* Upper case range - Extended latin and greek */ +static signed char UniCaseRangeU1e00[509] = { + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e00-1e0f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e10-1e1f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e20-1e2f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e30-1e3f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e40-1e4f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e50-1e5f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e60-1e6f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e70-1e7f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e80-1e8f */ + 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, -59, 0, -1, 0, -1, /* 1e90-1e9f */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ea0-1eaf */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1eb0-1ebf */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ec0-1ecf */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ed0-1edf */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ee0-1eef */ + 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */ + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f00-1f0f */ + 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f10-1f1f */ + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f20-1f2f */ + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f30-1f3f */ + 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f40-1f4f */ + 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f50-1f5f */ + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f60-1f6f */ + 74, 74, 86, 86, 86, 86, 100, 100, 0, 0, 112, 112, 126, 126, 0, 0, /* 1f70-1f7f */ + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f80-1f8f */ + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f90-1f9f */ + 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fa0-1faf */ + 8, 8, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fb0-1fbf */ + 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fc0-1fcf */ + 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fd0-1fdf */ + 8, 8, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fe0-1fef */ + 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +/* Upper case range - Wide latin */ +static signed char UniCaseRangeUff40[27] = { + 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* ff40-ff4f */ + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, +}; + +/* + * Upper Case Range + */ +const struct UniCaseRange CifsUniUpperRange[] = { + {0x03a0, 0x03ce, UniCaseRangeU03a0}, + {0x0430, 0x045f, UniCaseRangeU0430}, + {0x0490, 0x04cc, UniCaseRangeU0490}, + {0x1e00, 0x1ffc, UniCaseRangeU1e00}, + {0xff40, 0xff5a, UniCaseRangeUff40}, + {0, 0, NULL} +}; +#endif + +#ifndef UNIUPR_NOLOWER +/* + * Latin lower case + */ +static signed char CifsUniLowerTable[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */ + 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 040-04f */ + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0, 0, 0, 0, 0, /* 050-05f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 060-06f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 070-07f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */ + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 0c0-0cf */ + 32, 32, 32, 32, 32, 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 0, /* 0d0-0df */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0e0-0ef */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0f0-0ff */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 100-10f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 110-11f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 120-12f */ + 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, /* 130-13f */ + 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, /* 140-14f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 150-15f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 160-16f */ + 1, 0, 1, 0, 1, 0, 1, 0, -121, 1, 0, 1, 0, 1, 0, 0, /* 170-17f */ + 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 79, 0, /* 180-18f */ + 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 190-19f */ + 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, /* 1a0-1af */ + 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 1b0-1bf */ + 0, 0, 0, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 1, 0, 1, /* 1c0-1cf */ + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, /* 1d0-1df */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e0-1ef */ + 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1f0-1ff */ +}; + +/* Lower case range - Greek */ +static signed char UniCaseRangeL0380[44] = { + 0, 0, 0, 0, 0, 0, 38, 0, 37, 37, 37, 0, 64, 0, 63, 63, /* 380-38f */ + 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 390-39f */ + 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, +}; + +/* Lower case range - Cyrillic */ +static signed char UniCaseRangeL0400[48] = { + 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 0, 80, 80, /* 400-40f */ + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 410-41f */ + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 420-42f */ +}; + +/* Lower case range - Extended cyrillic */ +static signed char UniCaseRangeL0490[60] = { + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 490-49f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4a0-4af */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4b0-4bf */ + 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, +}; + +/* Lower case range - Extended latin and greek */ +static signed char UniCaseRangeL1e00[504] = { + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e00-1e0f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e10-1e1f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e20-1e2f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e30-1e3f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e40-1e4f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e50-1e5f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e60-1e6f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e70-1e7f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e80-1e8f */ + 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 1e90-1e9f */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ea0-1eaf */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1eb0-1ebf */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ec0-1ecf */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ed0-1edf */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ee0-1eef */ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f00-1f0f */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f10-1f1f */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f20-1f2f */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f30-1f3f */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f40-1f4f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8, /* 1f50-1f5f */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f60-1f6f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f70-1f7f */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f80-1f8f */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f90-1f9f */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1fa0-1faf */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -74, -74, -9, 0, 0, 0, /* 1fb0-1fbf */ + 0, 0, 0, 0, 0, 0, 0, 0, -86, -86, -86, -86, -9, 0, 0, 0, /* 1fc0-1fcf */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -100, -100, 0, 0, 0, 0, /* 1fd0-1fdf */ + 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -112, -112, -7, 0, 0, 0, /* 1fe0-1fef */ + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +/* Lower case range - Wide latin */ +static signed char UniCaseRangeLff20[27] = { + 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* ff20-ff2f */ + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +}; + +/* + * Lower Case Range + */ +const static struct UniCaseRange CifsUniLowerRange[] = { + 0x0380, 0x03ab, UniCaseRangeL0380, + 0x0400, 0x042f, UniCaseRangeL0400, + 0x0490, 0x04cb, UniCaseRangeL0490, + 0x1e00, 0x1ff7, UniCaseRangeL1e00, + 0xff20, 0xff3a, UniCaseRangeLff20, + 0, 0, 0 +}; +#endif diff --git a/release/src/linux/linux/fs/cifs/cifsencrypt.c b/release/src/linux/linux/fs/cifs/cifsencrypt.c new file mode 100644 index 00000000..8fdf3d79 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/cifsencrypt.c @@ -0,0 +1,204 @@ +/* + * fs/cifs/cifsencrypt.c + * + * Copyright (C) International Business Machines Corp., 2003 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/fs.h> +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifs_debug.h" +#include "md5.h" +#include "cifs_unicode.h" + +/* Calculate and return the CIFS signature based on the mac key and the smb pdu */ +/* the 16 byte signature must be allocated by the caller */ +/* Note we only use the 1st eight bytes */ +/* Note that the smb header signature field on input contains the + sequence number before this function is called */ + +extern void mdfour(unsigned char *out, unsigned char *in, int n); +extern void E_md4hash(const unsigned char *passwd, unsigned char *p16); + +static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char * key, char * signature) +{ + struct MD5Context context; + + if((cifs_pdu == NULL) || (signature == NULL)) + return -EINVAL; + + MD5Init(&context); + MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16); + MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length); + MD5Final(signature,&context); + return 0; +} + +int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses, + __u32 * pexpected_response_sequence_number) +{ + int rc = 0; + char smb_signature[20]; + + /* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */ + /* BB remember to add code to save expected sequence number in midQ entry BB */ + + if((cifs_pdu == NULL) || (ses == NULL)) + return -EINVAL; + + if((le32_to_cpu(cifs_pdu->Flags2) & SMBFLG2_SECURITY_SIGNATURE) == 0) + return rc; + + spin_lock(&GlobalMid_Lock); + cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(ses->sequence_number); + cifs_pdu->Signature.Sequence.Reserved = 0; + + *pexpected_response_sequence_number = ses->sequence_number++; + ses->sequence_number++; + spin_unlock(&GlobalMid_Lock); + + rc = cifs_calculate_signature(cifs_pdu, ses->mac_signing_key,smb_signature); + if(rc) + memset(cifs_pdu->Signature.SecuritySignature, 0, 8); + else + memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8); + + return rc; +} + +int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key, + __u32 expected_sequence_number) +{ + unsigned int rc; + char server_response_sig[8]; + char what_we_think_sig_should_be[20]; + + if((cifs_pdu == NULL) || (mac_key == NULL)) + return -EINVAL; + + if (cifs_pdu->Command == SMB_COM_NEGOTIATE) + return 0; + + if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) { + struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)cifs_pdu; + if(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE) + return 0; + } + + /* BB what if signatures are supposed to be on for session but server does not + send one? BB */ + + /* Do not need to verify session setups with signature "BSRSPYL " */ + if(memcmp(cifs_pdu->Signature.SecuritySignature,"BSRSPYL ",8)==0) + cFYI(1,("dummy signature received for smb command 0x%x",cifs_pdu->Command)); + + expected_sequence_number = cpu_to_le32(expected_sequence_number); + + /* save off the origiginal signature so we can modify the smb and check + its signature against what the server sent */ + memcpy(server_response_sig,cifs_pdu->Signature.SecuritySignature,8); + + cifs_pdu->Signature.Sequence.SequenceNumber = expected_sequence_number; + cifs_pdu->Signature.Sequence.Reserved = 0; + + rc = cifs_calculate_signature(cifs_pdu, mac_key, + what_we_think_sig_should_be); + + if(rc) + return rc; + + +/* cifs_dump_mem("what we think it should be: ",what_we_think_sig_should_be,16); */ + + if(memcmp(server_response_sig, what_we_think_sig_should_be, 8)) + return -EACCES; + else + return 0; + +} + +/* We fill in key by putting in 40 byte array which was allocated by caller */ +int cifs_calculate_mac_key(char * key, const char * rn, const char * password) +{ + char temp_key[16]; + if ((key == NULL) || (rn == NULL)) + return -EINVAL; + + E_md4hash(password, temp_key); + mdfour(key,temp_key,16); + memcpy(key+16,rn, CIFS_SESSION_KEY_SIZE); + return 0; +} + +int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_info) +{ + char temp_hash[16]; + struct HMACMD5Context ctx; + char * ucase_buf; + wchar_t * unicode_buf; + unsigned int i,user_name_len,dom_name_len; + + if(ses) + return -EINVAL; + + E_md4hash(ses->password, temp_hash); + + hmac_md5_init_limK_to_64(temp_hash, 16, &ctx); + user_name_len = strlen(ses->userName); + if(user_name_len > MAX_USERNAME_SIZE) + return -EINVAL; + dom_name_len = strlen(ses->domainName); + if(dom_name_len > MAX_USERNAME_SIZE) + return -EINVAL; + + ucase_buf = kmalloc((MAX_USERNAME_SIZE+1), GFP_KERNEL); + unicode_buf = kmalloc((MAX_USERNAME_SIZE+1)*4, GFP_KERNEL); + + for(i=0;i<user_name_len;i++) + ucase_buf[i] = nls_info->charset2upper[(int)ses->userName[i]]; + ucase_buf[i] = 0; + user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); + unicode_buf[user_name_len] = 0; + user_name_len++; + + for(i=0;i<dom_name_len;i++) + ucase_buf[i] = nls_info->charset2upper[(int)ses->domainName[i]]; + ucase_buf[i] = 0; + dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); + + unicode_buf[user_name_len + dom_name_len] = 0; + hmac_md5_update((const unsigned char *) unicode_buf, + (user_name_len+dom_name_len)*2,&ctx); + + hmac_md5_final(ses->mac_signing_key,&ctx); + kfree(ucase_buf); + kfree(unicode_buf); + return 0; +} +void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) +{ + struct HMACMD5Context context; + memcpy(v2_session_response + 8, ses->server->cryptKey,8); + /* gen_blob(v2_session_response + 16); */ + hmac_md5_init_limK_to_64(ses->mac_signing_key, 16, &context); + + hmac_md5_update(ses->server->cryptKey,8,&context); +/* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */ + + hmac_md5_final(v2_session_response,&context); +} diff --git a/release/src/linux/linux/fs/cifs/cifserr.c b/release/src/linux/linux/fs/cifs/cifserr.c new file mode 100644 index 00000000..4c8eb7a0 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/cifserr.c @@ -0,0 +1,70 @@ +/* + * fs/cifserr.c + * + * Copyright (c) International Business Machines Corp., 2002 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/smbno.h> +#include "cifsfs.h" + +int map_cifs_error(int error_class, int error_code, + int status_codes_negotiated) +{ + + + if (status_codes_negotiated) { + switch (error_code) { + default: + return EIO; + } + } else + switch (error_class) { + case SUCCESS: + return 0; + + case ERRDOS: + switch (error_code) { + case ERRbadfunc: + return EINVAL; + default: + return EIO; + } + + case ERRSRV: + switch (error_code) { + default: + return EIO; + } + + case ERRHRD: + switch (error_code) { + default: + return EIO; + } + default: + return EIO; + } + return 0; +} + +int map_smb_error(int error_class, int error_code) +{ + return map_cifs_error(error_class, error_code, FALSE); +} diff --git a/release/src/linux/linux/fs/cifs/cifsfs.c b/release/src/linux/linux/fs/cifs/cifsfs.c new file mode 100644 index 00000000..9e96b3b3 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/cifsfs.c @@ -0,0 +1,769 @@ +/* + * fs/cifs/cifsfs.c + * + * Copyright (C) International Business Machines Corp., 2002,2004 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * Common Internet FileSystem (CIFS) client + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Note that BB means BUGBUG (ie something to fix eventually) */ + +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/mount.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/version.h> +#include <linux/list.h> +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15)) +#include <linux/seq_file.h> +#endif +#include <linux/vfs.h> +#include "cifsfs.h" +#include "cifspdu.h" +#define DECLARE_GLOBALS_HERE +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_debug.h" +#include "cifs_fs_sb.h" +#include <linux/mm.h> +#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ +/* BB when mempool_resize is added back in, we will resize pool on new mount */ +#define CIFS_MIN_RCV_POOL 11 /* enough for progress to five servers */ + +#ifdef CONFIG_CIFS_QUOTA +static struct quotactl_ops cifs_quotactl_ops; +#endif + +extern struct file_system_type cifs_fs_type; + +int cifsFYI = 0; +int cifsERROR = 1; +int traceSMB = 0; +unsigned int oplockEnabled = 1; +unsigned int quotaEnabled = 0; +unsigned int linuxExtEnabled = 1; +unsigned int lookupCacheEnabled = 1; +unsigned int multiuser_mount = 0; +unsigned int extended_security = 0; +unsigned int ntlmv2_support = 0; +unsigned int sign_CIFS_PDUs = 1; +unsigned int CIFSMaximumBufferSize = CIFS_MAX_MSGSIZE; +struct task_struct * oplockThread = NULL; + +extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, + const char *); +extern int cifs_umount(struct super_block *, struct cifs_sb_info *); +void cifs_proc_init(void); +void cifs_proc_clean(void); + +static DECLARE_COMPLETION(cifs_oplock_exited); + + +struct super_block * +cifs_read_super(struct super_block *sb, void *data, int silent) +{ + struct inode *inode; + struct cifs_sb_info *cifs_sb; + int rc = 0; + + sb->s_flags |= MS_NODIRATIME; /* and probably even noatime */ + cifs_sb = CIFS_SB(sb); + if(cifs_sb == NULL) + return 0; + else + memset(cifs_sb,0,sizeof(struct cifs_sb_info)); + + + rc = cifs_mount(sb, cifs_sb, data, NULL); + + if (rc) { + if (!silent) + cERROR(1, + ("cifs_mount failed w/return code = %d", rc)); + goto out_mount_failed; + } + + sb->s_magic = CIFS_MAGIC_NUMBER; + sb->s_op = &cifs_super_ops; +/* if(cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512) + sb->s_blocksize = cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */ +#ifdef CONFIG_CIFS_QUOTA + sb->s_qcop = &cifs_quotactl_ops; +#endif + sb->s_blocksize = CIFS_MAX_MSGSIZE; + sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */ + inode = iget(sb, ROOT_I); + + if (!inode) { + goto out_no_root; + } + + sb->s_root = d_alloc_root(inode); + + if (!sb->s_root) { + goto out_no_root; + } + + return sb; + +out_no_root: + cERROR(1, ("cifs_read_super: get root inode failed")); + if (inode) + iput(inode); + +out_mount_failed: + if(cifs_sb->local_nls) + unload_nls(cifs_sb->local_nls); + sb->s_dev = 0; + return 0; +} + +static void +cifs_put_super(struct super_block *sb) +{ + int rc = 0; + struct cifs_sb_info *cifs_sb; + + cFYI(1, ("In cifs_put_super")); + cifs_sb = CIFS_SB(sb); + if(cifs_sb == NULL) { + cFYI(1,("Empty cifs superblock info passed to unmount")); + return; + } + rc = cifs_umount(sb, cifs_sb); + if (rc) { + cERROR(1, ("cifs_umount failed with return code %d", rc)); + } + unload_nls(cifs_sb->local_nls); + return; +} + +static int +cifs_statfs(struct super_block *sb, struct statfs *buf) +{ + int xid, rc; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + + xid = GetXid(); + + cifs_sb = CIFS_SB(sb); + pTcon = cifs_sb->tcon; + + buf->f_type = CIFS_MAGIC_NUMBER; + + /* instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO */ + buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would presumably + be length of total path, note that some servers may be + able to support more than this, but best to be safe + since Win2k and others can not handle very long filenames */ + buf->f_files = 0; /* undefined */ + buf->f_ffree = 0; /* unlimited */ + + rc = CIFSSMBQFSInfo(xid, pTcon, buf, cifs_sb->local_nls); + + /* + int f_type; + __fsid_t f_fsid; + int f_namelen; */ + /* BB get from info put in tcon struct at mount time with call to QFSAttrInfo */ + FreeXid(xid); + return 0; /* always return success? what if volume is no longer available? */ +} + +static int cifs_permission(struct inode * inode, int mask) +{ + /* the server does permission checks, we do not need to do it here */ + return 0; +} + +kmem_cache_t *cifs_req_cachep; +kmem_cache_t *cifs_mid_cachep; +kmem_cache_t *cifs_oplock_cachep; + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +static struct inode * +cifs_alloc_inode(struct super_block *sb) +{ + struct cifsInodeInfo *cifs_inode; + cifs_inode = + (struct cifsInodeInfo *) kmem_cache_alloc(cifs_inode_cachep, + SLAB_KERNEL); + if (!cifs_inode) + return NULL; + cifs_inode->cifsAttrs = 0x20; /* default */ + atomic_set(&cifs_inode->inUse, 0); + cifs_inode->time = 0; + /* Until the file is open and we have gotten oplock + info back from the server, can not assume caching of + file data or metadata */ + cifs_inode->clientCanCacheRead = FALSE; + cifs_inode->clientCanCacheAll = FALSE; + INIT_LIST_HEAD(&cifs_inode->openFileList); + return &cifs_inode->vfs_inode; +} + +static void +cifs_destroy_inode(struct inode *inode) +{ + kmem_cache_free(cifs_inode_cachep, CIFS_I(inode)); +} +#endif + +/* + * cifs_show_options() is for displaying mount options in /proc/mounts. + * Not all settable options are displayed but most of the important + * ones are. + */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15)) +static int +cifs_show_options(struct seq_file *s, struct vfsmount *m) +{ + struct cifs_sb_info *cifs_sb; + + cifs_sb = CIFS_SB(m->mnt_sb); + + if (cifs_sb) { + if (cifs_sb->tcon) { + seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName); + if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->userName)) + seq_printf(s, ",username=%s", + cifs_sb->tcon->ses->userName); + if(cifs_sb->tcon->ses->domainName) + seq_printf(s, ",domain=%s", + cifs_sb->tcon->ses->domainName); + } + seq_printf(s, ",rsize=%d",cifs_sb->rsize); + seq_printf(s, ",wsize=%d",cifs_sb->wsize); + } + return 0; +} +#endif + +#ifdef CONFIG_CIFS_QUOTA +int cifs_xquota_set(struct super_block * sb, int quota_type, qid_t qid, + struct fs_disk_quota * pdquota) +{ + int xid; + int rc = 0; + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + struct cifsTconInfo *pTcon; + + if(cifs_sb) + pTcon = cifs_sb->tcon; + else + return -EIO; + + + xid = GetXid(); + if(pTcon) { + cFYI(1,("set type: 0x%x id: %d",quota_type,qid)); + } else { + return -EIO; + } + + FreeXid(xid); + return rc; +} + +int cifs_xquota_get(struct super_block * sb, int quota_type, qid_t qid, + struct fs_disk_quota * pdquota) +{ + int xid; + int rc = 0; + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + struct cifsTconInfo *pTcon; + + if(cifs_sb) + pTcon = cifs_sb->tcon; + else + return -EIO; + + xid = GetXid(); + if(pTcon) { + cFYI(1,("set type: 0x%x id: %d",quota_type,qid)); + } else { + rc = -EIO; + } + + FreeXid(xid); + return rc; +} + +int cifs_xstate_set(struct super_block * sb, unsigned int flags, int operation) +{ + int xid; + int rc = 0; + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + struct cifsTconInfo *pTcon; + + if(cifs_sb) + pTcon = cifs_sb->tcon; + else + return -EIO; + + xid = GetXid(); + if(pTcon) { + cFYI(1,("flags: 0x%x operation: 0x%x",flags,operation)); + } else { + rc = -EIO; + } + + FreeXid(xid); + return rc; +} + +int cifs_xstate_get(struct super_block * sb, struct fs_quota_stat *qstats) +{ + int xid; + int rc = 0; + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + struct cifsTconInfo *pTcon; + + if(cifs_sb) { + pTcon = cifs_sb->tcon; + } else { + return -EIO; + } + xid = GetXid(); + if(pTcon) { + cFYI(1,("pqstats %p",qstats)); + } else { + rc = -EIO; + } + + FreeXid(xid); + return rc; +} + +static struct quotactl_ops cifs_quotactl_ops = { + .set_xquota = cifs_xquota_set, + .get_xquota = cifs_xquota_set, + .set_xstate = cifs_xstate_set, + .get_xstate = cifs_xstate_get, +}; +#endif + +static int cifs_remount(struct super_block *sb, int *flags, char *data) +{ + *flags |= MS_NODIRATIME; + return 0; +} + +struct super_operations cifs_super_ops = { + .read_inode = cifs_read_inode, + .put_super = cifs_put_super, + .statfs = cifs_statfs, +/* .alloc_inode = cifs_alloc_inode, + .destroy_inode = cifs_destroy_inode, */ +/* .drop_inode = generic_delete_inode, + .delete_inode = cifs_delete_inode, *//* Do not need the above two functions + unless later we add lazy close of inodes or unless the kernel forgets to call + us with the same number of releases (closes) as opens */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15)) + .show_options = cifs_show_options, +#endif +/* .umount_begin = cifs_umount_begin, *//* consider adding in the future */ +}; + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +static struct super_block * +cifs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) +{ + int rc; + struct super_block *sb = sget(fs_type, NULL, set_anon_super, NULL); + + cFYI(1, ("Devname: %s flags: %d ", dev_name, flags)); + + if (IS_ERR(sb)) + return sb; + + sb->s_flags = flags; + + rc = cifs_read_super(sb, data, dev_name, flags & MS_VERBOSE ? 1 : 0); + if (rc) { + up_write(&sb->s_umount); + deactivate_super(sb); + return ERR_PTR(rc); + } + sb->s_flags |= MS_ACTIVE; + return sb; +} +#endif + +static ssize_t +cifs_read_wrapper(struct file * file, char *read_data, size_t read_size, + loff_t * poffset) +{ + if(file == NULL) + return -EIO; + else if(file->f_dentry == NULL) + return -EIO; + else if(file->f_dentry->d_inode == NULL) + return -EIO; + + if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead) { + return generic_file_read(file,read_data,read_size,poffset); + } else { + /* BB do we need to lock inode from here until after invalidate? */ +/* if(file->f_dentry->d_inode->i_mapping) { + filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); + filemap_fdatawait(file->f_dentry->d_inode->i_mapping); + }*/ +/* cifs_revalidate(file->f_dentry);*/ /* BB fixme */ + + /* BB we should make timer configurable - perhaps + by simply calling cifs_revalidate here */ + /* invalidate_remote_inode(file->f_dentry->d_inode);*/ + return generic_file_read(file,read_data,read_size,poffset); + } +} + +static ssize_t +cifs_write_wrapper(struct file * file, const char *write_data, + size_t write_size, loff_t * poffset) +{ + ssize_t written; + + if(file == NULL) + return -EIO; + else if(file->f_dentry == NULL) + return -EIO; + else if(file->f_dentry->d_inode == NULL) + return -EIO; + + /* check whether we can cache writes locally */ + written = generic_file_write(file,write_data,write_size,poffset); + if(!CIFS_I(file->f_dentry->d_inode)->clientCanCacheAll) { + if(file->f_dentry->d_inode->i_mapping) { + filemap_fdatasync(file->f_dentry->d_inode->i_mapping); + } + } + return written; +} + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +static struct file_system_type cifs_fs_type = { + .owner = THIS_MODULE, + .name = "cifs", + .get_sb = cifs_get_sb, + .kill_sb = kill_anon_super, + /* .fs_flags */ +}; +#endif + +static DECLARE_FSTYPE(cifs_fs_type, "cifs", cifs_read_super,0); + + +struct inode_operations cifs_dir_inode_ops = { + .create = cifs_create, + .lookup = cifs_lookup, + .unlink = cifs_unlink, + .link = cifs_hardlink, + .mkdir = cifs_mkdir, + .rmdir = cifs_rmdir, + .rename = cifs_rename, + .permission = cifs_permission, + .revalidate = cifs_revalidate, + .setattr = cifs_setattr, + .symlink = cifs_symlink, + .mknod = cifs_mknod, +}; + +struct inode_operations cifs_file_inode_ops = { + .revalidate = cifs_revalidate, + .setattr = cifs_setattr, +/* .getattr = cifs_getattr,*/ + .rename = cifs_rename, + .permission = cifs_permission, +#ifdef CONFIG_CIFS_XATTR + .setxattr = cifs_setxattr, + .getxattr = cifs_getxattr, + .listxattr = cifs_listxattr, + .removexattr = cifs_removexattr, +#endif +}; + +struct inode_operations cifs_symlink_inode_ops = { + .readlink = cifs_readlink, + .follow_link = cifs_follow_link, + .permission = cifs_permission, + /* BB add the following two eventually */ + /* revalidate: cifs_revalidate, + setattr: cifs_notify_change, *//* BB do we need notify change */ +#ifdef CONFIG_CIFS_XATTR + .setxattr = cifs_setxattr, + .getxattr = cifs_getxattr, + .listxattr = cifs_listxattr, + .removexattr = cifs_removexattr, +#endif +}; + +struct file_operations cifs_file_ops = { + .read = cifs_read_wrapper, + .write = cifs_write_wrapper, + .open = cifs_open, + .release = cifs_close, + .lock = cifs_lock, + .fsync = cifs_fsync, + .flush = cifs_flush, + .mmap = cifs_file_mmap, +/* .sendfile = generic_file_sendfile,*/ +#ifdef CONFIG_CIFS_FCNTL + .fcntl = cifs_fcntl, +#endif +}; + +struct file_operations cifs_dir_ops = { + .readdir = cifs_readdir, + .release = cifs_closedir, + .read = generic_read_dir, +#ifdef CONFIG_CIFS_FCNTL + .fcntl = cifs_fcntl, +#endif +}; +/* +static void +cifs_init_once(void *inode, kmem_cache_t * cachep, unsigned long flags) +{ + struct cifsInodeInfo *cifsi = (struct cifsInodeInfo *) inode; + + if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) == + SLAB_CTOR_CONSTRUCTOR) { + inode_init_once(&cifsi->vfs_inode); + INIT_LIST_HEAD(&cifsi->lockList); + } +} + +static int +cifs_init_inodecache(void) +{ + cifs_inode_cachep = kmem_cache_create("cifs_inode_cache", + sizeof (struct cifsInodeInfo), + 0, SLAB_HWCACHE_ALIGN, + cifs_init_once, NULL); + if (cifs_inode_cachep == NULL) + return -ENOMEM; + + + return 0; +} + +static void +cifs_destroy_inodecache(void) +{ + if (kmem_cache_destroy(cifs_inode_cachep)) + printk(KERN_WARNING "cifs_inode_cache: error freeing\n"); +} */ + +static int +cifs_init_request_bufs(void) +{ + cifs_req_cachep = kmem_cache_create("cifs_request", + CIFS_MAX_MSGSIZE + + MAX_CIFS_HDR_SIZE, 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if (cifs_req_cachep == NULL) + return -ENOMEM; + + return 0; +} + +static void +cifs_destroy_request_bufs(void) +{ + if (kmem_cache_destroy(cifs_req_cachep)) + printk(KERN_WARNING + "cifs_destroy_request_cache: error not all structures were freed\n"); +} + +static int +cifs_init_mids(void) +{ + cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids", + sizeof (struct mid_q_entry), 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if (cifs_mid_cachep == NULL) + return -ENOMEM; + cifs_oplock_cachep = kmem_cache_create("cifs_oplock_struct", + sizeof (struct oplock_q_entry), 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if (cifs_oplock_cachep == NULL) { + kmem_cache_destroy(cifs_mid_cachep); + return -ENOMEM; + } + + return 0; +} + +static void +cifs_destroy_mids(void) +{ + if (kmem_cache_destroy(cifs_mid_cachep)) + printk(KERN_WARNING + "cifs_destroy_mids: error not all structures were freed\n"); + if (kmem_cache_destroy(cifs_oplock_cachep)) + printk(KERN_WARNING + "error not all oplock structures were freed\n"); +} + +static int cifs_oplock_thread(void * dummyarg) +{ + struct oplock_q_entry * oplock_item; + struct cifsTconInfo *pTcon; + struct inode * inode; + __u16 netfid; + int rc = 0; + + daemonize(); + sprintf(current->comm,"cifsoplockd"); + + oplockThread = current; + do { + set_current_state(TASK_INTERRUPTIBLE); + + schedule_timeout(1*HZ); + spin_lock(&GlobalMid_Lock); + if(list_empty(&GlobalOplock_Q)) { + spin_unlock(&GlobalMid_Lock); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(39*HZ); + } else { + oplock_item = list_entry(GlobalOplock_Q.next, + struct oplock_q_entry, qhead); + if(oplock_item) { + cFYI(1,("found oplock item to write out")); + pTcon = oplock_item->tcon; + inode = oplock_item->pinode; + netfid = oplock_item->netfid; + spin_unlock(&GlobalMid_Lock); + DeleteOplockQEntry(oplock_item); + /* can not grab inode sem here since it would + deadlock when oplock received on delete + since vfs_unlink holds the i_sem across + the call */ + /* down(&inode->i_sem);*/ + if (S_ISREG(inode->i_mode)) { +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,17)) + rc = filemap_fdatasync(inode->i_mapping); + if(rc) + CIFS_I(inode)->write_behind_rc = rc; +#else + filemap_fdatasync(inode->i_mapping); +#endif + if(CIFS_I(inode)->clientCanCacheRead == 0) + invalidate_inode_pages(inode); + } else + rc = 0; + /* releasing a stale oplock after recent reconnection + of smb session using a now incorrect file + handle is not a data integrity issue but do + not bother sending an oplock release if session + to server still is disconnected since oplock + already released by the server in that case */ + if(pTcon->tidStatus != CifsNeedReconnect) { + rc = CIFSSMBLock(0, pTcon, + netfid, + 0 /* len */ , 0 /* offset */, 0, + 0, LOCKING_ANDX_OPLOCK_RELEASE, + 0 /* wait flag */); + cFYI(1,("Oplock release rc = %d ",rc)); + } + } else + spin_unlock(&GlobalMid_Lock); + } + } while(!signal_pending(current)); + complete_and_exit (&cifs_oplock_exited, 0); +} + +static int __init +init_cifs(void) +{ + int rc = 0; +#if CONFIG_PROC_FS + cifs_proc_init(); +#endif + INIT_LIST_HEAD(&GlobalServerList); /* BB not implemented yet */ + INIT_LIST_HEAD(&GlobalSMBSessionList); + INIT_LIST_HEAD(&GlobalTreeConnectionList); + INIT_LIST_HEAD(&GlobalOplock_Q); +/* + * Initialize Global counters + */ + atomic_set(&sesInfoAllocCount, 0); + atomic_set(&tconInfoAllocCount, 0); + atomic_set(&tcpSesReconnectCount, 0); + atomic_set(&tconInfoReconnectCount, 0); + + atomic_set(&bufAllocCount, 0); + atomic_set(&midCount, 0); + GlobalCurrentXid = 0; + GlobalTotalActiveXid = 0; + GlobalMaxActiveXid = 0; + GlobalSMBSeslock = RW_LOCK_UNLOCKED; + GlobalMid_Lock = SPIN_LOCK_UNLOCKED; + +/* rc = cifs_init_inodecache();*/ + if (!rc) { + rc = cifs_init_mids(); + if (!rc) { + rc = cifs_init_request_bufs(); + if (!rc) { + rc = register_filesystem(&cifs_fs_type); + if (!rc) { + kernel_thread(cifs_oplock_thread, NULL, + CLONE_FS | CLONE_FILES | CLONE_VM); + return rc; /* Success */ + } else + cifs_destroy_request_bufs(); + } + cifs_destroy_mids(); + } +/* cifs_destroy_inodecache(); */ + } +#if CONFIG_PROC_FS + cifs_proc_clean(); +#endif + return rc; +} + +static void __exit +exit_cifs(void) +{ + cFYI(0, ("In unregister ie exit_cifs")); +#if CONFIG_PROC_FS + cifs_proc_clean(); +#endif + unregister_filesystem(&cifs_fs_type); +/* cifs_destroy_inodecache();*/ + cifs_destroy_mids(); + cifs_destroy_request_bufs(); + if(oplockThread) { + send_sig(SIGTERM, oplockThread, 1); + wait_for_completion(&cifs_oplock_exited); + } +} + +MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>"); +MODULE_LICENSE("GPL"); /* combination of LGPL + GPL source behaves as GPL */ +MODULE_DESCRIPTION + ("VFS to access servers complying with the SNIA CIFS Specification e.g. Samba and Windows"); +module_init(init_cifs) +module_exit(exit_cifs) diff --git a/release/src/linux/linux/fs/cifs/cifsfs.h b/release/src/linux/linux/fs/cifs/cifsfs.h new file mode 100644 index 00000000..4f2da1e7 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/cifsfs.h @@ -0,0 +1,97 @@ +/* + * fs/cifs/cifsfs.h + * + * Copyright (c) International Business Machines Corp., 2002 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _CIFSFS_H +#define _CIFSFS_H + +#define ROOT_I 2 + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +extern int map_cifs_error(int error_class, int error_code, + int status_codes_negotiated); + +extern struct address_space_operations cifs_addr_ops; + +/* Functions related to super block operations */ +extern struct super_operations cifs_super_ops; +extern void cifs_put_inode(struct inode *); +extern void cifs_read_inode(struct inode *); +extern void cifs_delete_inode(struct inode *); +/* extern void cifs_write_inode(struct inode *); *//* BB not needed yet */ + +/* Functions related to inodes */ +extern struct inode_operations cifs_dir_inode_ops; +extern int cifs_create(struct inode *, struct dentry *, int); +extern struct dentry *cifs_lookup(struct inode *, struct dentry *); +extern int cifs_unlink(struct inode *, struct dentry *); +extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *); +extern int cifs_mknod(struct inode *, struct dentry *, int, int); +extern int cifs_mkdir(struct inode *, struct dentry *, int); +extern int cifs_rmdir(struct inode *, struct dentry *); +extern int cifs_rename(struct inode *, struct dentry *, struct inode *, + struct dentry *); +extern int cifs_revalidate(struct dentry *); +extern int cifs_setattr(struct dentry *, struct iattr *); + +extern struct inode_operations cifs_file_inode_ops; +extern void cifs_truncate_file(struct inode *); +extern struct inode_operations cifs_symlink_inode_ops; + +/* Functions related to files and directories */ +extern struct file_operations cifs_file_ops; +extern int cifs_open(struct inode *inode, struct file *file); +extern int cifs_close(struct inode *inode, struct file *file); +extern int cifs_closedir(struct inode *inode, struct file *file); +extern ssize_t cifs_read(struct file *file, char *read_data, + size_t read_size, loff_t * poffset); +extern ssize_t cifs_write(struct file *file, const char *write_data, + size_t write_size, loff_t * poffset); +extern int cifs_lock(struct file *, int, struct file_lock *); +extern int cifs_fsync(struct file *, struct dentry *, int); +extern int cifs_flush(struct file *); +extern int cifs_file_mmap(struct file * , struct vm_area_struct *); +extern struct file_operations cifs_dir_ops; +extern int cifs_dir_open(struct inode *inode, struct file *file); +extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir); +extern long cifs_fcntl(int, unsigned int, unsigned long, struct file *); + +/* Functions related to dir entries */ +extern struct dentry_operations cifs_dentry_ops; + +/* Functions related to symlinks */ +extern int cifs_follow_link(struct dentry *direntry, struct nameidata *nd); +extern int cifs_readlink(struct dentry *direntry, char *buffer, int buflen); +extern int cifs_symlink(struct inode *inode, struct dentry *direntry, + const char *symname); +extern int cifs_removexattr(struct dentry *, const char *); +extern int cifs_setxattr(struct dentry *, const char *, const void *, + size_t, int); +extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); +extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); +#define CIFS_VERSION "1.20" +#endif /* _CIFSFS_H */ diff --git a/release/src/linux/linux/fs/cifs/cifsglob.h b/release/src/linux/linux/fs/cifs/cifsglob.h new file mode 100644 index 00000000..e8991b79 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/cifsglob.h @@ -0,0 +1,413 @@ +/* + * fs/cifs/cifsglob.h + * + * Copyright (C) International Business Machines Corp., 2002,2003 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + */ +#include <linux/in.h> +#include <linux/in6.h> +#include "cifs_fs_sb.h" +/* + * The sizes of various internal tables and strings + */ +#define MAX_UID_INFO 16 +#define MAX_SES_INFO 2 +#define MAX_TCON_INFO 4 + +#define MAX_TREE_SIZE 2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1 +#define MAX_SERVER_SIZE 15 +#define MAX_SHARE_SIZE 64 /* used to be 20 - this should still be enough */ +#define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null + termination then *2 for unicode versions */ +#define MAX_PASSWORD_SIZE 16 + +/* + * MAX_REQ is the maximum number of requests that WE will send + * on one socket concurently. It also matches the most common + * value of max multiplex returned by servers. We may + * eventually want to use the negotiated value (in case + * future servers can handle more) when we are more confident that + * we will not have problems oveloading the socket with pending + * write data. + */ +#define CIFS_MAX_REQ 50 + +#define SERVER_NAME_LENGTH 15 +#define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1) + +/* used to define string lengths for reversing unicode strings */ +/* (256+1)*2 = 514 */ +/* (max path length + 1 for null) * 2 for unicode */ +#define MAX_NAME 514 + +#include "cifspdu.h" + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef XATTR_DOS_ATTRIB +#define XATTR_DOS_ATTRIB "user.DOSATTRIB" +#endif + +/* + * This information is kept on every Server we know about. + * + * Some things to note: + * + */ +#define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1) + +/* + * CIFS vfs client Status information (based on what we know.) + */ + + /* associated with each tcp and smb session */ +enum statusEnum { + CifsNew = 0, + CifsGood, + CifsExiting, + CifsNeedReconnect +}; + +enum securityEnum { + NTLM = 0, /* Legacy NTLM012 auth with NTLM hash */ + NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ + RawNTLMSSP, /* NTLMSSP without SPNEGO */ + NTLMSSP, /* NTLMSSP via SPNEGO */ + Kerberos /* Kerberos via SPNEGO */ +}; + +enum protocolEnum { + IPV4 = 0, + IPV6, + SCTP + /* Netbios frames protocol not supported at this time */ +}; + +/* + ***************************************************************** + * Except the CIFS PDUs themselves all the + * globally interesting structs should go here + ***************************************************************** + */ + +struct TCP_Server_Info { + char server_Name[SERVER_NAME_LEN_WITH_NULL]; /* 15 chars + X'20'in 16th */ + char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; /* Unicode version of server_Name */ + struct socket *ssocket; + union { + struct sockaddr_in sockAddr; + struct sockaddr_in6 sockAddr6; + } addr; + wait_queue_head_t response_q; + wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/ + struct list_head pending_mid_q; + void *Server_NlsInfo; /* BB - placeholder for future NLS info */ + unsigned short server_codepage; /* codepage for the server */ + unsigned long ip_address; /* IP addr for the server if known */ + enum protocolEnum protocolType; + char versionMajor; + char versionMinor; + int svlocal:1; /* local server or remote */ + atomic_t socketUseCount; /* number of open cifs sessions on socket */ + atomic_t inFlight; /* number of requests on the wire to server */ + enum statusEnum tcpStatus; /* what we think the status is */ + struct semaphore tcpSem; + struct task_struct *tsk; + char server_GUID[16]; + char secMode; + enum securityEnum secType; + unsigned int maxReq; /* Clients should submit no more */ + /* than maxReq distinct unanswered SMBs to the server when using */ + /* multiplexed reads or writes */ + unsigned int maxBuf; /* maxBuf specifies the maximum */ + /* message size the server can send or receive for non-raw SMBs */ + unsigned int maxRw; /* maxRw specifies the maximum */ + /* message size the server can send or receive for */ + /* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */ + char sessid[4]; /* unique token id for this session */ + /* (returned on Negotiate */ + int capabilities; /* allow selective disabling of caps by smb sess */ + __u16 timeZone; + char cryptKey[CIFS_CRYPTO_KEY_SIZE]; + char workstation_RFC1001_name[16]; /* 16th byte is always zero */ +}; + +/* + * The following is our shortcut to user information. We surface the uid, + * and name. We always get the password on the fly in case it + * has changed. We also hang a list of sessions owned by this user off here. + */ +struct cifsUidInfo { + struct list_head userList; + struct list_head sessionList; /* SMB sessions for this user */ + uid_t linux_uid; + char user[MAX_USERNAME_SIZE + 1]; /* ascii name of user */ + /* BB may need ptr or callback for PAM or WinBind info */ +}; + +/* + * Session structure. One of these for each uid session with a particular host + */ +struct cifsSesInfo { + struct list_head cifsSessionList; + struct semaphore sesSem; + struct cifsUidInfo *uidInfo; /* pointer to user info */ + struct TCP_Server_Info *server; /* pointer to server info */ + atomic_t inUse; /* # of mounts (tree connections) on this ses */ + enum statusEnum status; + __u32 sequence_number; /* needed for CIFS PDU signature */ + __u16 ipc_tid; /* special tid for connection to IPC share */ + char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; + char *serverOS; /* name of operating system underlying the server */ + char *serverNOS; /* name of network operating system that the server is running */ + char *serverDomain; /* security realm of server */ + int Suid; /* remote smb uid */ + uid_t linux_uid; /* local Linux uid */ + int capabilities; + char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for tcp names - will ipv6 and sctp addresses fit here?? */ + char userName[MAX_USERNAME_SIZE + 1]; + char domainName[MAX_USERNAME_SIZE + 1]; + char * password; +}; + +/* + * there is one of these for each connection to a resource on a particular + * session + */ +struct cifsTconInfo { + struct list_head cifsConnectionList; + struct list_head openFileList; + struct semaphore tconSem; + struct cifsSesInfo *ses; /* pointer to session associated with */ + char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource (in ASCII not UTF) */ + char *nativeFileSystem; + __u16 tid; /* The 2 byte tree id */ + __u16 Flags; /* optional support bits */ + enum statusEnum tidStatus; + atomic_t useCount; /* how many mounts (explicit or implicit) to this share */ +#ifdef CONFIG_CIFS_STATS + atomic_t num_smbs_sent; + atomic_t num_writes; + atomic_t num_reads; + atomic_t num_oplock_brks; + atomic_t num_opens; + atomic_t num_deletes; + atomic_t num_mkdirs; + atomic_t num_rmdirs; + atomic_t num_renames; + atomic_t num_t2renames; + __u64 bytes_read; + __u64 bytes_written; + spinlock_t stat_lock; +#endif + FILE_SYSTEM_DEVICE_INFO fsDevInfo; + FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */ + FILE_SYSTEM_UNIX_INFO fsUnixInfo; + int retry:1; + /* BB add field for back pointer to sb struct? */ +}; + +/* + * This info hangs off the cifsFileInfo structure. This is used to track + * byte stream locks on the file + */ +struct cifsLockInfo { + struct cifsLockInfo *next; + int start; + int length; + int type; +}; + +/* + * One of these for each open instance of a file + */ +struct cifsFileInfo { + struct list_head tlist; /* pointer to next fid owned by tcon */ + struct list_head flist; /* next fid (file instance) for this inode */ + unsigned int uid; /* allows finding which FileInfo structure */ + __u32 pid; /* process id who opened file */ + __u16 netfid; /* file id from remote */ + /* BB add lock scope info here if needed */ ; + /* lock scope id (0 if none) */ + struct file * pfile; /* needed for writepage */ + struct inode * pInode; /* needed for oplock break */ + int endOfSearch:1; /* we have reached end of search */ + int closePend:1; /* file is marked to close */ + int emptyDir:1; + int invalidHandle:1; /* file closed via session abend */ + struct semaphore fh_sem; /* prevents reopen race after dead ses*/ + char * search_resume_name; + unsigned int resume_name_length; + __u32 resume_key; +}; + +/* + * One of these for each file inode + */ + +struct cifsInodeInfo { + struct list_head lockList; + /* BB add in lists for dirty pages - i.e. write caching info for oplock */ + struct list_head openFileList; + int write_behind_rc; + __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ + atomic_t inUse; /* num concurrent users (local openers cifs) of file*/ + unsigned long time; /* jiffies of last update/check of inode */ + int clientCanCacheRead:1; /* read oplock */ + int clientCanCacheAll:1; /* read and writebehind oplock */ + int oplockPending:1; + struct inode vfs_inode; +}; + +static inline struct cifsInodeInfo * CIFS_I(struct inode *inode) +{ + return (struct cifsInodeInfo *)&(inode->u); +} + +static inline struct cifs_sb_info * CIFS_SB(struct super_block *sb) +{ + return (struct cifs_sb_info *) &(sb->u); +} + + +/* one of these for every pending CIFS request to the server */ +struct mid_q_entry { + struct list_head qhead; /* mids waiting on reply from this server */ + __u16 mid; /* multiplex id */ + __u16 pid; /* process id */ + __u32 sequence_number; /* for CIFS signing */ + __u16 command; /* smb command code */ + struct timeval when_sent; /* time when smb sent */ + struct cifsSesInfo *ses; /* smb was sent to this server */ + struct task_struct *tsk; /* task waiting for response */ + struct smb_hdr *resp_buf; /* response buffer */ + int midState; /* wish this were enum but can not pass to wait_event */ +}; + +struct oplock_q_entry { + struct list_head qhead; + struct inode * pinode; + struct cifsTconInfo * tcon; + __u16 netfid; +}; + +#define MID_FREE 0 +#define MID_REQUEST_ALLOCATED 1 +#define MID_REQUEST_SUBMITTED 2 +#define MID_RESPONSE_RECEIVED 4 +#define MID_RETRY_NEEDED 8 /* session closed while this request out */ + +/* + ***************************************************************** + * All constants go here + ***************************************************************** + */ + +#define UID_HASH (16) + +/* + * Note that ONE module should define _DECLARE_GLOBALS_HERE to cause the + * following to be declared. + */ + +/**************************************************************************** + * Locking notes. All updates to global variables and lists should be + * protected by spinlocks or semaphores. + * + * Spinlocks + * --------- + * GlobalMid_Lock protects: + * list operations on pending_mid_q and oplockQ + * updates to XID counters, multiplex id and SMB sequence numbers + * GlobalSMBSesLock protects: + * list operations on tcp and SMB session lists and tCon lists + * f_owner.lock protects certain per file struct operations + * mapping->page_lock protects certain per page operations + * + * Semaphores + * ---------- + * sesSem operations on smb session + * tconSem operations on tree connection + * fh_sem file handle reconnection operations + * + ****************************************************************************/ + +#ifdef DECLARE_GLOBALS_HERE +#define GLOBAL_EXTERN +#else +#define GLOBAL_EXTERN extern +#endif + +/* + * The list of servers that did not respond with NT LM 0.12. + * This list helps improve performance and eliminate the messages indicating + * that we had a communications error talking to the server in this list. + */ +GLOBAL_EXTERN struct servers_not_supported *NotSuppList; /*@z4a */ + +/* + * The following is a hash table of all the users we know about. + */ +GLOBAL_EXTERN struct smbUidInfo *GlobalUidList[UID_HASH]; + +GLOBAL_EXTERN struct list_head GlobalServerList; /* BB not implemented yet */ +GLOBAL_EXTERN struct list_head GlobalSMBSessionList; +GLOBAL_EXTERN struct list_head GlobalTreeConnectionList; +GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ + +GLOBAL_EXTERN struct list_head GlobalOplock_Q; + +/* + * Global transaction id (XID) information + */ +GLOBAL_EXTERN unsigned int GlobalCurrentXid; /* protected by GlobalMid_Sem */ +GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */ +GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */ +GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above and list operations */ + /* on midQ entries */ +GLOBAL_EXTERN char Local_System_Name[15]; + +/* + * Global counters, updated atomically + */ +GLOBAL_EXTERN atomic_t sesInfoAllocCount; +GLOBAL_EXTERN atomic_t tconInfoAllocCount; + +GLOBAL_EXTERN atomic_t tcpSesReconnectCount; +GLOBAL_EXTERN atomic_t tconInfoReconnectCount; + +/* Various Debug counters to remove someday (BB) */ +GLOBAL_EXTERN atomic_t bufAllocCount; +GLOBAL_EXTERN atomic_t midCount; + +/* Misc globals */ +GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions + to be established on existing mount if we + have the uid/password or Kerberos credential + or equivalent for current user */ +GLOBAL_EXTERN unsigned int oplockEnabled; +GLOBAL_EXTERN unsigned int quotaEnabled; +GLOBAL_EXTERN unsigned int lookupCacheEnabled; +GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent + with more secure ntlmssp2 challenge/resp */ +GLOBAL_EXTERN unsigned int ntlmv2_support; /* better optional password hash */ +GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */ +GLOBAL_EXTERN unsigned int linuxExtEnabled; /* enable Linux/Unix CIFS extensions */ + diff --git a/release/src/linux/linux/fs/cifs/cifspdu.h b/release/src/linux/linux/fs/cifs/cifspdu.h new file mode 100644 index 00000000..067eb4e3 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/cifspdu.h @@ -0,0 +1,1793 @@ +/* + * fs/cifs/cifspdu.h + * + * Copyright (c) International Business Machines Corp., 2002 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _CIFSPDU_H +#define _CIFSPDU_H + +#include <net/sock.h> + +#define CIFS_PROT 0 +#define BAD_PROT CIFS_PROT+1 + +/* SMB command codes */ +#define SMB_COM_CREATE_DIRECTORY 0x00 +#define SMB_COM_DELETE_DIRECTORY 0x01 +#define SMB_COM_CLOSE 0x04 +#define SMB_COM_DELETE 0x06 +#define SMB_COM_RENAME 0x07 +#define SMB_COM_LOCKING_ANDX 0x24 +#define SMB_COM_COPY 0x29 +#define SMB_COM_READ_ANDX 0x2E +#define SMB_COM_WRITE_ANDX 0x2F +#define SMB_COM_TRANSACTION2 0x32 +#define SMB_COM_TRANSACTION2_SECONDARY 0x33 +#define SMB_COM_FIND_CLOSE2 0x34 +#define SMB_COM_TREE_DISCONNECT 0x71 +#define SMB_COM_NEGOTIATE 0x72 +#define SMB_COM_SESSION_SETUP_ANDX 0x73 +#define SMB_COM_LOGOFF_ANDX 0x74 +#define SMB_COM_TREE_CONNECT_ANDX 0x75 +#define SMB_COM_NT_TRANSACT 0xA0 +#define SMB_COM_NT_TRANSACT_SECONDARY 0xA1 +#define SMB_COM_NT_CREATE_ANDX 0xA2 +#define SMB_COM_NT_RENAME 0xA5 + +/* Transact2 subcommand codes */ +#define TRANS2_OPEN 0x00 +#define TRANS2_FIND_FIRST 0x01 +#define TRANS2_FIND_NEXT 0x02 +#define TRANS2_QUERY_FS_INFORMATION 0x03 +#define TRANS2_QUERY_PATH_INFORMATION 0x05 +#define TRANS2_SET_PATH_INFORMATION 0x06 +#define TRANS2_QUERY_FILE_INFORMATION 0x07 +#define TRANS2_SET_FILE_INFORMATION 0x08 +#define TRANS2_GET_DFS_REFERRAL 0x10 +#define TRANS2_REPORT_DFS_INCOSISTENCY 0x11 + +/* NT Transact subcommand codes */ +#define NT_TRANSACT_CREATE 0x01 +#define NT_TRANSACT_IOCTL 0x02 +#define NT_TRANSACT_SET_SECURITY_DESC 0x03 +#define NT_TRANSACT_NOTIFY_CHANGE 0x04 +#define NT_TRANSACT_RENAME 0x05 +#define NT_TRANSACT_QUERY_SECURITY_DESC 0x06 +#define NT_TRANSACT_GET_USER_QUOTA 0x07 +#define NT_TRANSACT_SET_USER_QUOTA 0x08 + +#define MAX_CIFS_HDR_SIZE 256 /* chained NTCreateXReadX will probably be biggest */ + +/* internal cifs vfs structures */ +/***************************************************************** + * All constants go here + ***************************************************************** + */ + +/* + * Starting value for maximum SMB size negotiation + */ +#define CIFS_MAX_MSGSIZE (4*4096) + +/* + * Size of encrypted user password in bytes + */ +#define CIFS_ENCPWD_SIZE (16) + +/* + * Size of the crypto key returned on the negotiate SMB in bytes + */ +#define CIFS_CRYPTO_KEY_SIZE (8) + +/* + * Size of the session key (crypto key encrypted with the password + */ +#define CIFS_SESSION_KEY_SIZE (24) + +/* + * Maximum user name length + */ +#define CIFS_UNLEN (20) + +/* + * Flags on SMB open + */ +#define SMBOPEN_WRITE_THROUGH 0x4000 +#define SMBOPEN_DENY_ALL 0x0010 +#define SMBOPEN_DENY_WRITE 0x0020 +#define SMBOPEN_DENY_READ 0x0030 +#define SMBOPEN_DENY_NONE 0x0040 +#define SMBOPEN_READ 0x0000 +#define SMBOPEN_WRITE 0x0001 +#define SMBOPEN_READWRITE 0x0002 +#define SMBOPEN_EXECUTE 0x0003 + +#define SMBOPEN_OCREATE 0x0010 +#define SMBOPEN_OTRUNC 0x0002 +#define SMBOPEN_OAPPEND 0x0001 + +/* + * SMB flag definitions + */ +#define SMBFLG_EXTD_LOCK 0x01 /* server supports lock-read write-unlock primitives */ +#define SMBFLG_RCV_POSTED 0x02 /* obsolete */ +#define SMBFLG_RSVD 0x04 +#define SMBFLG_CASELESS 0x08 /* all pathnames treated as caseless (off implies case sensitive file handling requested) */ +#define SMBFLG_CANONICAL_PATH_FORMAT 0x10 /* obsolete */ +#define SMBFLG_OLD_OPLOCK 0x20 /* obsolete */ +#define SMBFLG_OLD_OPLOCK_NOTIFY 0x40 /* obsolete */ +#define SMBFLG_RESPONSE 0x80 /* this PDU is a response from server */ + +/* + * SMB flag2 definitions + */ +#define SMBFLG2_KNOWS_LONG_NAMES 0x0001 /* can send long (non-8.3) path names in response */ +#define SMBFLG2_KNOWS_EAS 0x0002 +#define SMBFLG2_SECURITY_SIGNATURE 0x0004 +#define SMBFLG2_IS_LONG_NAME 0x0040 +#define SMBFLG2_EXT_SEC 0x0800 +#define SMBFLG2_DFS 0x1000 +#define SMBFLG2_PAGING_IO 0x2000 +#define SMBFLG2_ERR_STATUS 0x4000 +#define SMBFLG2_UNICODE 0x8000 + +/* + * These are the file access permission bits defined in CIFS for the + * NTCreateAndX as well as the level 0x107 + * TRANS2_QUERY_PATH_INFORMATION API. The level 0x107, SMB_QUERY_FILE_ALL_INFO + * responds with the AccessFlags. + * The AccessFlags specifies the access permissions a caller has to the + * file and can have any suitable combination of the following values: + */ + +#define FILE_READ_DATA 0x00000001 /* Data can be read from the file */ +#define FILE_WRITE_DATA 0x00000002 /* Data can be written to the file */ +#define FILE_APPEND_DATA 0x00000004 /* Data can be appended to the file */ +#define FILE_READ_EA 0x00000008 /* Extended attributes associated */ + /* with the file can be read */ +#define FILE_WRITE_EA 0x00000010 /* Extended attributes associated */ + /* with the file can be written */ +#define FILE_EXECUTE 0x00000020 /*Data can be read into memory from */ + /* the file using system paging I/O */ +#define FILE_DELETE_CHILD 0x00000040 +#define FILE_READ_ATTRIBUTES 0x00000080 /* Attributes associated with the */ + /* file can be read */ +#define FILE_WRITE_ATTRIBUTES 0x00000100 /* Attributes associated with the */ + /* file can be written */ +#define DELETE 0x00010000 /* The file can be deleted */ +#define READ_CONTROL 0x00020000 /* The access control list and */ + /* ownership associated with the */ + /* file can be read */ +#define WRITE_DAC 0x00040000 /* The access control list and */ + /* ownership associated with the */ + /* file can be written. */ +#define WRITE_OWNER 0x00080000 /* Ownership information associated */ + /* with the file can be written */ +#define SYNCHRONIZE 0x00100000 /* The file handle can waited on to */ + /* synchronize with the completion */ + /* of an input/output request */ +#define GENERIC_ALL 0x10000000 +#define GENERIC_EXECUTE 0x20000000 +#define GENERIC_WRITE 0x40000000 +#define GENERIC_READ 0x80000000 + /* In summary - Relevant file */ + /* access flags from CIFS are */ + /* file_read_data, file_write_data */ + /* file_execute, file_read_attributes */ + /* write_dac, and delete. */ + +/* + * Invalid readdir handle + */ +#define CIFS_NO_HANDLE 0xFFFF + +/* IPC$ in ASCII */ +#define CIFS_IPC_RESOURCE "\x49\x50\x43\x24" + +/* IPC$ in Unicode */ +#define CIFS_IPC_UNICODE_RESOURCE "\x00\x49\x00\x50\x00\x43\x00\x24\x00\x00" + +/* Unicode Null terminate 2 bytes of 0 */ +#define UNICODE_NULL "\x00\x00" +#define ASCII_NULL 0x00 + +/* + * Server type values (returned on EnumServer API + */ +#define CIFS_SV_TYPE_DC 0x00000008 +#define CIFS_SV_TYPE_BACKDC 0x00000010 + +/* + * Alias type flags (From EnumAlias API call + */ +#define CIFS_ALIAS_TYPE_FILE 0x0001 +#define CIFS_SHARE_TYPE_FILE 0x0000 + +/* + * File Attribute flags + */ +#define ATTR_READONLY 0x0001 +#define ATTR_HIDDEN 0x0002 +#define ATTR_SYSTEM 0x0004 +#define ATTR_VOLUME 0x0008 +#define ATTR_DIRECTORY 0x0010 +#define ATTR_ARCHIVE 0x0020 +#define ATTR_DEVICE 0x0040 +#define ATTR_NORMAL 0x0080 +#define ATTR_TEMPORARY 0x0100 +#define ATTR_SPARSE 0x0200 +#define ATTR_REPARSE 0x0400 +#define ATTR_COMPRESSED 0x0800 +#define ATTR_OFFLINE 0x1000 /* ie file not immediately available - offline storage */ +#define ATTR_NOT_CONTENT_INDEXED 0x2000 +#define ATTR_ENCRYPTED 0x4000 +#define ATTR_POSIX_SEMANTICS 0x01000000 +#define ATTR_BACKUP_SEMANTICS 0x02000000 +#define ATTR_DELETE_ON_CLOSE 0x04000000 +#define ATTR_SEQUENTIAL_SCAN 0x08000000 +#define ATTR_RANDOM_ACCESS 0x10000000 +#define ATTR_NO_BUFFERING 0x20000000 +#define ATTR_WRITE_THROUGH 0x80000000 + +/* ShareAccess flags */ +#define FILE_NO_SHARE 0x00000000 +#define FILE_SHARE_READ 0x00000001 +#define FILE_SHARE_WRITE 0x00000002 +#define FILE_SHARE_DELETE 0x00000004 +#define FILE_SHARE_ALL 0x00000007 + +/* CreateDisposition flags */ +#define FILE_SUPERSEDE 0x00000000 +#define FILE_OPEN 0x00000001 +#define FILE_CREATE 0x00000002 +#define FILE_OPEN_IF 0x00000003 +#define FILE_OVERWRITE 0x00000004 +#define FILE_OVERWRITE_IF 0x00000005 + +/* CreateOptions */ +#define CREATE_NOT_FILE 0x00000001 /* if set must not be file */ +#define CREATE_WRITE_THROUGH 0x00000002 +#define CREATE_NOT_DIR 0x00000040 /* if set must not be directory */ +#define CREATE_RANDOM_ACCESS 0x00000800 +#define CREATE_DELETE_ON_CLOSE 0x00001000 +#define OPEN_REPARSE_POINT 0x00200000 + +/* ImpersonationLevel flags */ +#define SECURITY_ANONYMOUS 0 +#define SECURITY_IDENTIFICATION 1 +#define SECURITY_IMPERSONATION 2 +#define SECURITY_DELEGATION 3 + +/* SecurityFlags */ +#define SECURITY_CONTEXT_TRACKING 0x01 +#define SECURITY_EFFECTIVE_ONLY 0x02 + +/* + * Default PID value, used in all SMBs where the PID is not important + */ +#define CIFS_DFT_PID 0x1234 + +/* + * We use the same routine for Copy and Move SMBs. This flag is used to + * distinguish + */ +#define CIFS_COPY_OP 1 +#define CIFS_RENAME_OP 2 + +#define GETU16(var) (*((__u16 *)var)) /* BB check for endian issues */ +#define GETU32(var) (*((__u32 *)var)) /* BB check for endian issues */ + +#pragma pack(1) + +struct smb_hdr { + __u32 smb_buf_length; /* big endian on wire *//* BB length is only two or three bytes - with one or two byte type preceding it but that is always zero - we could mask the type byte off just in case BB */ + __u8 Protocol[4]; + __u8 Command; + union { + struct { + __u8 ErrorClass; + __u8 Reserved; + __u16 Error; /* note: treated as little endian (le) on wire */ + } DosError; + __u32 CifsError; /* note: le */ + } Status; + __u8 Flags; + __u16 Flags2; /* note: le */ + __u16 PidHigh; /* note: le */ + union { + struct { + __u32 SequenceNumber; /* le */ + __u32 Reserved; /* zero */ + } Sequence; + __u8 SecuritySignature[8]; /* le */ + } Signature; + __u8 pad[2]; + __u16 Tid; + __u16 Pid; /* note: le */ + __u16 Uid; + __u16 Mid; + __u8 WordCount; +}; +/* given a pointer to an smb_hdr retrieve the value of byte count */ +#define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) + +/* given a pointer to an smb_hdr retrieve the pointer to the byte area */ +#define pByteArea(smb_var) ((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 ) + +/* + * Computer Name Length + */ +#define CNLEN 15 + +/* + * Share Name Length @S8A + * Note: This length is limited by the SMB used to get @S8A + * the Share info. NetShareEnum only returns 13 @S8A + * chars, including the null termination. @S8A + */ +#define SNLEN 12 /*@S8A */ + +/* + * Comment Length + */ +#define MAXCOMMENTLEN 40 + +/* + * The OS/2 maximum path name + */ +#define MAX_PATHCONF 256 + +/* + * SMB frame definitions (following must be packed structs) + * See the SNIA CIFS Specification for details. + * + * The Naming convention is the lower case version of the + * smb command code name for the struct and this is typedef to the + * uppercase version of the same name with the prefix SMB_ removed + * for brevity. Although typedefs are not commonly used for + * structure definitions in the Linux kernel, their use in the + * CIFS standards document, which this code is based on, may + * make this one of the cases where typedefs for structures make + * sense to improve readability for readers of the standards doc. + * Typedefs can always be removed later if they are too distracting + * and they are only used for the CIFSs PDUs themselves, not + * internal cifs vfs structures + * + */ + +typedef struct negotiate_req { + struct smb_hdr hdr; /* wct = 0 */ + __u16 ByteCount; + unsigned char DialectsArray[1]; +} NEGOTIATE_REQ; + +typedef struct negotiate_rsp { + struct smb_hdr hdr; /* wct = 17 */ + __u16 DialectIndex; + __u8 SecurityMode; + __u16 MaxMpxCount; + __u16 MaxNumberVcs; + __u32 MaxBufferSize; + __u32 MaxRawSize; + __u32 SessionKey; + __u32 Capabilities; /* see below */ + __u32 SystemTimeLow; + __u32 SystemTimeHigh; + __u16 ServerTimeZone; + __u8 EncryptionKeyLength; + __u16 ByteCount; + union { + unsigned char EncryptionKey[1]; /* if cap extended security is off */ + /* followed by Domain name - if extended security is off */ + /* followed by 16 bytes of server GUID */ + /* followed by security blob if cap_extended_security negotiated */ + struct { + unsigned char GUID[16]; + unsigned char SecurityBlob[1]; + } extended_response; + } u; +} NEGOTIATE_RSP; + +/* SecurityMode bits */ +#define SECMODE_USER 0x01 /* off indicates share level security */ +#define SECMODE_PW_ENCRYPT 0x02 +#define SECMODE_SIGN_ENABLED 0x04 /* SMB security signatures enabled */ +#define SECMODE_SIGN_REQUIRED 0x08 /* SMB security signatures required */ + +/* Negotiate response Capabilities */ +#define CAP_RAW_MODE 0x00000001 +#define CAP_MPX_MODE 0x00000002 +#define CAP_UNICODE 0x00000004 +#define CAP_LARGE_FILES 0x00000008 +#define CAP_NT_SMBS 0x00000010 /* implies CAP_NT_FIND */ +#define CAP_RPC_REMOTE_APIS 0x00000020 +#define CAP_STATUS32 0x00000040 +#define CAP_LEVEL_II_OPLOCKS 0x00000080 +#define CAP_LOCK_AND_READ 0x00000100 +#define CAP_NT_FIND 0x00000200 +#define CAP_DFS 0x00001000 +#define CAP_INFOLEVEL_PASSTHRU 0x00002000 +#define CAP_LARGE_READ_X 0x00004000 +#define CAP_LARGE_WRITE_X 0x00008000 +#define CAP_UNIX 0x00800000 +#define CAP_RESERVED 0x02000000 +#define CAP_BULK_TRANSFER 0x20000000 +#define CAP_COMPRESSED_DATA 0x40000000 +#define CAP_EXTENDED_SECURITY 0x80000000 + +typedef union smb_com_session_setup_andx { + struct { /* request format */ + struct smb_hdr hdr; /* wct = 12 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 MaxBufferSize; + __u16 MaxMpxCount; + __u16 VcNumber; + __u32 SessionKey; + __u16 SecurityBlobLength; + __u32 Reserved; + __u32 Capabilities; /* see below */ + __u16 ByteCount; + unsigned char SecurityBlob[1]; /* followed by */ + /* STRING NativeOS */ + /* STRING NativeLanMan */ + } req; /* NTLM request format (with extended security */ + + struct { /* request format */ + struct smb_hdr hdr; /* wct = 13 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 MaxBufferSize; + __u16 MaxMpxCount; + __u16 VcNumber; + __u32 SessionKey; + __u16 CaseInsensitivePasswordLength; /* ASCII password length */ + __u16 CaseSensitivePasswordLength; /* Unicode password length */ + __u32 Reserved; /* see below */ + __u32 Capabilities; + __u16 ByteCount; + unsigned char CaseInsensitivePassword[1]; /* followed by: */ + /* unsigned char * CaseSensitivePassword; */ + /* STRING AccountName */ + /* STRING PrimaryDomain */ + /* STRING NativeOS */ + /* STRING NativeLanMan */ + } req_no_secext; /* NTLM request format (without extended security */ + + struct { /* default (NTLM) response format */ + struct smb_hdr hdr; /* wct = 4 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 Action; /* see below */ + __u16 SecurityBlobLength; + __u16 ByteCount; + unsigned char SecurityBlob[1]; /* followed by */ +/* unsigned char * NativeOS; */ +/* unsigned char * NativeLanMan; */ +/* unsigned char * PrimaryDomain; */ + } resp; /* NTLM response format (with or without extended security */ + + struct { /* request format */ + struct smb_hdr hdr; /* wct = 10 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 MaxBufferSize; + __u16 MaxMpxCount; + __u16 VcNumber; + __u32 SessionKey; + __u16 PassswordLength; + __u32 Reserved; + __u16 ByteCount; + unsigned char AccountPassword[1]; /* followed by */ + /* STRING AccountName */ + /* STRING PrimaryDomain */ + /* STRING NativeOS */ + /* STRING NativeLanMan */ + } old_req; /* pre-NTLM (LANMAN2.1) request format */ + + struct { /* default (NTLM) response format */ + struct smb_hdr hdr; /* wct = 3 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 Action; /* see below */ + __u16 ByteCount; + unsigned char NativeOS[1]; /* followed by */ +/* unsigned char * NativeLanMan; */ +/* unsigned char * PrimaryDomain; */ + } old_resp; /* pre-NTLM (LANMAN2.1) response format */ +} SESSION_SETUP_ANDX; + +#define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux" + +/* Capabilities bits (for NTLM SessSetup request) */ +#define CAP_UNICODE 0x00000004 +#define CAP_LARGE_FILES 0x00000008 +#define CAP_NT_SMBS 0x00000010 +#define CAP_STATUS32 0x00000040 +#define CAP_LEVEL_II_OPLOCKS 0x00000080 +#define CAP_NT_FIND 0x00000200 /* reserved should be zero (presumably because NT_SMBs implies the same thing) */ +#define CAP_BULK_TRANSFER 0x20000000 +#define CAP_EXTENDED_SECURITY 0x80000000 + +/* Action bits */ +#define GUEST_LOGIN 1 + +typedef struct smb_com_tconx_req { + struct smb_hdr hdr; /* wct = 4 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 Flags; /* see below */ + __u16 PasswordLength; + __u16 ByteCount; + unsigned char Password[1]; /* followed by */ +/* STRING Path *//* \\server\share name */ + /* STRING Service */ +} TCONX_REQ; + +typedef struct smb_com_tconx_rsp { + struct smb_hdr hdr; /* wct = 3 *//* note that Win2000 has sent wct=7 in some cases on responses. Four unspecified words followed OptionalSupport */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 OptionalSupport; /* see below */ + __u16 ByteCount; + unsigned char Service[1]; /* always ASCII, not Unicode */ + /* STRING NativeFileSystem */ +} TCONX_RSP; + +/* tree connect Flags */ +#define DISCONNECT_TID 0x0001 +#define TCON_EXTENDED_SECINFO 0x0008 +/* OptionalSupport bits */ +#define SMB_SUPPORT_SEARCH_BITS 0x0001 /* must have bits (exclusive searches suppt. */ +#define SMB_SHARE_IS_IN_DFS 0x0002 + +typedef struct smb_com_logoff_andx_req { + + struct smb_hdr hdr; /* wct = 2 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 ByteCount; +} LOGOFF_ANDX_REQ; + +typedef struct smb_com_logoff_andx_rsp { + struct smb_hdr hdr; /* wct = 2 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 ByteCount; +} LOGOFF_ANDX_RSP; + +typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on tree_connect PDU to effect disconnect *//* probably the simplest SMB PDU */ + struct { + struct smb_hdr hdr; /* wct = 0 */ + __u16 ByteCount; /* bcc = 0 */ + } req; + struct { + struct smb_hdr hdr; /* wct = 0 */ + __u16 ByteCount; /* bcc = 0 */ + } resp; +} TREE_DISCONNECT; + +typedef struct smb_com_close_req { + struct smb_hdr hdr; /* wct = 3 */ + __u16 FileID; + __u32 LastWriteTime; /* should be zero */ + __u16 ByteCount; /* 0 */ +} CLOSE_REQ; + +typedef struct smb_com_close_rsp { + struct smb_hdr hdr; /* wct = 0 */ + __u16 ByteCount; /* bct = 0 */ +} CLOSE_RSP; + +typedef struct smb_com_findclose_req { + struct smb_hdr hdr; /* wct = 1 */ + __u16 FileID; + __u16 ByteCount; /* 0 */ +} FINDCLOSE_REQ; + +/* OpenFlags */ +#define REQ_OPLOCK 0x00000002 +#define REQ_BATCHOPLOCK 0x00000004 +#define REQ_OPENDIRONLY 0x00000008 + +typedef struct smb_com_open_req { /* also handles create */ + struct smb_hdr hdr; /* wct = 24 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u8 Reserved; /* Must Be Zero */ + __u16 NameLength; + __u32 OpenFlags; + __u32 RootDirectoryFid; + __u32 DesiredAccess; + __u64 AllocationSize; + __u32 FileAttributes; + __u32 ShareAccess; + __u32 CreateDisposition; + __u32 CreateOptions; + __u32 ImpersonationLevel; + __u8 SecurityFlags; + __u16 ByteCount; + char fileName[1]; +} OPEN_REQ; + +/* open response: oplock levels */ +#define OPLOCK_NONE 0 +#define OPLOCK_EXCLUSIVE 1 +#define OPLOCK_BATCH 2 +#define OPLOCK_READ 3 /* level 2 oplock */ + +/* open response for CreateAction shifted left */ +#define CIFS_CREATE_ACTION 0x20000 /* file created */ + +typedef struct smb_com_open_rsp { + struct smb_hdr hdr; /* wct = 34 BB */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u8 OplockLevel; + __u16 Fid; + __u32 CreateAction; + __u64 CreationTime; + __u64 LastAccessTime; + __u64 LastWriteTime; + __u64 ChangeTime; + __u32 FileAttributes; + __u64 AllocationSize; + __u64 EndOfFile; + __u16 FileType; + __u16 DeviceState; + __u8 DirectoryFlag; + __u16 ByteCount; /* bct = 0 */ +} OPEN_RSP; + +typedef struct smb_com_write_req { + struct smb_hdr hdr; /* wct = 14 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 Fid; + __u32 OffsetLow; + __u32 Reserved; + __u16 WriteMode; + __u16 Remaining; + __u16 DataLengthHigh; + __u16 DataLengthLow; + __u16 DataOffset; + __u32 OffsetHigh; + __u16 ByteCount; + __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ + char Data[1]; +} WRITE_REQ; + +typedef struct smb_com_write_rsp { + struct smb_hdr hdr; /* wct = 6 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 Count; + __u16 Remaining; + __u32 Reserved; + __u16 ByteCount; +} WRITE_RSP; + +typedef struct smb_com_read_req { + struct smb_hdr hdr; /* wct = 12 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 Fid; + __u32 OffsetLow; + __u16 MaxCount; + __u16 MinCount; /* obsolete */ + __u32 MaxCountHigh; + __u16 Remaining; + __u32 OffsetHigh; + __u16 ByteCount; +} READ_REQ; + +typedef struct smb_com_read_rsp { + struct smb_hdr hdr; /* wct = 12 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 Remaining; + __u16 DataCompactionMode; + __u16 Reserved; + __u16 DataLength; + __u16 DataOffset; + __u16 DataLengthHigh; + __u64 Reserved2; + __u16 ByteCount; + __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ + char Data[1]; +} READ_RSP; + +typedef struct locking_andx_range { + __u16 Pid; + __u16 Pad; + __u32 OffsetHigh; + __u32 OffsetLow; + __u32 LengthHigh; + __u32 LengthLow; +} LOCKING_ANDX_RANGE; + +#define LOCKING_ANDX_SHARED_LOCK 0x01 +#define LOCKING_ANDX_OPLOCK_RELEASE 0x02 +#define LOCKING_ANDX_CHANGE_LOCKTYPE 0x04 +#define LOCKING_ANDX_CANCEL_LOCK 0x08 +#define LOCKING_ANDX_LARGE_FILES 0x10 /* always on for us */ + +typedef struct smb_com_lock_req { + struct smb_hdr hdr; /* wct = 8 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 Fid; + __u8 LockType; + __u8 OplockLevel; + __u32 Timeout; + __u16 NumberOfUnlocks; + __u16 NumberOfLocks; + __u16 ByteCount; + LOCKING_ANDX_RANGE Locks[1]; +} LOCK_REQ; + +typedef struct smb_com_lock_rsp { + struct smb_hdr hdr; /* wct = 2 */ + __u8 AndXCommand; + __u8 AndXReserved; + __u16 AndXOffset; + __u16 ByteCount; +} LOCK_RSP; + +typedef struct smb_com_rename_req { + struct smb_hdr hdr; /* wct = 1 */ + __u16 SearchAttributes; /* target file attributes */ + __u16 ByteCount; + __u8 BufferFormat; /* 4 = ASCII or Unicode */ + unsigned char OldFileName[1]; + /* followed by __u8 BufferFormat2 */ + /* followed by NewFileName */ +} RENAME_REQ; + + /* copy request flags */ +#define COPY_MUST_BE_FILE 0x0001 +#define COPY_MUST_BE_DIR 0x0002 +#define COPY_TARGET_MODE_ASCII 0x0004 /* if not set, binary */ +#define COPY_SOURCE_MODE_ASCII 0x0008 /* if not set, binary */ +#define COPY_VERIFY_WRITES 0x0010 +#define COPY_TREE 0x0020 + +typedef struct smb_com_copy_req { + struct smb_hdr hdr; /* wct = 3 */ + __u16 Tid2; + __u16 OpenFunction; + __u16 Flags; + __u16 ByteCount; + __u8 BufferFormat; /* 4 = ASCII or Unicode */ + unsigned char OldFileName[1]; + /* followed by __u8 BufferFormat2 */ + /* followed by NewFileName string */ +} COPY_REQ; + +typedef struct smb_com_copy_rsp { + struct smb_hdr hdr; /* wct = 1 */ + __u16 CopyCount; /* number of files copied */ + __u16 ByteCount; /* may be zero */ + __u8 BufferFormat; /* 0x04 - only present if errored file follows */ + unsigned char ErrorFileName[1]; /* only present if error in copy */ +} COPY_RSP; + +#define CREATE_HARD_LINK 0x103 +#define MOVEFILE_COPY_ALLOWED 0x0002 +#define MOVEFILE_REPLACE_EXISTING 0x0001 + +typedef struct smb_com_nt_rename_req { /* A5 - also used for create hardlink */ + struct smb_hdr hdr; /* wct = 4 */ + __u16 SearchAttributes; /* target file attributes */ + __u16 Flags; /* spec says Information Level */ + __u32 ClusterCount; + __u16 ByteCount; + __u8 BufferFormat; /* 4 = ASCII or Unicode */ + unsigned char OldFileName[1]; + /* followed by __u8 BufferFormat2 */ + /* followed by NewFileName */ +} NT_RENAME_REQ; + +typedef struct smb_com_rename_rsp { + struct smb_hdr hdr; /* wct = 0 */ + __u16 ByteCount; /* bct = 0 */ +} RENAME_RSP; + +typedef struct smb_com_delete_file_req { + struct smb_hdr hdr; /* wct = 1 */ + __u16 SearchAttributes; + __u16 ByteCount; + __u8 BufferFormat; /* 4 = ASCII */ + unsigned char fileName[1]; +} DELETE_FILE_REQ; + +typedef struct smb_com_delete_file_rsp { + struct smb_hdr hdr; /* wct = 0 */ + __u16 ByteCount; /* bct = 0 */ +} DELETE_FILE_RSP; + +typedef struct smb_com_delete_directory_req { + struct smb_hdr hdr; /* wct = 0 */ + __u16 ByteCount; + __u8 BufferFormat; /* 4 = ASCII */ + unsigned char DirName[1]; +} DELETE_DIRECTORY_REQ; + +typedef struct smb_com_delete_directory_rsp { + struct smb_hdr hdr; /* wct = 0 */ + __u16 ByteCount; /* bct = 0 */ +} DELETE_DIRECTORY_RSP; + +typedef struct smb_com_create_directory_req { + struct smb_hdr hdr; /* wct = 0 */ + __u16 ByteCount; + __u8 BufferFormat; /* 4 = ASCII */ + unsigned char DirName[1]; +} CREATE_DIRECTORY_REQ; + +typedef struct smb_com_create_directory_rsp { + struct smb_hdr hdr; /* wct = 0 */ + __u16 ByteCount; /* bct = 0 */ +} CREATE_DIRECTORY_RSP; + +/***************************************************/ +/* NT Transact structure defintions follow */ +/* Currently only ioctl and notify are implemented */ +/***************************************************/ +typedef struct smb_com_transaction_ioctl_req { + struct smb_hdr hdr; /* wct = 23 */ + __u8 MaxSetupCount; + __u16 Reserved; + __u32 TotalParameterCount; + __u32 TotalDataCount; + __u32 MaxParameterCount; + __u32 MaxDataCount; + __u32 ParameterCount; + __u32 ParameterOffset; + __u32 DataCount; + __u32 DataOffset; + __u8 SetupCount; /* four setup words follow subcommand */ + /* SNIA spec incorrectly included spurious pad here */ + __u16 SubCommand;/* 2 = IOCTL/FSCTL */ + __u32 FunctionCode; + __u16 Fid; + __u8 IsFsctl; /* 1 = File System Control, 0 = device control (IOCTL)*/ + __u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS share)*/ + __u16 ByteCount; + __u8 Pad[3]; + __u8 Data[1]; +} TRANSACT_IOCTL_REQ; + +typedef struct smb_com_transaction_ioctl_rsp { + struct smb_hdr hdr; /* wct = 19 */ + __u8 Reserved[3]; + __u32 TotalParameterCount; + __u32 TotalDataCount; + __u32 ParameterCount; + __u32 ParameterOffset; + __u32 ParameterDisplacement; + __u32 DataCount; + __u32 DataOffset; + __u32 DataDisplacement; + __u8 SetupCount; /* 1 */ + __u16 ReturnedDataLen; + __u16 ByteCount; + __u8 Pad[3]; +} TRANSACT_IOCTL_RSP; + +typedef struct smb_com_transaction_change_notify_req { + struct smb_hdr hdr; /* wct = 23 */ + __u8 MaxSetupCount; + __u16 Reserved; + __u32 TotalParameterCount; + __u32 TotalDataCount; + __u32 MaxParameterCount; + __u32 MaxDataCount; + __u32 ParameterCount; + __u32 ParameterOffset; + __u32 DataCount; + __u32 DataOffset; + __u8 SetupCount; /* four setup words follow subcommand */ + /* SNIA spec incorrectly included spurious pad here */ + __u16 SubCommand;/* 4 = Change Notify */ + __u32 CompletionFilter; /* operation to monitor */ + __u16 Fid; + __u8 WatchTree; /* 1 = Monitor subdirectories */ + __u8 Reserved2; + __u16 ByteCount; +/* __u8 Pad[3];*/ +/* __u8 Data[1];*/ +} TRANSACT_CHANGE_NOTIFY_REQ; + +typedef struct smb_com_transaction_change_notify_rsp { + struct smb_hdr hdr; /* wct = 18 */ + __u8 Reserved[3]; + __u32 TotalParameterCount; + __u32 TotalDataCount; + __u32 ParameterCount; + __u32 ParameterOffset; + __u32 ParameterDisplacement; + __u32 DataCount; + __u32 DataOffset; + __u32 DataDisplacement; + __u8 SetupCount; /* 0 */ + __u16 ByteCount; + /* __u8 Pad[3]; */ +} TRANSACT_CHANGE_NOTIFY_RSP; +/* Completion Filter flags for Notify */ +#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001 +#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002 +#define FILE_NOTIFY_CHANGE_NAME 0x00000003 +#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004 +#define FILE_NOTIFY_CHANGE_SIZE 0x00000008 +#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010 +#define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020 +#define FILE_NOTIFY_CHANGE_CREATION 0x00000040 +#define FILE_NOTIFY_CHANGE_EA 0x00000080 +#define FILE_NOTIFY_CHANGE_SECURITY 0x00000100 +#define FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200 +#define FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400 +#define FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800 + +#define FILE_ACTION_ADDED 0x00000001 +#define FILE_ACTION_REMOVED 0x00000002 +#define FILE_ACTION_MODIFIED 0x00000003 +#define FILE_ACTION_RENAMED_OLD_NAME 0x00000004 +#define FILE_ACTION_RENAMED_NEW_NAME 0x00000005 +#define FILE_ACTION_ADDED_STREAM 0x00000006 +#define FILE_ACTION_REMOVED_STREAM 0x00000007 +#define FILE_ACTION_MODIFIED_STREAM 0x00000008 + +/* response contains array of the following structures */ +struct file_notify_information { + __u32 NextEntryOffset; + __u32 Action; + __u32 FileNameLength; + __u8 FileName[1]; +}; + +struct reparse_data { + __u32 ReparseTag; + __u16 ReparseDataLength; + __u16 Reserved; + __u16 AltNameOffset; + __u16 AltNameLen; + __u16 TargetNameOffset; + __u16 TargetNameLen; + char LinkNamesBuf[1]; +}; + +struct cifs_quota_data { + __u32 rsrvd1; /* 0 */ + __u32 sid_size; + __u64 rsrvd2; /* 0 */ + __u64 space_used; + __u64 soft_limit; + __u64 hard_limit; + char sid[1]; /* variable size? */ +}; + +/* quota sub commands */ +#define QUOTA_LIST_CONTINUE 0 +#define QUOTA_LIST_START 0x100 +#define QUOTA_FOR_SID 0x101 + +typedef union smb_com_transaction2 { + struct { + struct smb_hdr hdr; /* wct = 14+ */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 MaxParameterCount; + __u16 MaxDataCount; + __u8 MaxSetupCount; + __u8 Reserved; + __u16 Flags; + __u32 Timeout; + __u16 Reserved2; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 DataCount; + __u16 DataOffset; + __u8 SetupCount; + __u8 Reserved3; + __u16 SubCommand; /* 1st setup word - can be followed by SetupCount words */ + __u16 ByteCount; /* careful - setupcount is not always one */ + } req; + struct { + struct smb_hdr hdr; /* wct = 0 */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 Reserved; + __u16 ParameterCount; + __u16 ParamterOffset; + __u16 ParameterDisplacement; + __u16 DataCount; + __u16 DataOffset; + __u16 DataDisplacement; + __u8 SetupCount; + __u8 Reserved1; /* should be zero setup words following */ + __u16 ByteCount; + __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ + /* data area follows */ + } resp; +} TRANSACTION2; + +/* PathInfo/FileInfo infolevels */ +#define SMB_INFO_STANDARD 1 +#define SMB_INFO_QUERY_EAS_FROM_LIST 3 +#define SMB_INFO_QUERY_ALL_EAS 4 +#define SMB_INFO_IS_NAME_VALID 6 +#define SMB_QUERY_FILE_BASIC_INFO 0x101 +#define SMB_QUERY_FILE_STANDARD_INFO 0x102 +#define SMB_QUERY_FILE_EA_INFO 0x103 +#define SMB_QUERY_FILE_NAME_INFO 0x104 +#define SMB_QUERY_FILE_ALLOCATION_INFO 0x105 +#define SMB_QUERY_FILE_END_OF_FILEINFO 0x106 +#define SMB_QUERY_FILE_ALL_INFO 0x107 +#define SMB_QUERY_ALT_NAME_INFO 0x108 +#define SMB_QUERY_FILE_STREAM_INFO 0x109 +#define SMB_QUERY_FILE_COMPRESSION_INFO 0x10B +#define SMB_QUERY_FILE_UNIX_BASIC 0x200 +#define SMB_QUERY_FILE_UNIX_LINK 0x201 + +#define SMB_SET_FILE_BASIC_INFO 0x101 +#define SMB_SET_FILE_DISPOSITION_INFO 0x102 +#define SMB_SET_FILE_ALLOCATION_INFO 0x103 +#define SMB_SET_FILE_END_OF_FILE_INFO 0x104 +#define SMB_SET_FILE_UNIX_BASIC 0x200 +#define SMB_SET_FILE_UNIX_LINK 0x201 +#define SMB_SET_FILE_UNIX_HLINK 0x203 +#define SMB_SET_FILE_BASIC_INFO2 0x3ec +#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 +#define SMB_FILE_ALL_INFO2 0x3fa +#define SMB_SET_FILE_ALLOCATION_INFO2 0x3fb +#define SMB_SET_FILE_END_OF_FILE_INFO2 0x3fc +#define SMB_FILE_MOVE_CLUSTER_INFO 0x407 +#define SMB_FILE_QUOTA_INFO 0x408 +#define SMB_FILE_REPARSEPOINT_INFO 0x409 +#define SMB_FILE_MAXIMUM_INFO 0x40d + +/* Find File infolevels */ +#define SMB_FIND_FILE_DIRECTORY_INFO 0x101 +#define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102 +#define SMB_FIND_FILE_NAMES_INFO 0x103 +#define SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x104 +#define SMB_FIND_FILE_UNIX 0x202 + +typedef struct smb_com_transaction2_qpi_req { + struct smb_hdr hdr; /* wct = 14+ */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 MaxParameterCount; + __u16 MaxDataCount; + __u8 MaxSetupCount; + __u8 Reserved; + __u16 Flags; + __u32 Timeout; + __u16 Reserved2; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 DataCount; + __u16 DataOffset; + __u8 SetupCount; + __u8 Reserved3; + __u16 SubCommand; /* one setup word */ + __u16 ByteCount; + __u8 Pad; + __u16 InformationLevel; + __u32 Reserved4; + char FileName[1]; +} TRANSACTION2_QPI_REQ; + +typedef struct smb_com_transaction2_qpi_rsp { + struct smb_hdr hdr; /* wct = 10 + SetupCount */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 Reserved; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 ParameterDisplacement; + __u16 DataCount; + __u16 DataOffset; + __u16 DataDisplacement; + __u8 SetupCount; + __u8 Reserved1; /* should be zero setup words following */ + __u16 ByteCount; + __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ +} TRANSACTION2_QPI_RSP; + +typedef struct smb_com_transaction2_spi_req { + struct smb_hdr hdr; /* wct = 15 */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 MaxParameterCount; + __u16 MaxDataCount; + __u8 MaxSetupCount; + __u8 Reserved; + __u16 Flags; + __u32 Timeout; + __u16 Reserved2; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 DataCount; + __u16 DataOffset; + __u8 SetupCount; + __u8 Reserved3; + __u16 SubCommand; /* one setup word */ + __u16 ByteCount; + __u8 Pad; + __u16 Pad1; + __u16 InformationLevel; + __u32 Reserved4; + char FileName[1]; +} TRANSACTION2_SPI_REQ; + +typedef struct smb_com_transaction2_spi_rsp { + struct smb_hdr hdr; /* wct = 10 + SetupCount */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 Reserved; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 ParameterDisplacement; + __u16 DataCount; + __u16 DataOffset; + __u16 DataDisplacement; + __u8 SetupCount; + __u8 Reserved1; /* should be zero setup words following */ + __u16 ByteCount; + __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ +} TRANSACTION2_SPI_RSP; + +struct set_file_rename { + __u32 overwrite; /* 1 = overwrite dest */ + __u32 root_fid; /* zero */ + __u32 target_name_len; + char target_name[0]; /* Must be unicode */ +}; + +struct smb_com_transaction2_sfi_req { + struct smb_hdr hdr; /* wct = 15 */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 MaxParameterCount; + __u16 MaxDataCount; + __u8 MaxSetupCount; + __u8 Reserved; + __u16 Flags; + __u32 Timeout; + __u16 Reserved2; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 DataCount; + __u16 DataOffset; + __u8 SetupCount; + __u8 Reserved3; + __u16 SubCommand; /* one setup word */ + __u16 ByteCount; + __u8 Pad; + __u16 Pad1; + __u16 Fid; + __u16 InformationLevel; + __u16 Reserved4; +}; + +struct smb_com_transaction2_sfi_rsp { + struct smb_hdr hdr; /* wct = 10 + SetupCount */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 Reserved; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 ParameterDisplacement; + __u16 DataCount; + __u16 DataOffset; + __u16 DataDisplacement; + __u8 SetupCount; + __u8 Reserved1; /* should be zero setup words following */ + __u16 ByteCount; + __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ +}; + + +/* + * Flags on T2 FINDFIRST and FINDNEXT + */ +#define CIFS_SEARCH_CLOSE_ALWAYS 0x0001 +#define CIFS_SEARCH_CLOSE_AT_END 0x0002 +#define CIFS_SEARCH_RETURN_RESUME 0x0004 +#define CIFS_SEARCH_CONTINUE_FROM_LAST 0x0008 +#define CIFS_SEARCH_BACKUP_SEARCH 0x0010 + +/* + * Size of the resume key on FINDFIRST and FINDNEXT calls + */ +#define CIFS_SMB_RESUME_KEY_SIZE 4 + +typedef struct smb_com_transaction2_ffirst_req { + struct smb_hdr hdr; /* wct = 15 */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 MaxParameterCount; + __u16 MaxDataCount; + __u8 MaxSetupCount; + __u8 Reserved; + __u16 Flags; + __u32 Timeout; + __u16 Reserved2; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 DataCount; + __u16 DataOffset; + __u8 SetupCount; /* one */ + __u8 Reserved3; + __u16 SubCommand; /* TRANS2_FIND_FIRST */ + __u16 ByteCount; + __u8 Pad; + __u16 SearchAttributes; + __u16 SearchCount; + __u16 SearchFlags; + __u16 InformationLevel; + __u32 SearchStorageType; + char FileName[1]; +} TRANSACTION2_FFIRST_REQ; + +typedef struct smb_com_transaction2_ffirst_rsp { + struct smb_hdr hdr; /* wct = 10 */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 Reserved; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 ParameterDisplacement; + __u16 DataCount; + __u16 DataOffset; + __u16 DataDisplacement; + __u8 SetupCount; + __u8 Reserved1; /* should be zero setup words following */ + __u16 ByteCount; +} TRANSACTION2_FFIRST_RSP; + +typedef struct smb_com_transaction2_ffirst_rsp_parms { + __u16 SearchHandle; + __u16 SearchCount; + __u16 EndofSearch; + __u16 EAErrorOffset; + __u16 LastNameOffset; +} T2_FFIRST_RSP_PARMS; + +typedef struct smb_com_transaction2_fnext_req { + struct smb_hdr hdr; /* wct = 15 */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 MaxParameterCount; + __u16 MaxDataCount; + __u8 MaxSetupCount; + __u8 Reserved; + __u16 Flags; + __u32 Timeout; + __u16 Reserved2; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 DataCount; + __u16 DataOffset; + __u8 SetupCount; /* one */ + __u8 Reserved3; + __u16 SubCommand; /* TRANS2_FIND_NEXT */ + __u16 ByteCount; + __u8 Pad; + __u16 SearchHandle; + __u16 SearchCount; + __u16 InformationLevel; + __u32 ResumeKey; + __u16 SearchFlags; + char ResumeFileName[1]; +} TRANSACTION2_FNEXT_REQ; + +typedef struct smb_com_transaction2_fnext_rsp { + struct smb_hdr hdr; /* wct = 10 */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 Reserved; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 ParameterDisplacement; + __u16 DataCount; + __u16 DataOffset; + __u16 DataDisplacement; + __u8 SetupCount; + __u8 Reserved1; /* should be zero setup words following */ + __u16 ByteCount; +} TRANSACTION2_FNEXT_RSP; + +typedef struct smb_com_transaction2_fnext_rsp_parms { + __u16 SearchCount; + __u16 EndofSearch; + __u16 EAErrorOffset; + __u16 LastNameOffset; +} T2_FNEXT_RSP_PARMS; + +/* QFSInfo Levels */ +#define SMB_INFO_ALLOCATION 1 +#define SMB_INFO_VOLUME 2 +#define SMB_QUERY_FS_VOLUME_INFO 0x102 +#define SMB_QUERY_FS_SIZE_INFO 0x103 +#define SMB_QUERY_FS_DEVICE_INFO 0x104 +#define SMB_QUERY_FS_ATTRIBUTE_INFO 0x105 +#define SMB_QUERY_CIFS_UNIX_INFO 0x200 +#define SMB_QUERY_LABEL_INFO 0x3ea +#define SMB_QUERY_FS_QUOTA_INFO 0x3ee + +typedef struct smb_com_transaction2_qfsi_req { + struct smb_hdr hdr; /* wct = 14+ */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 MaxParameterCount; + __u16 MaxDataCount; + __u8 MaxSetupCount; + __u8 Reserved; + __u16 Flags; + __u32 Timeout; + __u16 Reserved2; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 DataCount; + __u16 DataOffset; + __u8 SetupCount; + __u8 Reserved3; + __u16 SubCommand; /* one setup word */ + __u16 ByteCount; + __u8 Pad; + __u16 InformationLevel; +} TRANSACTION2_QFSI_REQ; + +typedef struct smb_com_transaction_qfsi_rsp { + struct smb_hdr hdr; /* wct = 10 + SetupCount */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 Reserved; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 ParameterDisplacement; + __u16 DataCount; + __u16 DataOffset; + __u16 DataDisplacement; + __u8 SetupCount; + __u8 Reserved1; /* should be zero setup words following */ + __u16 ByteCount; + __u8 Pad; /* may be three bytes *//* followed by data area */ +} TRANSACTION2_QFSI_RSP; + +typedef struct smb_com_transaction2_get_dfs_refer_req { + struct smb_hdr hdr; /* wct = 15 */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 MaxParameterCount; + __u16 MaxDataCount; + __u8 MaxSetupCount; + __u8 Reserved; + __u16 Flags; + __u32 Timeout; + __u16 Reserved2; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 DataCount; + __u16 DataOffset; + __u8 SetupCount; + __u8 Reserved3; + __u16 SubCommand; /* one setup word */ + __u16 ByteCount; + __u8 Pad[3]; /* Win2K has sent 0x0F01 (max resp length perhaps?) followed by one byte pad - doesn't seem to matter though */ + __u16 MaxReferralLevel; + char RequestFileName[1]; +} TRANSACTION2_GET_DFS_REFER_REQ; + +typedef struct dfs_referral_level_3 { + __u16 VersionNumber; + __u16 ReferralSize; + __u16 ServerType; /* 0x0001 = CIFS server */ + __u16 ReferralFlags; /* or proximity - not clear which since always set to zero - SNIA spec says 0x01 means strip off PathConsumed chars before submitting RequestFileName to remote node */ + __u16 TimeToLive; + __u16 Proximity; + __u16 DfsPathOffset; + __u16 DfsAlternatePathOffset; + __u16 NetworkAddressOffset; +} REFERRAL3; + +typedef struct smb_com_transaction_get_dfs_refer_rsp { + struct smb_hdr hdr; /* wct = 10 */ + __u16 TotalParameterCount; + __u16 TotalDataCount; + __u16 Reserved; + __u16 ParameterCount; + __u16 ParameterOffset; + __u16 ParameterDisplacement; + __u16 DataCount; + __u16 DataOffset; + __u16 DataDisplacement; + __u8 SetupCount; + __u8 Reserved1; /* zero setup words following */ + __u16 ByteCount; + __u8 Pad; + __u16 PathConsumed; + __u16 NumberOfReferrals; + __u16 DFSFlags; + __u16 Pad2; + REFERRAL3 referrals[1]; /* array of level 3 dfs_referral structures */ + /* followed by the strings pointed to by the referral structures */ +} TRANSACTION2_GET_DFS_REFER_RSP; + +/* DFS Flags */ +#define DFSREF_REFERRAL_SERVER 0x0001 +#define DFSREF_STORAGE_SERVER 0x0002 + +/* IOCTL information */ +/* List of ioctl function codes that look to be of interest to remote clients like this. */ +/* Need to do some experimentation to make sure they all work remotely. */ +/* Some of the following such as the encryption/compression ones would be */ +/* invoked from tools via a specialized hook into the VFS rather than via the */ +/* standard vfs entry points */ +#define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000 +#define FSCTL_REQUEST_OPLOCK_LEVEL_2 0x00090004 +#define FSCTL_REQUEST_BATCH_OPLOCK 0x00090008 +#define FSCTL_LOCK_VOLUME 0x00090018 +#define FSCTL_UNLOCK_VOLUME 0x0009001C +#define FSCTL_GET_COMPRESSION 0x0009003C +#define FSCTL_SET_COMPRESSION 0x0009C040 +#define FSCTL_REQUEST_FILTER_OPLOCK 0x0009008C +#define FSCTL_FILESYS_GET_STATISTICS 0x00090090 +#define FSCTL_SET_REPARSE_POINT 0x000900A4 +#define FSCTL_GET_REPARSE_POINT 0x000900A8 +#define FSCTL_DELETE_REPARSE_POINT 0x000900AC +#define FSCTL_SET_SPARSE 0x000900C4 +#define FSCTL_SET_ZERO_DATA 0x000900C8 +#define FSCTL_SET_ENCRYPTION 0x000900D7 +#define FSCTL_ENCRYPTION_FSCTL_IO 0x000900DB +#define FSCTL_WRITE_RAW_ENCRYPTED 0x000900DF +#define FSCTL_READ_RAW_ENCRYPTED 0x000900E3 +#define FSCTL_SIS_COPYFILE 0x00090100 +#define FSCTL_SIS_LINK_FILES 0x0009C104 + +#define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003 +#define IO_REPARSE_TAG_HSM 0xC0000004 +#define IO_REPARSE_TAG_SIS 0x80000007 + +/* + ************************************************************************ + * All structs for everything above the SMB PDUs themselves + * (such as the T2 level specific data) go here + ************************************************************************ + */ + +/* + * Information on a server + */ + +struct serverInfo { + char name[16]; + unsigned char versionMajor; + unsigned char versionMinor; + unsigned long type; + unsigned int commentOffset; +}; + +/* + * The following structure is the format of the data returned on a NetShareEnum + * with level "90" (x5A) + */ + +struct shareInfo { + char shareName[13]; + char pad; + unsigned short type; + unsigned int commentOffset; +}; + +struct aliasInfo { + char aliasName[9]; + char pad; + unsigned int commentOffset; + unsigned char type[2]; +}; + +struct aliasInfo92 { + int aliasNameOffset; + int serverNameOffset; + int shareNameOffset; +}; + +typedef struct { + __u64 TotalAllocationUnits; + __u64 FreeAllocationUnits; + __u32 SectorsPerAllocationUnit; + __u32 BytesPerSector; +} FILE_SYSTEM_INFO; /* size info, level 0x103 */ + +typedef struct { + __u16 MajorVersionNumber; + __u16 MinorVersionNumber; + __u64 Capability; +} FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */ +/* Linux/Unix extensions capability flags */ +#define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */ +#define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 + +/* DeviceType Flags */ +#define FILE_DEVICE_CD_ROM 0x00000002 +#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 +#define FILE_DEVICE_DFS 0x00000006 +#define FILE_DEVICE_DISK 0x00000007 +#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 +#define FILE_DEVICE_FILE_SYSTEM 0x00000009 +#define FILE_DEVICE_NAMED_PIPE 0x00000011 +#define FILE_DEVICE_NETWORK 0x00000012 +#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 +#define FILE_DEVICE_NULL 0x00000015 +#define FILE_DEVICE_PARALLEL_PORT 0x00000016 +#define FILE_DEVICE_PRINTER 0x00000018 +#define FILE_DEVICE_SERIAL_PORT 0x0000001b +#define FILE_DEVICE_STREAMS 0x0000001e +#define FILE_DEVICE_TAPE 0x0000001f +#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020 +#define FILE_DEVICE_VIRTUAL_DISK 0x00000024 +#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 + +typedef struct { + __u32 DeviceType; + __u32 DeviceCharacteristics; +} FILE_SYSTEM_DEVICE_INFO; /* device info, level 0x104 */ + +typedef struct { + __u32 Attributes; + __u32 MaxPathNameComponentLength; + __u32 FileSystemNameLen; + char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */ +} FILE_SYSTEM_ATTRIBUTE_INFO; + +typedef struct { /* data block encoding of response to level 263 QPathInfo */ + __u64 CreationTime; + __u64 LastAccessTime; + __u64 LastWriteTime; + __u64 ChangeTime; + __u32 Attributes; + __u32 Pad1; + __u64 AllocationSize; + __u64 EndOfFile; /* size ie offset to first free byte in file */ + __u32 NumberOfLinks; /* hard links */ + __u8 DeletePending; + __u8 Directory; + __u16 Pad2; + __u64 IndexNumber; + __u32 EASize; + __u32 AccessFlags; + __u64 IndexNumber1; + __u64 CurrentByteOffset; + __u32 Mode; + __u32 AlignmentRequirement; + __u32 FileNameLength; + char FileName[1]; +} FILE_ALL_INFO; /* level 263 QPathInfo */ + +typedef struct { + __u64 EndOfFile; + __u64 NumOfBytes; + __u64 LastStatusChange; /*SNIA spec says DCE time for the three time fields */ + __u64 LastAccessTime; + __u64 LastModificationTime; + __u64 Uid; + __u64 Gid; + __u32 Type; + __u64 DevMajor; + __u64 DevMinor; + __u64 UniqueId; + __u64 Permissions; + __u64 Nlinks; +} FILE_UNIX_BASIC_INFO; /* level 512 QPathInfo */ + +typedef struct { + char LinkDest[1]; +} FILE_UNIX_LINK_INFO; /* level 513 QPathInfo */ + +/* defines for enumerating possible values of the Unix type field below */ +#define UNIX_FILE 0 +#define UNIX_DIR 1 +#define UNIX_SYMLINK 2 +#define UNIX_CHARDEV 3 +#define UNIX_BLOCKDEV 4 +#define UNIX_FIFO 5 +#define UNIX_SOCKET 6 + +typedef struct { + __u32 NextEntryOffset; + __u32 ResumeKey; + __u64 EndOfFile; + __u64 NumOfBytes; + __u64 LastStatusChange; /*SNIA spec says DCE time for the three time fields */ + __u64 LastAccessTime; + __u64 LastModificationTime; + __u64 Uid; + __u64 Gid; + __u32 Type; + __u64 DevMajor; + __u64 DevMinor; + __u64 UniqueId; + __u64 Permissions; + __u64 Nlinks; + char FileName[1]; +} FILE_UNIX_INFO; + +typedef struct { + __u64 CreationTime; + __u64 LastAccessTime; + __u64 LastWriteTime; + __u64 ChangeTime; + __u32 Attributes; + __u32 Pad; +} FILE_BASIC_INFO; /* size info, level 0x101 */ + +struct file_allocation_info { + __u64 AllocationSize; +}; /* size info, level 0x103 */ + +struct file_end_of_file_info { + __u64 FileSize; /* offset to end of file */ +}; /* size info, level 0x104 */ + +typedef struct { + __u32 NextEntryOffset; + __u32 FileIndex; + __u64 CreationTime; + __u64 LastAccessTime; + __u64 LastWriteTime; + __u64 ChangeTime; + __u64 EndOfFile; + __u64 AllocationSize; + __u32 ExtFileAttributes; + __u32 FileNameLength; + char FileName[1]; +} FILE_DIRECTORY_INFO; /* level 257 FF response data area */ + +struct gea { + unsigned char cbName; + char szName[1]; +}; + +struct gealist { + unsigned long cbList; + struct gea list[1]; +}; + +struct fea { + unsigned char EA_flags; + __u8 name_len; + __u16 value_len; + char szName[1]; + /* optionally followed by value */ +}; +/* flags for _FEA.fEA */ +#define FEA_NEEDEA 0x80 /* need EA bit */ + +struct fealist { + __u32 list_len; + struct fea list[1]; +}; + +/* used to hold an arbitrary blob of data */ +struct data_blob { + __u8 *data; + size_t length; + void (*free) (struct data_blob * data_blob); +}; + +#ifdef CONFIG_CIFS_POSIX +/* + For better POSIX semantics from Linux client, (even better + than the existing CIFS Unix Extensions) we need updated PDUs for: + + 1) PosixCreateX - to set and return the mode, inode#, device info and + perhaps add a CreateDevice - to create Pipes and other special .inodes + Also note POSIX open flags + 2) Close - to return the last write time to do cache across close more safely + 3) PosixQFSInfo - to return statfs info + 4) FindFirst return unique inode number - what about resume key, two forms short (matches readdir) and full (enough info to cache inodes) + 5) Mkdir - set mode + + And under consideration: + 6) FindClose2 (return nanosecond timestamp ??) + 7) Use nanosecond timestamps throughout all time fields if + corresponding attribute flag is set + 8) sendfile - handle based copy + 9) Direct i/o + 10) "POSIX ACL" support + 11) Misc fcntls? + + what about fixing 64 bit alignment + + There are also various legacy SMB/CIFS requests used as is + + From existing Lanman and NTLM dialects: + -------------------------------------- + NEGOTIATE + SESSION_SETUP_ANDX (BB which?) + TREE_CONNECT_ANDX (BB which wct?) + TREE_DISCONNECT (BB add volume timestamp on response) + LOGOFF_ANDX + DELETE (note delete open file behavior) + DELETE_DIRECTORY + READ_AND_X + WRITE_AND_X + LOCKING_AND_X (note posix lock semantics) + RENAME (note rename across dirs and open file rename posix behaviors) + NT_RENAME (for hardlinks) Is this good enough for all features? + FIND_CLOSE2 + TRANSACTION2 (18 cases) + SMB_SET_FILE_END_OF_FILE_INFO2 SMB_SET_PATH_END_OF_FILE_INFO2 + (BB verify that never need to set allocation size) + SMB_SET_FILE_BASIC_INFO2 (setting times - BB can it be done via Unix ext?) + + COPY (note support for copy across directories) - FUTURE, OPTIONAL + setting/getting OS/2 EAs - FUTURE (BB can this handle + setting Linux xattrs perfectly) - OPTIONAL + dnotify - FUTURE, OPTIONAL + quota - FUTURE, OPTIONAL + + Note that various requests implemented for NT interop such as + NT_TRANSACT (IOCTL) QueryReparseInfo + are unneeded to servers compliant with the CIFS POSIX extensions + + From CIFS Unix Extensions: + ------------------------- + T2 SET_PATH_INFO (SMB_SET_FILE_UNIX_LINK) for symlinks + T2 SET_PATH_INFO (SMB_SET_FILE_BASIC_INFO2) + T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_LINK) + T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_BASIC) - BB check for missing inode fields + Actually need QUERY_FILE_UNIX_INFO since has inode num + BB what about a) blksize/blkbits/blocks + b) i_version + c) i_rdev + d) notify mask? + e) generation + f) size_seqcount + T2 FIND_FIRST/FIND_NEXT FIND_FILE_UNIX + TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended + T2_QFS_INFO QueryDevice/AttributeInfo - OPTIONAL + + + */ +#endif + +#pragma pack() /* resume default structure packing */ + +#endif /* _CIFSPDU_H */ diff --git a/release/src/linux/linux/fs/cifs/cifsproto.h b/release/src/linux/linux/fs/cifs/cifsproto.h new file mode 100644 index 00000000..530c554e --- /dev/null +++ b/release/src/linux/linux/fs/cifs/cifsproto.h @@ -0,0 +1,254 @@ +/* + * fs/cifs/cifsproto.h + * + * Copyright (c) International Business Machines Corp., 2002 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _CIFSPROTO_H +#define _CIFSPROTO_H +#include <linux/nls.h> + +struct statfs; + +/* + ***************************************************************** + * All Prototypes + ***************************************************************** + */ + +extern struct smb_hdr *cifs_buf_get(void); +extern void cifs_buf_release(void *); +extern int smb_send(struct socket *, struct smb_hdr *, + unsigned int /* length */ , struct sockaddr *); +extern unsigned int _GetXid(void); +extern void _FreeXid(unsigned int); +#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__FUNCTION__, xid,current->fsuid)); +#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__FUNCTION__,curr_xid,rc));} +extern char *build_path_from_dentry(struct dentry *); +extern char *build_wildcard_path_from_dentry(struct dentry *direntry); +extern void renew_parental_timestamps(struct dentry *direntry); +extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, + struct smb_hdr * /* input */ , + struct smb_hdr * /* out */ , + int * /* bytes returned */ , const int long_op); +extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); +extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); +extern int is_valid_oplock_break(struct smb_hdr *smb); +extern unsigned int smbCalcSize(struct smb_hdr *ptr); +extern int decode_negTokenInit(unsigned char *security_blob, int length, + enum securityEnum *secType); +extern int map_smb_to_linux_error(struct smb_hdr *smb); +extern void header_assemble(struct smb_hdr *, char /* command */ , + const struct cifsTconInfo *, int + /* length of fixed section (word count) in two byte units */ + ); +struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, struct cifsTconInfo *); +void DeleteOplockQEntry(struct oplock_q_entry *); +extern time_t cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ ); +extern u64 cifs_UnixTimeToNT(time_t); +extern int cifs_get_inode_info(struct inode **pinode, + const unsigned char *search_path, + FILE_ALL_INFO * pfile_info, + struct super_block *sb, int xid); +extern int cifs_get_inode_info_unix(struct inode **pinode, + const unsigned char *search_path, + struct super_block *sb,int xid); + +extern int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, + struct nls_table * nls_info); +extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses); + +extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, + const char *tree, struct cifsTconInfo *tcon, + const struct nls_table *); + +extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, + const char *searchName, + FILE_DIRECTORY_INFO * findData, + T2_FFIRST_RSP_PARMS * findParms, + const struct nls_table *nls_codepage, + int *pUnicodeFlag, + int *pUnixFlag /* if Unix extensions used */ ); +extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, + FILE_DIRECTORY_INFO * findData, + T2_FNEXT_RSP_PARMS * findParms, + const __u16 searchHandle, char * resume_name, + int name_length, __u32 resume_key, + int *UnicodeFlag, int *pUnixFlag); + +extern int CIFSFindClose(const int, struct cifsTconInfo *tcon, + const __u16 search_handle); + +extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, + const unsigned char *searchName, + FILE_ALL_INFO * findData, + const struct nls_table *nls_codepage); + +extern int CIFSSMBUnixQPathInfo(const int xid, + struct cifsTconInfo *tcon, + const unsigned char *searchName, + FILE_UNIX_BASIC_INFO * pFindData, + const struct nls_table *nls_codepage); + +extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, + const unsigned char *searchName, + unsigned char **targetUNCs, + unsigned int *number_of_UNC_in_array, + const struct nls_table *nls_codepage); + +extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, + const char *old_path, + const struct nls_table *nls_codepage); +extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, + const char *old_path, const struct nls_table *nls_codepage, + unsigned int *pnum_referrals, unsigned char ** preferrals); +extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, + struct statfs *FSData, + const struct nls_table *nls_codepage); +extern int CIFSSMBQFSAttributeInfo(const int xid, + struct cifsTconInfo *tcon, + const struct nls_table *nls_codepage); +extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon, + const struct nls_table *nls_codepage); +extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon, + const struct nls_table *nls_codepage); + +extern int CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, + char *fileName, FILE_BASIC_INFO * data, + const struct nls_table *nls_codepage); +extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, + char *fileName, __u64 size,int setAllocationSizeFlag, + const struct nls_table *nls_codepage); +extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, + __u64 size, __u16 fileHandle,__u32 opener_pid, int AllocSizeFlag); +extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon, + char *full_path, __u64 mode, __u64 uid, + __u64 gid, dev_t dev, const struct nls_table *nls_codepage); + +extern int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, + const char *newName, + const struct nls_table *nls_codepage); +extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, + const char *name, const struct nls_table *nls_codepage); + +extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, + const char *name, + const struct nls_table *nls_codepage); +extern int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, + const char *fromName, const char *toName, + const struct nls_table *nls_codepage); +extern int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, + int netfid, char * target_name, const struct nls_table *nls_codepage); +extern int CIFSCreateHardLink(const int xid, + struct cifsTconInfo *tcon, + const char *fromName, const char *toName, + const struct nls_table *nls_codepage); +extern int CIFSUnixCreateHardLink(const int xid, + struct cifsTconInfo *tcon, + const char *fromName, const char *toName, + const struct nls_table *nls_codepage); +extern int CIFSUnixCreateSymLink(const int xid, + struct cifsTconInfo *tcon, + const char *fromName, const char *toName, + const struct nls_table *nls_codepage); +extern int CIFSSMBUnixQuerySymLink(const int xid, + struct cifsTconInfo *tcon, + const unsigned char *searchName, + char *syminfo, const int buflen, + const struct nls_table *nls_codepage); +extern int CIFSSMBQueryReparseLinkInfo(const int xid, + struct cifsTconInfo *tcon, + const unsigned char *searchName, + char *symlinkinfo, const int buflen, __u16 fid, + const struct nls_table *nls_codepage); + +extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, + const char *fileName, const int disposition, + const int access_flags, const int omode, + __u16 * netfid, int *pOplock, FILE_ALL_INFO *, + const struct nls_table *nls_codepage); +extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, + const int smb_file_id); + +extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, + const int netfid, unsigned int count, + const __u64 lseek, unsigned int *nbytes, char **buf); +extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, + const int netfid, const unsigned int count, + const __u64 lseek, unsigned int *nbytes, + const char *buf, const int long_op); +extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, + const __u16 netfid, const __u64 len, + const __u64 offset, const __u32 numUnlock, + const __u32 numLock, const __u8 lockType, + const int waitFlag); + +extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon); +extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses); + +extern struct cifsSesInfo *sesInfoAlloc(void); +extern void sesInfoFree(struct cifsSesInfo *); +extern struct cifsTconInfo *tconInfoAlloc(void); +extern void tconInfoFree(struct cifsTconInfo *); + +extern int cifs_reconnect(struct TCP_Server_Info *server); + +extern int cifs_sign_smb(struct smb_hdr *, struct cifsSesInfo *,__u32 *); +extern int cifs_verify_signature(const struct smb_hdr *, const char * mac_key, + __u32 expected_sequence_number); +extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); +extern void CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *); +extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * ); + +extern int CIFSBuildServerList(int xid, char *serverBufferList, + int recordlength, int *entries, + int *totalEntries, int *topoChangedFlag); +extern int CIFSSMBQueryShares(int xid, struct cifsTconInfo *tcon, + struct shareInfo *shareList, int bufferLen, + int *entries, int *totalEntries); +extern int CIFSSMBQueryAlias(int xid, struct cifsTconInfo *tcon, + struct aliasInfo *aliasList, int bufferLen, + int *entries, int *totalEntries); +extern int CIFSSMBAliasInfo(int xid, struct cifsTconInfo *tcon, + char *aliasName, char *serverName, + char *shareName, char *comment); +extern int CIFSSMBGetShareInfo(int xid, struct cifsTconInfo *tcon, + char *share, char *comment); +extern int CIFSSMBGetUserPerms(int xid, struct cifsTconInfo *tcon, + char *userName, char *searchName, int *perms); +extern int CIFSSMBSync(int xid, struct cifsTconInfo *tcon, int netfid, int pid); + +extern int CIFSSMBSeek(int xid, + struct cifsTconInfo *tcon, + int netfid, + int pid, + int whence, unsigned long offset, long long *newoffset); + +extern int CIFSSMBCopy(int xid, + struct cifsTconInfo *source_tcon, + const char *fromName, + const __u16 target_tid, + const char *toName, const int flags, + const struct nls_table *nls_codepage); +extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, + const int notify_subdirs,const __u16 netfid,__u32 filter, + const struct nls_table *nls_codepage); +extern int CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, + const unsigned char *searchName, + char * EAData, size_t size, + const struct nls_table *nls_codepage); +#endif /* _CIFSPROTO_H */ diff --git a/release/src/linux/linux/fs/cifs/cifssmb.c b/release/src/linux/linux/fs/cifs/cifssmb.c new file mode 100644 index 00000000..ca4dedf7 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/cifssmb.c @@ -0,0 +1,3016 @@ +/* + * fs/cifs/cifssmb.c + * + * Copyright (C) International Business Machines Corp., 2002,2003 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * Contains the routines for constructing the SMB PDUs themselves + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */ + /* These are mostly routines that operate on a pathname, or on a tree id */ + /* (mounted volume), but there are eight handle based routines which must be */ + /* treated slightly different for reconnection purposes since we never want */ + /* to reuse a stale file handle and the caller knows the file handle */ + +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/vfs.h> +#include <asm/uaccess.h> +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_unicode.h" +#include "cifs_debug.h" + +#ifdef CONFIG_CIFS_POSIX +static struct { + int index; + char *name; +} protocols[] = { + {CIFS_PROT, "\2NT LM 0.12"}, + {CIFS_PROT, "\2POSIX 2"}, + {BAD_PROT, "\2"} +}; +#else +static struct { + int index; + char *name; +} protocols[] = { + {CIFS_PROT, "\2NT LM 0.12"}, + {BAD_PROT, "\2"} +}; +#endif + + +/* Mark as invalid, all open files on tree connections since they + were closed when session to server was lost */ +static void mark_open_files_invalid(struct cifsTconInfo * pTcon) +{ + struct cifsFileInfo *open_file = NULL; + struct list_head * tmp; + struct list_head * tmp1; + +/* list all files open on tree connection and mark them invalid */ + write_lock(&GlobalSMBSeslock); + list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { + open_file = list_entry(tmp,struct cifsFileInfo, tlist); + if(open_file) { + open_file->invalidHandle = TRUE; + } + } + write_unlock(&GlobalSMBSeslock); + /* BB Add call to invalidate_inodes(sb) for all superblocks mounted to this tcon */ +} + +static int +smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, + void **request_buf /* returned */ , + void **response_buf /* returned */ ) +{ + int rc = 0; + int timeout = 10 * HZ; + + /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so + check for tcp and smb session status done differently + for those three - in the calling routine */ + if(tcon) { + if((tcon->ses) && (tcon->ses->server)){ + struct nls_table *nls_codepage; + /* Give Demultiplex thread up to 10 seconds to + reconnect, should be greater than cifs socket + timeout which is 7 seconds */ + while(tcon->ses->server->tcpStatus == CifsNeedReconnect) { + while ((tcon->ses->server->tcpStatus != CifsGood) && (timeout > 0)){ + timeout = interruptible_sleep_on_timeout(&tcon->ses->server->response_q,timeout); + } + if(tcon->ses->server->tcpStatus == CifsNeedReconnect) { + /* on "soft" mounts we wait once */ + if((tcon->retry == FALSE) || + (tcon->ses->status == CifsExiting)) { + cFYI(1,("gave up waiting on reconnect in smb_init")); + return -EHOSTDOWN; + } /* else "hard" mount - keep retrying until + process is killed or server comes back up */ + } else /* TCP session is reestablished now */ + break; + + } + + nls_codepage = load_nls_default(); + /* need to prevent multiple threads trying to + simultaneously reconnect the same SMB session */ + down(&tcon->ses->sesSem); + if(tcon->ses->status == CifsNeedReconnect) + rc = cifs_setup_session(0, tcon->ses, nls_codepage); + if(!rc && (tcon->tidStatus == CifsNeedReconnect)) { + mark_open_files_invalid(tcon); + rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, + nls_codepage); + up(&tcon->ses->sesSem); + if(rc == 0) + atomic_inc(&tconInfoReconnectCount); + + cFYI(1, ("reconnect tcon rc = %d", rc)); + /* Removed call to reopen open files here - + it is safer (and faster) to reopen files + one at a time as needed in read and write */ + + /* Check if handle based operation so we + know whether we can continue or not without + returning to caller to reset file handle */ + switch(smb_command) { + case SMB_COM_READ_ANDX: + case SMB_COM_WRITE_ANDX: + case SMB_COM_CLOSE: + case SMB_COM_FIND_CLOSE2: + case SMB_COM_LOCKING_ANDX: { + unload_nls(nls_codepage); + return -EAGAIN; + } + } + } else { + up(&tcon->ses->sesSem); + } + unload_nls(nls_codepage); + + } else { + return -EIO; + } + } + if(rc) + return rc; + + *request_buf = cifs_buf_get(); + if (*request_buf == 0) { + /* BB should we add a retry in here if not a writepage? */ + return -ENOMEM; + } + /* Although the original thought was we needed the response buf for */ + /* potential retries of smb operations it turns out we can determine */ + /* from the mid flags when the request buffer can be resent without */ + /* having to use a second distinct buffer for the response */ + *response_buf = *request_buf; + + header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, + wct /*wct */ ); + +#ifdef CONFIG_CIFS_STATS + if(tcon != NULL) { + atomic_inc(&tcon->num_smbs_sent); + } +#endif + return rc; +} + +int +CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) +{ + NEGOTIATE_REQ *pSMB; + NEGOTIATE_RSP *pSMBr; + int rc = 0; + int bytes_returned; + struct TCP_Server_Info * server; + + if(ses->server) + server = ses->server; + else { + rc = -EIO; + return rc; + } + rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ , + (void **) &pSMB, (void **) &pSMBr); + if (rc) + return rc; + + pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; + if (extended_security) + pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; + + pSMB->ByteCount = strlen(protocols[0].name) + 1; + strncpy(pSMB->DialectsArray, protocols[0].name, 30); + /* null guaranteed to be at end of source and target buffers anyway */ + + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc == 0) { + server->secMode = pSMBr->SecurityMode; + server->secType = NTLM; /* BB override default for NTLMv2 or krb*/ + /* one byte - no need to convert this or EncryptionKeyLen from le,*/ + server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); + /* probably no need to store and check maxvcs */ + server->maxBuf = + min(le32_to_cpu(pSMBr->MaxBufferSize), + (__u32) CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE); + server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); + cFYI(0, ("Max buf = %d ", ses->server->maxBuf)); + GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); + server->capabilities = le32_to_cpu(pSMBr->Capabilities); + server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); + /* BB with UTC do we ever need to be using srvr timezone? */ + if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { + memcpy(server->cryptKey, pSMBr->u.EncryptionKey, + CIFS_CRYPTO_KEY_SIZE); + } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) + && (pSMBr->EncryptionKeyLength == 0)) { + /* decode security blob */ + } else + rc = -EIO; + + /* BB might be helpful to save off the domain of server here */ + + if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) { + if (pSMBr->ByteCount < 16) + rc = -EIO; + else if (pSMBr->ByteCount == 16) { + server->secType = RawNTLMSSP; + if (server->socketUseCount.counter > 1) { + if (memcmp + (server->server_GUID, + pSMBr->u.extended_response. + GUID, 16) != 0) { + cFYI(1, + ("UID of server does not match previous connection to same ip address")); + memcpy(server-> + server_GUID, + pSMBr->u. + extended_response. + GUID, 16); + } + } else + memcpy(server->server_GUID, + pSMBr->u.extended_response. + GUID, 16); + } else { + rc = decode_negTokenInit(pSMBr->u. + extended_response. + SecurityBlob, + pSMBr->ByteCount - + 16, &server->secType); + } + } else + server->capabilities &= ~CAP_EXTENDED_SECURITY; + if(sign_CIFS_PDUs == FALSE) { + if(server->secMode & SECMODE_SIGN_REQUIRED) + cERROR(1, + ("Server requires /proc/fs/cifs/PacketSigningEnabled")); + server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); + } else if(sign_CIFS_PDUs == 1) { + if((server->secMode & SECMODE_SIGN_REQUIRED) == 0) + server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); + } + + } + if (pSMB) + cifs_buf_release(pSMB); + return rc; +} + +int +CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) +{ + struct smb_hdr *smb_buffer; + struct smb_hdr *smb_buffer_response; + int rc = 0; + int length; + + cFYI(1, ("In tree disconnect")); + /* + * If last user of the connection and + * connection alive - disconnect it + * If this is the last connection on the server session disconnect it + * (and inside session disconnect we should check if tcp socket needs + * to be freed and kernel thread woken up). + */ + if (tcon) + down(&tcon->tconSem); + else + return -EIO; + + atomic_dec(&tcon->useCount); + if (atomic_read(&tcon->useCount) > 0) { + up(&tcon->tconSem); + return -EBUSY; + } + + /* No need to return error on this operation if tid invalidated and + closed on server already e.g. due to tcp session crashing */ + if(tcon->tidStatus == CifsNeedReconnect) { + up(&tcon->tconSem); + return 0; + } + + if((tcon->ses == 0) || (tcon->ses->server == 0)) { + up(&tcon->tconSem); + return -EIO; + } + + rc = smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, + (void **) &smb_buffer, (void **) &smb_buffer_response); + if (rc) { + up(&tcon->tconSem); + return rc; + } + rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response, + &length, 0); + if (rc) + cFYI(1, (" Tree disconnect failed %d", rc)); + + if (smb_buffer) + cifs_buf_release(smb_buffer); + up(&tcon->tconSem); + + /* No need to return error on this operation if tid invalidated and + closed on server already e.g. due to tcp session crashing */ + if (rc == -EAGAIN) + rc = 0; + + return rc; +} + +int +CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) +{ + struct smb_hdr *smb_buffer_response; + LOGOFF_ANDX_REQ *pSMB; + int rc = 0; + int length; + + cFYI(1, ("In SMBLogoff for session disconnect")); + if (ses) + down(&ses->sesSem); + else + return -EIO; + + atomic_dec(&ses->inUse); + if (atomic_read(&ses->inUse) > 0) { + up(&ses->sesSem); + return -EBUSY; + } + + rc = smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL /* no tcon anymore */, + (void **) &pSMB, (void **) &smb_buffer_response); + + if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + + if (rc) { + up(&ses->sesSem); + return rc; + } + + pSMB->hdr.Uid = ses->Suid; + + pSMB->AndXCommand = 0xFF; + rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, + smb_buffer_response, &length, 0); + if (ses->server) { + atomic_dec(&ses->server->socketUseCount); + if (atomic_read(&ses->server->socketUseCount) == 0) { + spin_lock(&GlobalMid_Lock); + ses->server->tcpStatus = CifsExiting; + spin_unlock(&GlobalMid_Lock); + rc = -ESHUTDOWN; + } + } + if (pSMB) + cifs_buf_release(pSMB); + up(&ses->sesSem); + + /* if session dead then we do not need to do ulogoff, + since server closed smb session, no sense reporting + error */ + if (rc == -EAGAIN) + rc = 0; + return rc; +} + +int +CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, + const char *fileName, const struct nls_table *nls_codepage) +{ + DELETE_FILE_REQ *pSMB = NULL; + DELETE_FILE_RSP *pSMBr = NULL; + int rc = 0; + int bytes_returned; + int name_len; + +DelFileRetry: + rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(fileName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->fileName, fileName, name_len); + } + pSMB->SearchAttributes = + cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM); + pSMB->ByteCount = name_len + 1; + pSMB->BufferFormat = 0x04; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Error in RMFile = %d", rc)); + } +#ifdef CONFIG_CIFS_STATS + else { + atomic_inc(&tcon->num_deletes); + } +#endif + + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto DelFileRetry; + + return rc; +} + +int +CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, + const char *dirName, const struct nls_table *nls_codepage) +{ + DELETE_DIRECTORY_REQ *pSMB = NULL; + DELETE_DIRECTORY_RSP *pSMBr = NULL; + int rc = 0; + int bytes_returned; + int name_len; + + cFYI(1, ("In CIFSSMBRmDir")); +RmDirRetry: + rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, dirName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(dirName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->DirName, dirName, name_len); + } + + pSMB->ByteCount = name_len + 1; + pSMB->BufferFormat = 0x04; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Error in RMDir = %d", rc)); + } +#ifdef CONFIG_CIFS_STATS + else { + atomic_inc(&tcon->num_rmdirs); + } +#endif + + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto RmDirRetry; + return rc; +} + +int +CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, + const char *name, const struct nls_table *nls_codepage) +{ + int rc = 0; + CREATE_DIRECTORY_REQ *pSMB = NULL; + CREATE_DIRECTORY_RSP *pSMBr = NULL; + int bytes_returned; + int name_len; + + cFYI(1, ("In CIFSSMBMkDir")); +MkDirRetry: + rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, name, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(name, 530); + name_len++; /* trailing null */ + strncpy(pSMB->DirName, name, name_len); + } + + pSMB->ByteCount = name_len + 1 /* for buf format */ ; + pSMB->BufferFormat = 0x04; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Error in Mkdir = %d", rc)); + } +#ifdef CONFIG_CIFS_STATS + else { + atomic_inc(&tcon->num_mkdirs); + } +#endif + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto MkDirRetry; + return rc; +} + +int +CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, + const char *fileName, const int openDisposition, + const int access_flags, const int create_options, __u16 * netfid, + int *pOplock, FILE_ALL_INFO * pfile_info, + const struct nls_table *nls_codepage) +{ + int rc = -EACCES; + OPEN_REQ *pSMB = NULL; + OPEN_RSP *pSMBr = NULL; + int bytes_returned; + int name_len; + +openRetry: + rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->AndXCommand = 0xFF; /* none */ + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + pSMB->ByteCount = 1; /* account for one byte pad to word boundary */ + name_len = + cifs_strtoUCS((wchar_t *) (pSMB->fileName + 1), + fileName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + pSMB->NameLength = cpu_to_le16(name_len); + } else { /* BB improve the check for buffer overruns BB */ + pSMB->ByteCount = 0; /* no pad */ + name_len = strnlen(fileName, 530); + name_len++; /* trailing null */ + pSMB->NameLength = cpu_to_le16(name_len); + strncpy(pSMB->fileName, fileName, name_len); + } + if (*pOplock & REQ_OPLOCK) + pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK); + else if (*pOplock & REQ_BATCHOPLOCK) { + pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK); + } + pSMB->DesiredAccess = cpu_to_le32(access_flags); + pSMB->AllocationSize = 0; + pSMB->FileAttributes = ATTR_NORMAL; + /* XP does not handle ATTR_POSIX_SEMANTICS */ + /* but it helps speed up case sensitive checks for other + servers such as Samba */ + if (tcon->ses->capabilities & CAP_UNIX) + pSMB->FileAttributes |= ATTR_POSIX_SEMANTICS; + + /* if ((omode & S_IWUGO) == 0) + pSMB->FileAttributes |= ATTR_READONLY;*/ + /* Above line causes problems due to vfs splitting create into two + pieces - need to set mode after file created not while it is + being created */ + pSMB->FileAttributes = cpu_to_le32(pSMB->FileAttributes); + pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); + pSMB->CreateDisposition = cpu_to_le32(openDisposition); + pSMB->CreateOptions = cpu_to_le32(create_options); + pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); /* BB ??*/ + pSMB->SecurityFlags = + cpu_to_le32(SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY); + + pSMB->ByteCount += name_len; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + /* long_op set to 1 to allow for oplock break timeouts */ + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 1); + if (rc) { + cFYI(1, ("Error in Open = %d", rc)); + } else { + *pOplock = pSMBr->OplockLevel; /* one byte no need to le_to_cpu */ + *netfid = pSMBr->Fid; /* cifs fid stays in le */ + /* Let caller know file was created so we can set the mode. */ + /* Do we care about the CreateAction in any other cases? */ + if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction) + *pOplock |= CIFS_CREATE_ACTION; + if(pfile_info) { + memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime, + 36 /* CreationTime to Attributes */); + /* the file_info buf is endian converted by caller */ + pfile_info->AllocationSize = pSMBr->AllocationSize; + pfile_info->EndOfFile = pSMBr->EndOfFile; + pfile_info->NumberOfLinks = cpu_to_le32(1); + } + +#ifdef CONFIG_CIFS_STATS + atomic_inc(&tcon->num_opens); +#endif + } + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto openRetry; + return rc; +} + +/* If no buffer passed in, then caller wants to do the copy + as in the case of readpages so the SMB buffer must be + freed by the caller */ + +int +CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, + const int netfid, const unsigned int count, + const __u64 lseek, unsigned int *nbytes, char **buf) +{ + int rc = -EACCES; + READ_REQ *pSMB = NULL; + READ_RSP *pSMBr = NULL; + char *pReadData = NULL; + int bytes_returned; + + *nbytes = 0; + rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + /* tcon and ses pointer are checked in smb_init */ + if (tcon->ses->server == NULL) + return -ECONNABORTED; + + pSMB->AndXCommand = 0xFF; /* none */ + pSMB->Fid = netfid; + pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); + pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); + pSMB->Remaining = 0; + pSMB->MaxCount = cpu_to_le16(count); + pSMB->MaxCountHigh = 0; + pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */ + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cERROR(1, ("Send error in read = %d", rc)); + } else { + pSMBr->DataLength = le16_to_cpu(pSMBr->DataLength); + *nbytes = pSMBr->DataLength; + /*check that DataLength would not go beyond end of SMB */ + if ((pSMBr->DataLength > CIFS_MAX_MSGSIZE) + || (pSMBr->DataLength > count)) { + cFYI(1,("bad length %d for count %d",pSMBr->DataLength,count)); + rc = -EIO; + *nbytes = 0; + } else { + pReadData = + (char *) (&pSMBr->hdr.Protocol) + + le16_to_cpu(pSMBr->DataOffset); +/* if(rc = copy_to_user(buf, pReadData, pSMBr->DataLength)) { + cERROR(1,("Faulting on read rc = %d",rc)); + rc = -EFAULT; + }*/ /* can not use copy_to_user when using page cache*/ + if(*buf) + memcpy(*buf,pReadData,pSMBr->DataLength); + } + } + if (pSMB) { + if(*buf) + cifs_buf_release(pSMB); + else + *buf = (char *)pSMB; + } + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + return rc; +} + +int +CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, + const int netfid, const unsigned int count, + const __u64 offset, unsigned int *nbytes, const char *buf, + const int long_op) +{ + int rc = -EACCES; + WRITE_REQ *pSMB = NULL; + WRITE_RSP *pSMBr = NULL; + int bytes_returned; + + rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + /* tcon and ses pointer are checked in smb_init */ + if (tcon->ses->server == NULL) + return -ECONNABORTED; + + pSMB->AndXCommand = 0xFF; /* none */ + pSMB->Fid = netfid; + pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); + pSMB->OffsetHigh = cpu_to_le32(offset >> 32); + pSMB->Remaining = 0; + if (count > ((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00)) + pSMB->DataLengthLow = + (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00; + else + pSMB->DataLengthLow = count; + pSMB->DataLengthHigh = 0; + pSMB->DataOffset = + cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); + + memcpy(pSMB->Data,buf,pSMB->DataLengthLow); + + pSMB->ByteCount += pSMB->DataLengthLow + 1 /* pad */ ; + pSMB->DataLengthLow = cpu_to_le16(pSMB->DataLengthLow); + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, long_op); + if (rc) { + cFYI(1, ("Send error in write = %d", rc)); + *nbytes = 0; + } else + *nbytes = le16_to_cpu(pSMBr->Count); + + if (pSMB) + cifs_buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + + return rc; +} + +int +CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, + const __u16 smb_file_id, const __u64 len, + const __u64 offset, const __u32 numUnlock, + const __u32 numLock, const __u8 lockType, const int waitFlag) +{ + int rc = 0; + LOCK_REQ *pSMB = NULL; + LOCK_RSP *pSMBr = NULL; + int bytes_returned; + int timeout = 0; + __u64 temp; + + cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock)); + rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) { + timeout = -1; /* no response expected */ + pSMB->Timeout = 0; + } else if (waitFlag == TRUE) { + timeout = 3; /* blocking operation, no timeout */ + pSMB->Timeout = -1; /* blocking - do not time out */ + } else { + pSMB->Timeout = 0; + } + + pSMB->NumberOfLocks = cpu_to_le32(numLock); + pSMB->NumberOfUnlocks = cpu_to_le32(numUnlock); + pSMB->LockType = lockType; + pSMB->AndXCommand = 0xFF; /* none */ + pSMB->Fid = smb_file_id; /* netfid stays le */ + + if(numLock != 0) { + pSMB->Locks[0].Pid = cpu_to_le16(current->tgid); + /* BB where to store pid high? */ + temp = cpu_to_le64(len); + pSMB->Locks[0].LengthLow = (__u32)(temp & 0xFFFFFFFF); + pSMB->Locks[0].LengthHigh = (__u32)(temp>>32); + temp = cpu_to_le64(offset); + pSMB->Locks[0].OffsetLow = (__u32)(temp & 0xFFFFFFFF); + pSMB->Locks[0].OffsetHigh = (__u32)(temp>>32); + pSMB->ByteCount = sizeof (LOCKING_ANDX_RANGE); + } else { + /* oplock break */ + pSMB->ByteCount = 0; + } + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, timeout); + + if (rc) { + cFYI(1, ("Send error in Lock = %d", rc)); + } + if (pSMB) + cifs_buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + return rc; +} + +int +CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) +{ + int rc = 0; + CLOSE_REQ *pSMB = NULL; + CLOSE_RSP *pSMBr = NULL; + int bytes_returned; + cFYI(1, ("In CIFSSMBClose")); + +/* do not retry on dead session on close */ + rc = smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB, + (void **) &pSMBr); + if(rc == -EAGAIN) + return 0; + if (rc) + return rc; + + pSMB->FileID = (__u16) smb_file_id; + pSMB->LastWriteTime = 0; + pSMB->ByteCount = 0; + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + if(rc!=-EINTR) { + /* EINTR is expected when user ctl-c to kill app */ + cERROR(1, ("Send error in Close = %d", rc)); + } + } + if (pSMB) + cifs_buf_release(pSMB); + + /* Since session is dead, file will be closed on server already */ + if(rc == -EAGAIN) + rc = 0; + + return rc; +} + +int +CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, + const char *fromName, const char *toName, + const struct nls_table *nls_codepage) +{ + int rc = 0; + RENAME_REQ *pSMB = NULL; + RENAME_RSP *pSMBr = NULL; + int bytes_returned; + int name_len, name_len2; + + cFYI(1, ("In CIFSSMBRename")); +renameRetry: + rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->BufferFormat = 0x04; + pSMB->SearchAttributes = + cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | + ATTR_DIRECTORY); + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + pSMB->OldFileName[name_len] = 0x04; /* pad */ + /* protocol requires ASCII signature byte on Unicode string */ + pSMB->OldFileName[name_len + 1] = 0x00; + name_len2 = + cifs_strtoUCS((wchar_t *) & pSMB-> + OldFileName[name_len + 2], toName, 530, + nls_codepage); + name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; + name_len2 *= 2; /* convert to bytes */ + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(fromName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->OldFileName, fromName, name_len); + name_len2 = strnlen(toName, 530); + name_len2++; /* trailing null */ + pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ + strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2); + name_len2++; /* trailing null */ + name_len2++; /* signature byte */ + } + + pSMB->ByteCount = 1 /* 1st signature byte */ + name_len + name_len2; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in rename = %d", rc)); + } + +#ifdef CONFIG_CIFS_STATS + else { + atomic_inc(&tcon->num_renames); + } +#endif + + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto renameRetry; + + return rc; +} + +int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, + int netfid, char * target_name, const struct nls_table * nls_codepage) +{ + struct smb_com_transaction2_sfi_req *pSMB = NULL; + struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; + struct set_file_rename * rename_info; + char *data_offset; + char dummy_string[30]; + int rc = 0; + int bytes_returned = 0; + int len_of_str; + + cFYI(1, ("Rename to File by handle")); + rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->ParameterCount = 6; + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_sfi_req, + Fid) - 4; + pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + + data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; + rename_info = (struct set_file_rename *) data_offset; + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); + pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount; + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->TotalParameterCount = pSMB->ParameterCount; + pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); + pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); + /* construct random name ".cifs_tmp<inodenum><mid>" */ + rename_info->overwrite = cpu_to_le32(1); + rename_info->root_fid = 0; + /* unicode only call */ + if(target_name == NULL) { + sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid); + len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, dummy_string, 24, nls_codepage); + } else { + len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, target_name, 530, nls_codepage); + } + rename_info->target_name_len = cpu_to_le32(2 * len_of_str); + pSMB->DataCount = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2; + pSMB->ByteCount += pSMB->DataCount; + pSMB->DataCount = cpu_to_le16(pSMB->DataCount); + pSMB->TotalDataCount = pSMB->DataCount; + pSMB->Fid = netfid; + pSMB->InformationLevel = + cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1,("Send error in Rename (by file handle) = %d", rc)); + } +#ifdef CONFIG_CIFS_STATS + else { + atomic_inc(&pTcon->num_t2renames); + } +#endif + if (pSMB) + cifs_buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + + return rc; +} + +int +CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, + const __u16 target_tid, const char *toName, const int flags, + const struct nls_table *nls_codepage) +{ + int rc = 0; + COPY_REQ *pSMB = NULL; + COPY_RSP *pSMBr = NULL; + int bytes_returned; + int name_len, name_len2; + + cFYI(1, ("In CIFSSMBCopy")); +copyRetry: + rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->BufferFormat = 0x04; + pSMB->Tid2 = target_tid; + + if(flags & COPY_TREE) + pSMB->Flags |= COPY_TREE; + pSMB->Flags = cpu_to_le16(pSMB->Flags); + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = cifs_strtoUCS((wchar_t *) pSMB->OldFileName, + fromName, + 530 /* find define for this maxpathcomponent */, + nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + pSMB->OldFileName[name_len] = 0x04; /* pad */ + /* protocol requires ASCII signature byte on Unicode string */ + pSMB->OldFileName[name_len + 1] = 0x00; + name_len2 = cifs_strtoUCS((wchar_t *) & pSMB-> + OldFileName[name_len + 2], toName, 530, + nls_codepage); + name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; + name_len2 *= 2; /* convert to bytes */ + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(fromName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->OldFileName, fromName, name_len); + name_len2 = strnlen(toName, 530); + name_len2++; /* trailing null */ + pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ + strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2); + name_len2++; /* trailing null */ + name_len2++; /* signature byte */ + } + + pSMB->ByteCount = 1 /* 1st signature byte */ + name_len + name_len2; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in copy = %d with %d files copied", + rc, pSMBr->CopyCount)); + } + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto copyRetry; + + return rc; +} + +int +CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon, + const char *fromName, const char *toName, + const struct nls_table *nls_codepage) +{ + TRANSACTION2_SPI_REQ *pSMB = NULL; + TRANSACTION2_SPI_RSP *pSMBr = NULL; + char *data_offset; + int name_len; + int name_len_target; + int rc = 0; + int bytes_returned = 0; + + cFYI(1, ("In Symlink Unix style")); +createSymLinkRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(fromName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, fromName, name_len); + } + pSMB->ParameterCount = 6 + name_len; + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, + InformationLevel) - 4; + pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + + data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len_target = + cifs_strtoUCS((wchar_t *) data_offset, toName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len_target++; /* trailing null */ + name_len_target *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len_target = strnlen(toName, 530); + name_len_target++; /* trailing null */ + strncpy(data_offset, toName, name_len_target); + } + + pSMB->DataCount = name_len_target; + pSMB->MaxParameterCount = cpu_to_le16(2); + /* BB find exact max on data count below from sess */ + pSMB->MaxDataCount = cpu_to_le16(1000); + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); + pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; + pSMB->DataCount = cpu_to_le16(pSMB->DataCount); + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->TotalDataCount = pSMB->DataCount; + pSMB->TotalParameterCount = pSMB->ParameterCount; + pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); + pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); + pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, + ("Send error in SetPathInfo (create symlink) = %d", + rc)); + } + + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto createSymLinkRetry; + + return rc; +} + +int +CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon, + const char *fromName, const char *toName, + const struct nls_table *nls_codepage) +{ + TRANSACTION2_SPI_REQ *pSMB = NULL; + TRANSACTION2_SPI_RSP *pSMBr = NULL; + char *data_offset; + int name_len; + int name_len_target; + int rc = 0; + int bytes_returned = 0; + + cFYI(1, ("In Create Hard link Unix style")); +createHardLinkRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = cifs_strtoUCS((wchar_t *) pSMB->FileName, toName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(toName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, toName, name_len); + } + pSMB->ParameterCount = 6 + name_len; + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, + InformationLevel) - 4; + pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + + data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len_target = + cifs_strtoUCS((wchar_t *) data_offset, fromName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len_target++; /* trailing null */ + name_len_target *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len_target = strnlen(fromName, 530); + name_len_target++; /* trailing null */ + strncpy(data_offset, fromName, name_len_target); + } + + pSMB->DataCount = name_len_target; + pSMB->MaxParameterCount = cpu_to_le16(2); + /* BB find exact max on data count below from sess*/ + pSMB->MaxDataCount = cpu_to_le16(1000); + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); + pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->TotalParameterCount = pSMB->ParameterCount; + pSMB->DataCount = cpu_to_le16(pSMB->DataCount); + pSMB->TotalDataCount = pSMB->DataCount; + pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); + pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); + pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc)); + } + + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto createHardLinkRetry; + + return rc; +} + +int +CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon, + const char *fromName, const char *toName, + const struct nls_table *nls_codepage) +{ + int rc = 0; + NT_RENAME_REQ *pSMB = NULL; + RENAME_RSP *pSMBr = NULL; + int bytes_returned; + int name_len, name_len2; + + cFYI(1, ("In CIFSCreateHardLink")); +winCreateHardLinkRetry: + + rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->SearchAttributes = + cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | + ATTR_DIRECTORY); + pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK); + pSMB->ClusterCount = 0; + + pSMB->BufferFormat = 0x04; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + pSMB->OldFileName[name_len] = 0; /* pad */ + pSMB->OldFileName[name_len + 1] = 0x04; + name_len2 = + cifs_strtoUCS((wchar_t *) & pSMB-> + OldFileName[name_len + 2], toName, 530, + nls_codepage); + name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; + name_len2 *= 2; /* convert to bytes */ + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(fromName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->OldFileName, fromName, name_len); + name_len2 = strnlen(toName, 530); + name_len2++; /* trailing null */ + pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ + strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2); + name_len2++; /* trailing null */ + name_len2++; /* signature byte */ + } + + pSMB->ByteCount = 1 /* string type byte */ + name_len + name_len2; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in hard link (NT rename) = %d", rc)); + } + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto winCreateHardLinkRetry; + + return rc; +} + +int +CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon, + const unsigned char *searchName, + char *symlinkinfo, const int buflen, + const struct nls_table *nls_codepage) +{ +/* SMB_QUERY_FILE_UNIX_LINK */ + TRANSACTION2_QPI_REQ *pSMB = NULL; + TRANSACTION2_QPI_RSP *pSMBr = NULL; + int rc = 0; + int bytes_returned; + int name_len; + + cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName)); + +querySymLinkRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(searchName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, searchName, name_len); + } + + pSMB->TotalParameterCount = + 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ; + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le16(2); + /* BB find exact max data count below from sess structure BB */ + pSMB->MaxDataCount = cpu_to_le16(4000); + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc)); + } else { /* decode response */ + pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount); + if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512)) + /* BB also check enough total bytes returned */ + rc = -EIO; /* bad smb */ + else { + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = UniStrnlen((wchar_t *) ((char *) + &pSMBr->hdr.Protocol +pSMBr->DataOffset), + min_t(const int, buflen,pSMBr->DataCount) / 2); + cifs_strfromUCS_le(symlinkinfo, + (wchar_t *) ((char *)&pSMBr->hdr.Protocol + + pSMBr->DataOffset), + name_len, nls_codepage); + } else { + strncpy(symlinkinfo, + (char *) &pSMBr->hdr.Protocol + + pSMBr->DataOffset, + min_t(const int, buflen, pSMBr->DataCount)); + } + symlinkinfo[buflen] = 0; + /* just in case so calling code does not go off the end of buffer */ + } + } + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto querySymLinkRetry; + return rc; +} + + + +int +CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, + const unsigned char *searchName, + char *symlinkinfo, const int buflen,__u16 fid, + const struct nls_table *nls_codepage) +{ + int rc = 0; + int bytes_returned; + int name_len; + struct smb_com_transaction_ioctl_req * pSMB; + struct smb_com_transaction_ioctl_rsp * pSMBr; + + cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName)); + rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->TotalParameterCount = 0 ; + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le32(2); + /* BB find exact data count max from sess structure BB */ + pSMB->MaxDataCount = cpu_to_le32(4000); + pSMB->MaxSetupCount = 4; + pSMB->Reserved = 0; + pSMB->ParameterOffset = 0; + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 4; + pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT); + pSMB->IsFsctl = 1; /* FSCTL */ + pSMB->IsRootFlag = 0; + pSMB->Fid = fid; /* file handle always le */ + pSMB->ByteCount = 0; + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc)); + } else { /* decode response */ + pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount); + if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512)) + /* BB also check enough total bytes returned */ + rc = -EIO; /* bad smb */ + else { + if(pSMBr->DataCount && (pSMBr->DataCount < 2048)) { + /* could also validate reparse tag && better check name length */ + struct reparse_data * reparse_buf = (struct reparse_data *) + ((char *)&pSMBr->hdr.Protocol + pSMBr->DataOffset); + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = UniStrnlen((wchar_t *) + (reparse_buf->LinkNamesBuf + + reparse_buf->TargetNameOffset), + min(buflen/2, reparse_buf->TargetNameLen / 2)); + cifs_strfromUCS_le(symlinkinfo, + (wchar_t *) (reparse_buf->LinkNamesBuf + + reparse_buf->TargetNameOffset), + name_len, nls_codepage); + } else { /* ASCII names */ + strncpy(symlinkinfo,reparse_buf->LinkNamesBuf + + reparse_buf->TargetNameOffset, + min_t(const int, buflen, reparse_buf->TargetNameLen)); + } + } else { + rc = -EIO; + cFYI(1,("Invalid return data count on get reparse info ioctl")); + } + symlinkinfo[buflen] = 0; /* just in case so the caller + does not go off the end of the buffer */ + cFYI(1,("readlink result - %s ",symlinkinfo)); + } + } + if (pSMB) + cifs_buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + + return rc; +} + +int +CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, + const unsigned char *searchName, + FILE_ALL_INFO * pFindData, + const struct nls_table *nls_codepage) +{ +/* level 263 SMB_QUERY_FILE_ALL_INFO */ + TRANSACTION2_QPI_REQ *pSMB = NULL; + TRANSACTION2_QPI_RSP *pSMBr = NULL; + int rc = 0; + int bytes_returned; + int name_len; + + cFYI(1, ("In QPathInfo path %s", searchName)); +QPathInfoRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(searchName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, searchName, name_len); + } + + pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ + + name_len /* includes null */ ; + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in QPathInfo = %d", rc)); + } else { /* decode response */ + pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + /* BB also check enough total bytes returned */ + /* BB we need to improve the validity checking + of these trans2 responses */ + if ((pSMBr->ByteCount < 40) || (pSMBr->DataOffset > 512)) + rc = -EIO; /* bad smb */ + else if (pFindData){ + memcpy((char *) pFindData, + (char *) &pSMBr->hdr.Protocol + + pSMBr->DataOffset, sizeof (FILE_ALL_INFO)); + } else + rc = -ENOMEM; + } + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto QPathInfoRetry; + + return rc; +} + +int +CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon, + const unsigned char *searchName, + FILE_UNIX_BASIC_INFO * pFindData, + const struct nls_table *nls_codepage) +{ +/* SMB_QUERY_FILE_UNIX_BASIC */ + TRANSACTION2_QPI_REQ *pSMB = NULL; + TRANSACTION2_QPI_RSP *pSMBr = NULL; + int rc = 0; + int bytes_returned = 0; + int name_len; + + cFYI(1, ("In QPathInfo (Unix) the path %s", searchName)); +UnixQPathInfoRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(searchName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, searchName, name_len); + } + + pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ + + name_len /* includes null */ ; + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le16(2); + /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxDataCount = cpu_to_le16(4000); + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in QPathInfo = %d", rc)); + } else { /* decode response */ + pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + /* BB also check if enough total bytes returned */ + if ((pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO)) || + (pSMBr->DataOffset > 512) || + (pSMBr->DataOffset < sizeof(struct smb_hdr))) { + cFYI(1,("UnixQPathinfo invalid data offset %d bytes returned %d", + (int)pSMBr->DataOffset,bytes_returned)); + rc = -EIO; /* bad smb */ + } else { + memcpy((char *) pFindData, + (char *) &pSMBr->hdr.Protocol + + pSMBr->DataOffset, + sizeof (FILE_UNIX_BASIC_INFO)); + } + } + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto UnixQPathInfoRetry; + + return rc; +} + +int +CIFSFindSingle(const int xid, struct cifsTconInfo *tcon, + const char *searchName, FILE_ALL_INFO * findData, + const struct nls_table *nls_codepage) +{ +/* level 257 SMB_ */ + TRANSACTION2_FFIRST_REQ *pSMB = NULL; + TRANSACTION2_FFIRST_RSP *pSMBr = NULL; + int rc = 0; + int bytes_returned; + int name_len; + + cFYI(1, ("In FindUnique")); +findUniqueRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(searchName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, searchName, name_len); + } + + pSMB->TotalParameterCount = 12 + name_len /* includes null */ ; + pSMB->TotalDataCount = 0; /* no EAs */ + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = cpu_to_le16( + offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; /* one byte, no need to le convert */ + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST); + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalDataCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->SearchAttributes = + cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | + ATTR_DIRECTORY); + pSMB->SearchCount = cpu_to_le16(16); /* BB increase */ + pSMB->SearchFlags = cpu_to_le16(1); + pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO); + pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */ + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + + if (rc) { + cFYI(1, ("Send error in FindFileDirInfo = %d", rc)); + } else { /* decode response */ + + /* BB fill in */ + } + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto findUniqueRetry; + + return rc; +} + +int +CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, + const char *searchName, FILE_DIRECTORY_INFO * findData, + T2_FFIRST_RSP_PARMS * findParms, + const struct nls_table *nls_codepage, int *pUnicodeFlag, + int *pUnixFlag) +{ +/* level 257 SMB_ */ + TRANSACTION2_FFIRST_REQ *pSMB = NULL; + TRANSACTION2_FFIRST_RSP *pSMBr = NULL; + char *response_data; + int rc = 0; + int bytes_returned; + int name_len; + + cFYI(1, ("In FindFirst")); +findFirstRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(searchName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, searchName, name_len); + } + + pSMB->TotalParameterCount = 12 + name_len /* includes null */ ; + pSMB->TotalDataCount = 0; /* no EAs */ + pSMB->MaxParameterCount = cpu_to_le16(10); + pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf - + MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->ParameterOffset = cpu_to_le16(offsetof(struct + smb_com_transaction2_ffirst_req, SearchAttributes) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; /* one byte no need to make endian neutral */ + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST); + pSMB->SearchAttributes = + cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | + ATTR_DIRECTORY); + pSMB->SearchCount = cpu_to_le16(CIFS_MAX_MSGSIZE / sizeof (FILE_DIRECTORY_INFO)); /* should this be shrunk even more ? */ + pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME); + + /* test for Unix extensions */ + if (tcon->ses->capabilities & CAP_UNIX) { + pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX); + *pUnixFlag = TRUE; + } else { + pSMB->InformationLevel = + cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO); + *pUnixFlag = FALSE; + } + pSMB->SearchStorageType = 0; /* BB what should we set this to? It is not clear if it matters BB */ + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + + if (rc) { /* BB add logic to retry regular search if Unix search rejected unexpectedly by server */ + cFYI(1, ("Error in FindFirst = %d", rc)); + } else { /* decode response */ + /* BB add safety checks for these memcpys */ + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) + *pUnicodeFlag = TRUE; + else + *pUnicodeFlag = FALSE; + memcpy(findParms, + (char *) &pSMBr->hdr.Protocol + + le16_to_cpu(pSMBr->ParameterOffset), + sizeof (T2_FFIRST_RSP_PARMS)); + /* search handle can stay LE and EAoffset not needed so not converted */ + findParms->EndofSearch = le16_to_cpu(findParms->EndofSearch); + findParms->LastNameOffset = + le16_to_cpu(findParms->LastNameOffset); + findParms->SearchCount = le16_to_cpu(findParms->SearchCount); + response_data = + (char *) &pSMBr->hdr.Protocol + + le16_to_cpu(pSMBr->DataOffset); + memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount)); + } + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto findFirstRetry; + + return rc; +} + +int +CIFSFindNext(const int xid, struct cifsTconInfo *tcon, + FILE_DIRECTORY_INFO * findData, T2_FNEXT_RSP_PARMS * findParms, + const __u16 searchHandle, char * resume_file_name, int name_len, + __u32 resume_key, int *pUnicodeFlag, int *pUnixFlag) +{ +/* level 257 SMB_ */ + TRANSACTION2_FNEXT_REQ *pSMB = NULL; + TRANSACTION2_FNEXT_RSP *pSMBr = NULL; + char *response_data; + int rc = 0; + int bytes_returned; + + cFYI(1, ("In FindNext")); + + if(resume_file_name == NULL) { + return -EIO; + } + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->TotalParameterCount = 14; /* includes 2 bytes of null string, converted to LE below */ + pSMB->TotalDataCount = 0; /* no EAs */ + pSMB->MaxParameterCount = cpu_to_le16(8); + pSMB->MaxDataCount = + cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_fnext_req,SearchHandle) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT); + pSMB->SearchHandle = searchHandle; /* always kept as le */ + findParms->SearchCount = 0; /* set to zero in case of error */ + pSMB->SearchCount = + cpu_to_le16(CIFS_MAX_MSGSIZE / sizeof (FILE_DIRECTORY_INFO)); + /* test for Unix extensions */ + if (tcon->ses->capabilities & CAP_UNIX) { + pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX); + *pUnixFlag = TRUE; + } else { + pSMB->InformationLevel = + cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO); + *pUnixFlag = FALSE; + } + pSMB->ResumeKey = resume_key; + pSMB->SearchFlags = + cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME); + /* BB add check to make sure we do not cross end of smb */ + if(name_len < CIFS_MAX_MSGSIZE) { + memcpy(pSMB->ResumeFileName, resume_file_name, name_len); + pSMB->ByteCount += name_len; + } + pSMB->TotalParameterCount += name_len; + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + /* BB improve error handling here */ + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + + if (rc) { + if (rc == -EBADF) + rc = 0; /* search probably was closed at end of search above */ + else + cFYI(1, ("FindNext returned = %d", rc)); + } else { /* decode response */ + /* BB add safety checks for these memcpys */ + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) + *pUnicodeFlag = TRUE; + else + *pUnicodeFlag = FALSE; + memcpy(findParms, + (char *) &pSMBr->hdr.Protocol + + le16_to_cpu(pSMBr->ParameterOffset), + sizeof (T2_FNEXT_RSP_PARMS)); + findParms->EndofSearch = le16_to_cpu(findParms->EndofSearch); + findParms->LastNameOffset = + le16_to_cpu(findParms->LastNameOffset); + findParms->SearchCount = le16_to_cpu(findParms->SearchCount); + response_data = + (char *) &pSMBr->hdr.Protocol + + le16_to_cpu(pSMBr->DataOffset); + memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount)); + } + if (pSMB) + cifs_buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + + return rc; +} + +int +CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle) +{ + int rc = 0; + FINDCLOSE_REQ *pSMB = NULL; + CLOSE_RSP *pSMBr = NULL; + int bytes_returned; + + cFYI(1, ("In CIFSSMBFindClose")); + rc = smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **) &pSMB, + (void **) &pSMBr); + /* no sense returning error if session restarted + file handle has been closed */ + if(rc == -EAGAIN) + return 0; + if (rc) + return rc; + + pSMB->FileID = searchHandle; + pSMB->ByteCount = 0; + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cERROR(1, ("Send error in FindClose = %d", rc)); + } + if (pSMB) + cifs_buf_release(pSMB); + + /* Since session is dead, search handle closed on server already */ + if (rc == -EAGAIN) + rc = 0; + + return rc; +} + +int +CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, + const unsigned char *searchName, + unsigned char **targetUNCs, + unsigned int *number_of_UNC_in_array, + const struct nls_table *nls_codepage) +{ +/* TRANS2_GET_DFS_REFERRAL */ + TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL; + TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL; + struct dfs_referral_level_3 * referrals = NULL; + int rc = 0; + int bytes_returned; + int name_len; + unsigned int i; + char * temp; + *number_of_UNC_in_array = 0; + *targetUNCs = NULL; + + cFYI(1, ("In GetDFSRefer the path %s", searchName)); + if (ses == NULL) + return -ENODEV; +getDFSRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->hdr.Tid = ses->ipc_tid; + pSMB->hdr.Uid = ses->Suid; + if (ses->capabilities & CAP_STATUS32) { + pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS; + } + if (ses->capabilities & CAP_DFS) { + pSMB->hdr.Flags2 |= SMBFLG2_DFS; + } + + if (ses->capabilities & CAP_UNICODE) { + pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; + name_len = + cifs_strtoUCS((wchar_t *) pSMB->RequestFileName, + searchName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(searchName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->RequestFileName, searchName, name_len); + } + + pSMB->ParameterCount = 2 /* level */ + name_len /*includes null */ ; + pSMB->TotalDataCount = 0; + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->MaxParameterCount = 0; + pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4); + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL); + pSMB->ByteCount = pSMB->ParameterCount + 3 /* pad */ ; + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->TotalParameterCount = pSMB->ParameterCount; + pSMB->MaxReferralLevel = cpu_to_le16(3); + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in GetDFSRefer = %d", rc)); + } else { /* decode response */ +/* BB Add logic to parse referrals here */ + pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount); + cFYI(1, + ("Decoding GetDFSRefer response. BCC: %d Offset %d", + pSMBr->ByteCount, pSMBr->DataOffset)); + if ((pSMBr->ByteCount < 17) || (pSMBr->DataOffset > 512)) /* BB also check enough total bytes returned */ + rc = -EIO; /* bad smb */ + else { + referrals = + (struct dfs_referral_level_3 *) + (8 /* sizeof start of data block */ + + pSMBr->DataOffset + + (char *) &pSMBr->hdr.Protocol); + cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x",pSMBr->NumberOfReferrals,pSMBr->DFSFlags, referrals->ReferralSize,referrals->ServerType,referrals->ReferralFlags,referrals->TimeToLive)); + /* BB This field is actually two bytes in from start of + data block so we could do safety check that DataBlock + begins at address of pSMBr->NumberOfReferrals */ + *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals); + + /* BB Fix below so can return more than one referral */ + if(*number_of_UNC_in_array > 1) + *number_of_UNC_in_array = 1; + + /* get the length of the strings describing refs */ + name_len = 0; + for(i=0;i<*number_of_UNC_in_array;i++) { + /* make sure that DfsPathOffset not past end */ + referrals->DfsPathOffset = le16_to_cpu(referrals->DfsPathOffset); + if(referrals->DfsPathOffset > pSMBr->DataCount) { + /* if invalid referral, stop here and do + not try to copy any more */ + *number_of_UNC_in_array = i; + break; + } + temp = ((char *)referrals) + referrals->DfsPathOffset; + + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len += UniStrnlen((wchar_t *)temp,pSMBr->DataCount); + } else { + name_len += strnlen(temp,pSMBr->DataCount); + } + referrals++; + /* BB add check that referral pointer does not fall off end PDU */ + + } + /* BB add check for name_len bigger than bcc */ + *targetUNCs = + kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL); + /* copy the ref strings */ + referrals = + (struct dfs_referral_level_3 *) + (8 /* sizeof data hdr */ + + pSMBr->DataOffset + + (char *) &pSMBr->hdr.Protocol); + + for(i=0;i<*number_of_UNC_in_array;i++) { + temp = ((char *)referrals) + referrals->DfsPathOffset; + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { + cifs_strfromUCS_le(*targetUNCs, + (wchar_t *) temp, name_len, nls_codepage); + } else { + strncpy(*targetUNCs,temp,name_len); + } + /* BB update target_uncs pointers */ + referrals++; + } + temp = *targetUNCs; + temp[name_len] = 0; + } + + } + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto getDFSRetry; + + return rc; +} + +int +CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, + struct statfs *FSData, const struct nls_table *nls_codepage) +{ +/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */ + TRANSACTION2_QFSI_REQ *pSMB = NULL; + TRANSACTION2_QFSI_RSP *pSMBr = NULL; + FILE_SYSTEM_INFO *response_data; + int rc = 0; + int bytes_returned = 0; + + cFYI(1, ("In QFSInfo")); +QFSInfoRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->TotalParameterCount = 2; /* level */ + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); + pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO); + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cERROR(1, ("Send error in QFSInfo = %d", rc)); + } else { /* decode response */ + pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + cFYI(1, + ("Decoding qfsinfo response. BCC: %d Offset %d", + pSMBr->ByteCount, pSMBr->DataOffset)); + if ((pSMBr->ByteCount < 24) || (pSMBr->DataOffset > 512)) /* BB also check enough total bytes returned */ + rc = -EIO; /* bad smb */ + else { + response_data = + (FILE_SYSTEM_INFO + *) (((char *) &pSMBr->hdr.Protocol) + + pSMBr->DataOffset); + FSData->f_bsize = + le32_to_cpu(response_data->BytesPerSector) * + le32_to_cpu(response_data-> + SectorsPerAllocationUnit); + FSData->f_blocks = + le64_to_cpu(response_data->TotalAllocationUnits); + FSData->f_bfree = FSData->f_bavail = + le64_to_cpu(response_data->FreeAllocationUnits); + cFYI(1, + ("Blocks: %lld Free: %lld Block size %ld", + (unsigned long long)FSData->f_blocks, + (unsigned long long)FSData->f_bfree, + FSData->f_bsize)); + } + } + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto QFSInfoRetry; + + return rc; +} + +int +CIFSSMBQFSAttributeInfo(int xid, struct cifsTconInfo *tcon, + const struct nls_table *nls_codepage) +{ +/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */ + TRANSACTION2_QFSI_REQ *pSMB = NULL; + TRANSACTION2_QFSI_RSP *pSMBr = NULL; + FILE_SYSTEM_ATTRIBUTE_INFO *response_data; + int rc = 0; + int bytes_returned = 0; + + cFYI(1, ("In QFSAttributeInfo")); +QFSAttributeRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->TotalParameterCount = 2; /* level */ + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); + pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO); + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cERROR(1, ("Send error in QFSAttributeInfo = %d", rc)); + } else { /* decode response */ + pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + if ((pSMBr->ByteCount < 13) || (pSMBr->DataOffset > 512)) { /* BB also check enough bytes returned */ + rc = -EIO; /* bad smb */ + } else { + response_data = + (FILE_SYSTEM_ATTRIBUTE_INFO + *) (((char *) &pSMBr->hdr.Protocol) + + pSMBr->DataOffset); + response_data->Attributes = le32_to_cpu(response_data->Attributes); + response_data->MaxPathNameComponentLength = + le32_to_cpu(response_data->MaxPathNameComponentLength); + response_data->FileSystemNameLen = + le32_to_cpu(response_data->FileSystemNameLen); + memcpy(&tcon->fsAttrInfo, response_data, + sizeof (FILE_SYSTEM_ATTRIBUTE_INFO)); + } + } + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto QFSAttributeRetry; + + return rc; +} + +int +CIFSSMBQFSDeviceInfo(int xid, struct cifsTconInfo *tcon, + const struct nls_table *nls_codepage) +{ +/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */ + TRANSACTION2_QFSI_REQ *pSMB = NULL; + TRANSACTION2_QFSI_RSP *pSMBr = NULL; + FILE_SYSTEM_DEVICE_INFO *response_data; + int rc = 0; + int bytes_returned = 0; + + cFYI(1, ("In QFSDeviceInfo")); +QFSDeviceRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->TotalParameterCount = 2; /* level */ + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); + + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); + pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO); + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in QFSDeviceInfo = %d", rc)); + } else { /* decode response */ + pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + if ((pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)) + || (pSMBr->DataOffset > 512)) + rc = -EIO; /* bad smb */ + else { + response_data = + (FILE_SYSTEM_DEVICE_INFO + *) (((char *) &pSMBr->hdr.Protocol) + + pSMBr->DataOffset); + response_data->DeviceType = + le32_to_cpu(response_data->DeviceType); + response_data->DeviceCharacteristics = + le32_to_cpu(response_data->DeviceCharacteristics); + memcpy(&tcon->fsDevInfo, response_data, + sizeof (FILE_SYSTEM_DEVICE_INFO)); + } + } + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto QFSDeviceRetry; + + return rc; +} + +int +CIFSSMBQFSUnixInfo(int xid, struct cifsTconInfo *tcon, + const struct nls_table *nls_codepage) +{ +/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */ + TRANSACTION2_QFSI_REQ *pSMB = NULL; + TRANSACTION2_QFSI_RSP *pSMBr = NULL; + FILE_SYSTEM_UNIX_INFO *response_data; + int rc = 0; + int bytes_returned = 0; + + cFYI(1, ("In QFSUnixInfo")); +QFSUnixRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->ParameterCount = 2; /* level */ + pSMB->TotalDataCount = 0; + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ByteCount = pSMB->ParameterCount + 1 /* pad */ ; + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->TotalParameterCount = pSMB->ParameterCount; + pSMB->ParameterOffset = cpu_to_le16(offsetof(struct + smb_com_transaction2_qfsi_req, InformationLevel) - 4); + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); + pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO); + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cERROR(1, ("Send error in QFSUnixInfo = %d", rc)); + } else { /* decode response */ + pSMBr->DataOffset = cpu_to_le16(pSMBr->DataOffset); + if ((pSMBr->ByteCount < 13) || (pSMBr->DataOffset > 512)) { + rc = -EIO; /* bad smb */ + } else { + response_data = + (FILE_SYSTEM_UNIX_INFO + *) (((char *) &pSMBr->hdr.Protocol) + + pSMBr->DataOffset); + response_data->MajorVersionNumber = + le16_to_cpu(response_data->MajorVersionNumber); + response_data->MinorVersionNumber = + le16_to_cpu(response_data->MinorVersionNumber); + response_data->Capability = + le64_to_cpu(response_data->Capability); + memcpy(&tcon->fsUnixInfo, response_data, + sizeof (FILE_SYSTEM_UNIX_INFO)); + } + } + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto QFSUnixRetry; + + + return rc; +} + +/* We can not use write of zero bytes trick to + set file size due to need for large file support. Also note that + this SetPathInfo is preferred to SetFileInfo based method in next + routine which is only needed to work around a sharing violation bug + in Samba which this routine can run into */ + +int +CIFSSMBSetEOF(int xid, struct cifsTconInfo *tcon, char *fileName, + __u64 size, int SetAllocation, const struct nls_table *nls_codepage) +{ + struct smb_com_transaction2_spi_req *pSMB = NULL; + struct smb_com_transaction2_spi_rsp *pSMBr = NULL; + struct file_end_of_file_info *parm_data; + int name_len; + int rc = 0; + int bytes_returned = 0; + + cFYI(1, ("In SetEOF")); +SetEOFRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(fileName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, fileName, name_len); + } + pSMB->ParameterCount = 6 + name_len; + pSMB->DataCount = sizeof (struct file_end_of_file_info); + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, + InformationLevel) - 4; + pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + if(SetAllocation) { + if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) + pSMB->InformationLevel = + cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2); + else + pSMB->InformationLevel = + cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO); + } else /* Set File Size */ { + if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) + pSMB->InformationLevel = + cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2); + else + pSMB->InformationLevel = + cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO); + } + + parm_data = + (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) + + pSMB->DataOffset); + pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); + pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); + pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; + pSMB->DataCount = cpu_to_le16(pSMB->DataCount); + pSMB->TotalDataCount = pSMB->DataCount; + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->TotalParameterCount = pSMB->ParameterCount; + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + parm_data->FileSize = cpu_to_le64(size); + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("SetPathInfo (file size) returned %d", rc)); + } + + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto SetEOFRetry; + + return rc; +} + +int +CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, + __u16 fid, __u32 pid_of_opener, int SetAllocation) +{ + struct smb_com_transaction2_sfi_req *pSMB = NULL; + struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; + char *data_offset; + struct file_end_of_file_info *parm_data; + int rc = 0; + int bytes_returned = 0; + __u32 tmp; + + cFYI(1, ("SetFileSize (via SetFileInfo) %lld", + (long long)size)); + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + tmp = cpu_to_le32(pid_of_opener); /* override pid of current process + so network fid will be valid */ + pSMB->hdr.Pid = tmp & 0xFFFF; + tmp >>= 16; + pSMB->hdr.PidHigh = tmp & 0xFFFF; + + pSMB->ParameterCount = 6; + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_sfi_req, + Fid) - 4; + pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + + data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; + + pSMB->DataCount = sizeof(struct file_end_of_file_info); + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); + pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; + pSMB->DataCount = cpu_to_le16(pSMB->DataCount); + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->TotalDataCount = pSMB->DataCount; + pSMB->TotalParameterCount = pSMB->ParameterCount; + pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); + parm_data = + (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) + + pSMB->DataOffset); + pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); /* now safe to change to le */ + parm_data->FileSize = cpu_to_le64(size); + pSMB->Fid = fid; + if(SetAllocation) { + if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) + pSMB->InformationLevel = + cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2); + else + pSMB->InformationLevel = + cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO); + } else /* Set File Size */ { + if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) + pSMB->InformationLevel = + cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2); + else + pSMB->InformationLevel = + cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO); + } + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, + ("Send error in SetFileInfo (SetFileSize) = %d", + rc)); + } + + if (pSMB) + cifs_buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + + return rc; +} + +int +CIFSSMBSetTimes(int xid, struct cifsTconInfo *tcon, char *fileName, + FILE_BASIC_INFO * data, const struct nls_table *nls_codepage) +{ + TRANSACTION2_SPI_REQ *pSMB = NULL; + TRANSACTION2_SPI_RSP *pSMBr = NULL; + int name_len; + int rc = 0; + int bytes_returned = 0; + char *data_offset; + + cFYI(1, ("In SetTimes")); + +SetTimesRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(fileName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, fileName, name_len); + } + + pSMB->ParameterCount = 6 + name_len; + pSMB->DataCount = sizeof (FILE_BASIC_INFO); + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, + InformationLevel) - 4; + pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; + pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); + pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); + pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; + + pSMB->DataCount = cpu_to_le16(pSMB->DataCount); + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->TotalDataCount = pSMB->DataCount; + pSMB->TotalParameterCount = pSMB->ParameterCount; + if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) + pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2); + else + pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + memcpy(data_offset, data, sizeof (FILE_BASIC_INFO)); + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("SetPathInfo (times) returned %d", rc)); + } + + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto SetTimesRetry; + + return rc; +} + +int +CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon, + char *fileName, __u64 mode, __u64 uid, __u64 gid, + dev_t device, const struct nls_table *nls_codepage) +{ + TRANSACTION2_SPI_REQ *pSMB = NULL; + TRANSACTION2_SPI_RSP *pSMBr = NULL; + int name_len; + int rc = 0; + int bytes_returned = 0; + FILE_UNIX_BASIC_INFO *data_offset; + + cFYI(1, ("In SetUID/GID/Mode")); +setPermsRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(fileName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, fileName, name_len); + } + + pSMB->ParameterCount = 6 + name_len; + pSMB->DataCount = sizeof (FILE_UNIX_BASIC_INFO); + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, + InformationLevel) - 4; + pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + data_offset = + (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol + + pSMB->DataOffset); + pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); + pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); + pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->DataCount = cpu_to_le16(pSMB->DataCount); + pSMB->TotalParameterCount = pSMB->ParameterCount; + pSMB->TotalDataCount = pSMB->DataCount; + pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + data_offset->Uid = cpu_to_le64(uid); + data_offset->Gid = cpu_to_le64(gid); + /* better to leave device as zero when it is */ + data_offset->DevMajor = cpu_to_le64(MAJOR(device)); + data_offset->DevMinor = cpu_to_le64(MINOR(device)); + data_offset->Permissions = cpu_to_le64(mode); + + if(S_ISREG(mode)) + data_offset->Type = cpu_to_le32(UNIX_FILE); + else if(S_ISDIR(mode)) + data_offset->Type = cpu_to_le32(UNIX_DIR); + else if(S_ISLNK(mode)) + data_offset->Type = cpu_to_le32(UNIX_SYMLINK); + else if(S_ISCHR(mode)) + data_offset->Type = cpu_to_le32(UNIX_CHARDEV); + else if(S_ISBLK(mode)) + data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV); + else if(S_ISFIFO(mode)) + data_offset->Type = cpu_to_le32(UNIX_FIFO); + else if(S_ISSOCK(mode)) + data_offset->Type = cpu_to_le32(UNIX_SOCKET); + + + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("SetPathInfo (perms) returned %d", rc)); + } + + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto setPermsRetry; + return rc; +} + +int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, + const int notify_subdirs, const __u16 netfid, + __u32 filter, const struct nls_table *nls_codepage) +{ + int rc = 0; + struct smb_com_transaction_change_notify_req * pSMB = NULL; + struct smb_com_transaction_change_notify_rsp * pSMBr = NULL; + int bytes_returned; + + cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid)); + rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + pSMB->TotalParameterCount = 0 ; + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le32(2); + /* BB find exact data count max from sess structure BB */ + pSMB->MaxDataCount = 0; /* same in little endian or be */ + pSMB->MaxSetupCount = 4; + pSMB->Reserved = 0; + pSMB->ParameterOffset = 0; + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 4; /* single byte does not need le conversion */ + pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE); + pSMB->ParameterCount = pSMB->TotalParameterCount; + if(notify_subdirs) + pSMB->WatchTree = 1; /* one byte - no le conversion needed */ + pSMB->Reserved2 = 0; + pSMB->CompletionFilter = cpu_to_le32(filter); + pSMB->Fid = netfid; /* file handle always le */ + pSMB->ByteCount = 0; + + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Error in Notify = %d", rc)); + } + if (pSMB) + cifs_buf_release(pSMB); +/* if (rc == -EAGAIN) + goto NotifyRetry; */ + return rc; +} +#ifdef CONFIG_CIFS_XATTR +int +CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, + const unsigned char *searchName, + char * EAData, size_t size, + const struct nls_table *nls_codepage) +{ + /* BB assumes one setup word */ + TRANSACTION2_QPI_REQ *pSMB = NULL; + TRANSACTION2_QPI_RSP *pSMBr = NULL; + int rc = 0; + int bytes_returned; + int name_len; + + cFYI(1, ("In Query All EAs path %s", searchName)); +QAllEAsRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(searchName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, searchName, name_len); + } + + pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ + + name_len /* includes null */ ; + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in QueryAllEAs = %d", rc)); + } else { /* decode response */ + pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + /* BB also check enough total bytes returned */ + /* BB we need to improve the validity checking + of these trans2 responses */ + if ((pSMBr->ByteCount < 4) || (pSMBr->DataOffset > 512)) + rc = -EIO; /* bad smb */ + /* else if (pFindData){ + memcpy((char *) pFindData, + (char *) &pSMBr->hdr.Protocol + + pSMBr->DataOffset, kl); + }*/ else { + /* check that length of list is not more than bcc */ + /* check that each entry does not go beyond length + of list */ + /* check that each element of each entry does not + go beyond end of list */ + struct fealist * ea_response_data; + rc = 0; + /* validate_trans2_offsets() */ + /* BB to check if(start of smb + pSMBr->DataOffset > &bcc+ bcc)*/ + ea_response_data = (struct fealist *) + (((char *) &pSMBr->hdr.Protocol) + + pSMBr->DataOffset); + cFYI(1,("ea length %d",ea_response_data->list_len)); + } + } + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto QAllEAsRetry; + + return rc; +} +#endif diff --git a/release/src/linux/linux/fs/cifs/connect.c b/release/src/linux/linux/fs/cifs/connect.c new file mode 100644 index 00000000..76e4a04f --- /dev/null +++ b/release/src/linux/linux/fs/cifs/connect.c @@ -0,0 +1,2925 @@ +/* + * fs/cifs/connect.c + * + * Copyright (C) International Business Machines Corp., 2002,2004 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/fs.h> +#include <linux/net.h> +#include <linux/string.h> +#include <linux/list.h> +#include <linux/wait.h> +#include <linux/version.h> +#include <linux/ipv6.h> +#include <linux/pagemap.h> +#include <linux/ctype.h> +#include <linux/utsname.h> +#include <asm/uaccess.h> +#include <asm/processor.h> +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_unicode.h" +#include "cifs_debug.h" +#include "cifs_fs_sb.h" +#include "ntlmssp.h" +#include "nterr.h" +#include "rfc1002pdu.h" + +#define CIFS_PORT 445 +#define RFC1001_PORT 139 + +extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, + unsigned char *p24); +extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, + unsigned char *p24); +extern int cifs_inet_pton(int, const char *, void *dst); + +struct smb_vol { + char *username; + char *password; + char *domainname; + char *UNC; + char *UNCip; + char *iocharset; /* local code page for mapping to and from Unicode */ + char source_rfc1001_name[16]; /* netbios name of client */ + uid_t linux_uid; + gid_t linux_gid; + mode_t file_mode; + mode_t dir_mode; + int rw:1; + int retry:1; + int intr:1; + unsigned int rsize; + unsigned int wsize; + unsigned int sockopt; + unsigned short int port; +}; + +static int ipv4_connect(struct sockaddr_in *psin_server, + struct socket **csocket, + char * netb_name); +static int ipv6_connect(struct sockaddr_in6 *psin_server, + struct socket **csocket); + + + /* + * cifs tcp session reconnection + * + * mark tcp session as reconnecting so temporarily locked + * mark all smb sessions as reconnecting for tcp session + * reconnect tcp session + * wake up waiters on reconnection? - (not needed currently) + */ + +int +cifs_reconnect(struct TCP_Server_Info *server) +{ + int rc = 0; + struct list_head *tmp; + struct cifsSesInfo *ses; + struct cifsTconInfo *tcon; + struct mid_q_entry * mid_entry; + + spin_lock(&GlobalMid_Lock); + if(server->tcpStatus == CifsExiting) { + /* the demux thread will exit normally + next time through the loop */ + spin_unlock(&GlobalMid_Lock); + return rc; + } else + server->tcpStatus = CifsNeedReconnect; + spin_unlock(&GlobalMid_Lock); + server->maxBuf = 0; + + cFYI(1, ("Reconnecting tcp session ")); + + /* before reconnecting the tcp session, mark the smb session (uid) + and the tid bad so they are not used until reconnected */ + read_lock(&GlobalSMBSeslock); + list_for_each(tmp, &GlobalSMBSessionList) { + ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); + if (ses->server) { + if (ses->server == server) { + ses->status = CifsNeedReconnect; + ses->ipc_tid = 0; + } + } + /* else tcp and smb sessions need reconnection */ + } + list_for_each(tmp, &GlobalTreeConnectionList) { + tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); + if((tcon) && (tcon->ses) && (tcon->ses->server == server)) { + tcon->tidStatus = CifsNeedReconnect; + } + } + read_unlock(&GlobalSMBSeslock); + /* do not want to be sending data on a socket we are freeing */ + down(&server->tcpSem); + if(server->ssocket) { + cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state, + server->ssocket->flags)); + server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN); + cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state, + server->ssocket->flags)); + sock_release(server->ssocket); + server->ssocket = NULL; + } + + spin_lock(&GlobalMid_Lock); + list_for_each(tmp, &server->pending_mid_q) { + mid_entry = list_entry(tmp, struct + mid_q_entry, + qhead); + if(mid_entry) { + if(mid_entry->midState == MID_REQUEST_SUBMITTED) { + /* Mark other intransit requests as needing retry so + we do not immediately mark the session bad again + (ie after we reconnect below) as they timeout too */ + mid_entry->midState = MID_RETRY_NEEDED; + } + } + } + spin_unlock(&GlobalMid_Lock); + up(&server->tcpSem); + + while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood)) + { + if(server->protocolType == IPV6) { + rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket); + } else { + rc = ipv4_connect(&server->addr.sockAddr, + &server->ssocket, + server->workstation_RFC1001_name); + } + if(rc) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(3 * HZ); + } else { + atomic_inc(&tcpSesReconnectCount); + spin_lock(&GlobalMid_Lock); + if(server->tcpStatus != CifsExiting) + server->tcpStatus = CifsGood; + spin_unlock(&GlobalMid_Lock); + /* atomic_set(&server->inFlight,0);*/ + wake_up(&server->response_q); + } + } + return rc; +} + +static int +cifs_demultiplex_thread(struct TCP_Server_Info *server) +{ + int length; + unsigned int pdu_length, total_read; + struct smb_hdr *smb_buffer = NULL; + struct msghdr smb_msg; + mm_segment_t temp_fs; + struct iovec iov; + struct socket *csocket = server->ssocket; + struct list_head *tmp; + struct cifsSesInfo *ses; + struct task_struct *task_to_wake = NULL; + struct mid_q_entry *mid_entry; + char *temp; + + daemonize(); + sprintf(current->comm,"cifsd"); + /* allow_signal(SIGKILL);*/ + current->flags |= PF_MEMALLOC; + server->tsk = current; /* save process info to wake at shutdown */ + cFYI(1, ("Demultiplex PID: %d", current->pid)); + + temp_fs = get_fs(); /* we must turn off socket api parm checking */ + set_fs(get_ds()); + + while (server->tcpStatus != CifsExiting) { + if (smb_buffer == NULL) + smb_buffer = cifs_buf_get(); + else + memset(smb_buffer, 0, sizeof (struct smb_hdr)); + + if (smb_buffer == NULL) { + cERROR(1,("Can not get memory for SMB response")); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ * 3); /* give system time to free memory */ + continue; + } + iov.iov_base = smb_buffer; + iov.iov_len = sizeof (struct smb_hdr) - 1; + /* 1 byte less above since wct is not always returned in error cases */ + smb_msg.msg_iov = &iov; + smb_msg.msg_iovlen = 1; + smb_msg.msg_control = NULL; + smb_msg.msg_controllen = 0; + + length = + sock_recvmsg(csocket, &smb_msg, + sizeof (struct smb_hdr) - + 1 /* RFC1001 header and SMB header */ , + MSG_PEEK /* flags see socket.h */ ); + + if(server->tcpStatus == CifsExiting) { + break; + } else if (server->tcpStatus == CifsNeedReconnect) { + cFYI(1,("Reconnecting after server stopped responding")); + cifs_reconnect(server); + cFYI(1,("call to reconnect done")); + csocket = server->ssocket; + continue; + } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); /* minimum sleep to prevent looping + allowing socket to clear and app threads to set + tcpStatus CifsNeedReconnect if server hung */ + continue; + } else if (length <= 0) { + if(server->tcpStatus == CifsNew) { + cFYI(1,("tcp session abended prematurely (after SMBnegprot)")); + /* some servers kill tcp session rather than returning + smb negprot error in which case reconnecting here is + not going to help - return error to mount */ + break; + } + if(length == -EINTR) { + cFYI(1,("cifsd thread killed")); + break; + } + cFYI(1,("Reconnecting after unexpected peek error %d",length)); + cifs_reconnect(server); + csocket = server->ssocket; + wake_up(&server->response_q); + continue; + } + + pdu_length = 4 + ntohl(smb_buffer->smb_buf_length); + /* Ony read pdu_length after below checks for too short (due + to e.g. int overflow) and too long ie beyond end of buf */ + cFYI(1, ("Peek length rcvd: 0x%x beginning 0x%x)", length, pdu_length)); + + temp = (char *) smb_buffer; + if (length > 3) { + if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { + iov.iov_base = smb_buffer; + iov.iov_len = 4; + length = sock_recvmsg(csocket, &smb_msg, 4, 0); + cFYI(0,("Received 4 byte keep alive packet")); + } else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) { + iov.iov_base = smb_buffer; + iov.iov_len = 4; + length = sock_recvmsg(csocket, &smb_msg, 4, 0); + cFYI(1,("Good RFC 1002 session rsp")); + } else if ((temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) + && (length == 5)) { + /* we get this from Windows 98 instead of error on SMB negprot response */ + cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4])); + if(server->tcpStatus == CifsNew) { + /* if nack on negprot (rather than + ret of smb negprot error) reconnecting + not going to help, ret error to mount */ + break; + } else { + /* give server a second to + clean up before reconnect attempt */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + /* always try 445 first on reconnect + since we get NACK on some if we ever + connected to port 139 (the NACK is + since we do not begin with RFC1001 + session initialize frame) */ + server->addr.sockAddr.sin_port = CIFS_PORT; + cifs_reconnect(server); + csocket = server->ssocket; + wake_up(&server->response_q); + continue; + } + } else if (temp[0] != (char) 0) { + cERROR(1,("Unknown RFC 1002 frame")); + cifs_dump_mem(" Received Data: ", temp, length); + cifs_reconnect(server); + csocket = server->ssocket; + continue; + } else { + if ((length != sizeof (struct smb_hdr) - 1) + || (pdu_length > + CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) + || (pdu_length < + sizeof (struct smb_hdr) - 1) + || + (checkSMBhdr + (smb_buffer, smb_buffer->Mid))) { + cERROR(1, + ("Invalid size or format for SMB found with length %d and pdu_lenght %d", + length, pdu_length)); + cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); + /* could we fix this network corruption by finding next + smb header (instead of killing the session) and + restart reading from next valid SMB found? */ + cifs_reconnect(server); + csocket = server->ssocket; + continue; + } else { /* length ok */ + + length = 0; + iov.iov_base = smb_buffer; + iov.iov_len = pdu_length; + for (total_read = 0; + total_read < pdu_length; + total_read += length) { + length = sock_recvmsg(csocket, &smb_msg, + pdu_length - total_read, 0); + if (length == 0) { + cERROR(1, + ("Zero length receive when expecting %d ", + pdu_length - total_read)); + cifs_reconnect(server); + csocket = server->ssocket; + continue; + } + } + } + + dump_smb(smb_buffer, length); + if (checkSMB + (smb_buffer, smb_buffer->Mid, total_read)) { + cERROR(1, ("Bad SMB Received ")); + continue; + } + + task_to_wake = NULL; + spin_lock(&GlobalMid_Lock); + list_for_each(tmp, &server->pending_mid_q) { + mid_entry = list_entry(tmp, struct + mid_q_entry, + qhead); + + if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED)) { + cFYI(1, + (" Mid 0x%x matched - waking up ",mid_entry->mid)); + task_to_wake = mid_entry->tsk; + mid_entry->resp_buf = + smb_buffer; + mid_entry->midState = + MID_RESPONSE_RECEIVED; + } + } + spin_unlock(&GlobalMid_Lock); + if (task_to_wake) { + smb_buffer = NULL; /* will be freed by users thread after he is done */ + wake_up_process(task_to_wake); + } else if (is_valid_oplock_break(smb_buffer) == FALSE) { + cERROR(1, ("No task to wake, unknown frame rcvd!")); + cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); + } + } + } else { + cFYI(0, + ("Frame less than four bytes received %d bytes long.", + length)); + if (length > 0) { + length = sock_recvmsg(csocket, &smb_msg, length, 0); /* throw away junk frame */ + cFYI(1, + (" with junk 0x%x in it ", + *(__u32 *) smb_buffer)); + } + } + } + spin_lock(&GlobalMid_Lock); + server->tcpStatus = CifsExiting; + server->tsk = NULL; + atomic_set(&server->inFlight, 0); + spin_unlock(&GlobalMid_Lock); + /* Although there should not be any requests blocked on + this queue it can not hurt to be paranoid and try to wake up requests + that may haven been blocked when more than 50 at time were on the wire + to the same server - they now will see the session is in exit state + and get out of SendReceive. */ + wake_up_all(&server->request_q); + /* give those requests time to exit */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/8); + + if(server->ssocket) { + sock_release(csocket); + server->ssocket = NULL; + } + set_fs(temp_fs); + if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */ + cifs_buf_release(smb_buffer); + + read_lock(&GlobalSMBSeslock); + if (list_empty(&server->pending_mid_q)) { + /* loop through server session structures attached to this and mark them dead */ + list_for_each(tmp, &GlobalSMBSessionList) { + ses = + list_entry(tmp, struct cifsSesInfo, + cifsSessionList); + if (ses->server == server) { + ses->status = CifsExiting; + ses->server = NULL; + } + } + read_unlock(&GlobalSMBSeslock); + } else { + spin_lock(&GlobalMid_Lock); + list_for_each(tmp, &server->pending_mid_q) { + mid_entry = list_entry(tmp, struct mid_q_entry, qhead); + if (mid_entry->midState == MID_REQUEST_SUBMITTED) { + cFYI(1, + (" Clearing Mid 0x%x - waking up ",mid_entry->mid)); + task_to_wake = mid_entry->tsk; + if(task_to_wake) { + wake_up_process(task_to_wake); + } + } + } + spin_unlock(&GlobalMid_Lock); + read_unlock(&GlobalSMBSeslock); + set_current_state(TASK_INTERRUPTIBLE); + /* 1/8th of sec is more than enough time for them to exit */ + schedule_timeout(HZ/8); + } + + if (list_empty(&server->pending_mid_q)) { + /* mpx threads have not exited yet give them + at least the smb send timeout time for long ops */ + cFYI(1, ("Wait for exit from demultiplex thread")); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(46 * HZ); + /* if threads still have not exited they are probably never + coming home not much else we can do but free the memory */ + } + kfree(server); + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/4); + return 0; +} + +static void * +cifs_kcalloc(size_t size, int type) +{ + void *addr; + addr = kmalloc(size, type); + if (addr) + memset(addr, 0, size); + return addr; +} + +static int +cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol) +{ + char *value; + char *data; + unsigned int temp_len, i, j; + char separator[2]; + + separator[0] = ','; + separator[1] = 0; + + memset(vol->source_rfc1001_name,0x20,15); + for(i=0;i < strnlen(system_utsname.nodename,15);i++) { + /* does not have to be a perfect mapping since the field is + informational, only used for servers that do not support + port 445 and it can be overridden at mount time */ + vol->source_rfc1001_name[i] = toupper(system_utsname.nodename[i]); + } + vol->source_rfc1001_name[15] = 0; + + vol->linux_uid = current->uid; /* current->euid instead? */ + vol->linux_gid = current->gid; + vol->dir_mode = S_IRWXUGO; + /* 2767 perms indicate mandatory locking support */ + vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP); + + /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ + vol->rw = TRUE; + + if (!options) + return 1; + + if(strncmp(options,"sep=",4) == 0) { + if(options[4] != 0) { + separator[0] = options[4]; + options += 5; + } else { + cFYI(1,("Null separator not allowed")); + } + } + + while ((data = strsep(&options, separator)) != NULL) { + if (!*data) + continue; + if ((value = strchr(data, '=')) != NULL) + *value++ = '\0'; + if (strnicmp(data, "user", 4) == 0) { + if (!value || !*value) { + printk(KERN_WARNING + "CIFS: invalid or missing username\n"); + return 1; /* needs_arg; */ + } + if (strnlen(value, 200) < 200) { + vol->username = value; + } else { + printk(KERN_WARNING "CIFS: username too long\n"); + return 1; + } + } else if (strnicmp(data, "pass", 4) == 0) { + if (!value || !*value) { + vol->password = NULL; + continue; + } + temp_len = strlen(value); + /* removed password length check, NTLM passwords + can be arbitrarily long */ + + /* if comma in password, the string will be + prematurely null terminated. Commas in password are + specified across the cifs mount interface by a double + comma ie ,, and a comma used as in other cases ie ',' + as a parameter delimiter/separator is single and due + to the strsep above is temporarily zeroed. */ + + /* NB: password legally can have multiple commas and + the only illegal character in a password is null */ + + if ((value[temp_len] == 0) && (value[temp_len+1] == separator[0])) { + /* reinsert comma */ + value[temp_len] = separator[0]; + temp_len+=2; /* move after the second comma */ + while(value[temp_len] != 0) { + if((value[temp_len] == separator[0]) && (value[temp_len+1] != separator[0])) { + /* single comma indicating start of next parm */ + break; + } + temp_len++; + } + if(value[temp_len] == 0) { + options = NULL; + } else { + value[temp_len] = 0; + /* move options to point to start of next parm */ + options = value + temp_len + 1; + } + /* go from value to (value + temp_len) condensing double commas to singles */ + vol->password = cifs_kcalloc(temp_len, GFP_KERNEL); + for(i=0,j=0;i<temp_len;i++,j++) { + vol->password[j] = value[i]; + if(value[i] == separator[0] && value[i+1] == separator[0]) { + /* skip second comma */ + i++; + } + } + /* value[temp_len] is zeroed above so + vol->password[temp_len] guaranteed to be null */ + } else { + vol->password = cifs_kcalloc(temp_len + 1, GFP_KERNEL); + strcpy(vol->password, value); + } + } else if (strnicmp(data, "ip", 2) == 0) { + if (!value || !*value) { + vol->UNCip = NULL; + } else if (strnlen(value, 35) < 35) { + vol->UNCip = value; + } else { + printk(KERN_WARNING "CIFS: ip address too long\n"); + return 1; + } + } else if ((strnicmp(data, "unc", 3) == 0) + || (strnicmp(data, "target", 6) == 0) + || (strnicmp(data, "path", 4) == 0)) { + if (!value || !*value) { + printk(KERN_WARNING + "CIFS: invalid path to network resource\n"); + return 1; /* needs_arg; */ + } + if ((temp_len = strnlen(value, 300)) < 300) { + vol->UNC = kmalloc(temp_len+1,GFP_KERNEL); + if(vol->UNC == NULL) + return 1; + strcpy(vol->UNC,value); + if (strncmp(vol->UNC, "//", 2) == 0) { + vol->UNC[0] = '\\'; + vol->UNC[1] = '\\'; + } else if (strncmp(vol->UNC, "\\\\", 2) != 0) { + printk(KERN_WARNING + "CIFS: UNC Path does not begin with // or \\\\ \n"); + return 1; + } + } else { + printk(KERN_WARNING "CIFS: UNC name too long\n"); + return 1; + } + } else if ((strnicmp(data, "domain", 3) == 0) + || (strnicmp(data, "workgroup", 5) == 0)) { + if (!value || !*value) { + printk(KERN_WARNING "CIFS: invalid domain name\n"); + return 1; /* needs_arg; */ + } + /* BB are there cases in which a comma can be valid in + a domain name and need special handling? */ + if (strnlen(value, 65) < 65) { + vol->domainname = value; + cFYI(1, ("Domain name set")); + } else { + printk(KERN_WARNING "CIFS: domain name too long\n"); + return 1; + } + } else if (strnicmp(data, "iocharset", 9) == 0) { + if (!value || !*value) { + printk(KERN_WARNING "CIFS: invalid iocharset specified\n"); + return 1; /* needs_arg; */ + } + if (strnlen(value, 65) < 65) { + if(strnicmp(value,"default",7)) + vol->iocharset = value; + /* if iocharset not set load_nls_default used by caller */ + cFYI(1, ("iocharset set to %s",value)); + } else { + printk(KERN_WARNING "CIFS: iocharset name too long.\n"); + return 1; + } + } else if (strnicmp(data, "uid", 3) == 0) { + if (value && *value) { + vol->linux_uid = + simple_strtoul(value, &value, 0); + } + } else if (strnicmp(data, "gid", 3) == 0) { + if (value && *value) { + vol->linux_gid = + simple_strtoul(value, &value, 0); + } + } else if (strnicmp(data, "file_mode", 4) == 0) { + if (value && *value) { + vol->file_mode = + simple_strtoul(value, &value, 0); + } + } else if (strnicmp(data, "dir_mode", 3) == 0) { + if (value && *value) { + vol->dir_mode = + simple_strtoul(value, &value, 0); + } + } else if (strnicmp(data, "port", 4) == 0) { + if (value && *value) { + vol->port = + simple_strtoul(value, &value, 0); + } + } else if (strnicmp(data, "rsize", 5) == 0) { + if (value && *value) { + vol->rsize = + simple_strtoul(value, &value, 0); + } + } else if (strnicmp(data, "wsize", 5) == 0) { + if (value && *value) { + vol->wsize = + simple_strtoul(value, &value, 0); + } + } else if (strnicmp(data, "sockopt", 5) == 0) { + if (value && *value) { + vol->sockopt = + simple_strtoul(value, &value, 0); + } + } else if (strnicmp(data, "netbiosname", 4) == 0) { + if (!value || !*value || (*value == ' ')) { + cFYI(1,("invalid (empty) netbiosname specified")); + } else { + memset(vol->source_rfc1001_name,0x20,15); + for(i=0;i<15;i++) { + /* BB are there cases in which a comma can be + valid in this workstation netbios name (and need + special handling)? */ + + /* We do not uppercase netbiosname for user */ + if (value[i]==0) + break; + else + vol->source_rfc1001_name[i] = value[i]; + } + /* The string has 16th byte zero still from + set at top of the function */ + if((i==15) && (value[i] != 0)) + printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n"); + } + } else if (strnicmp(data, "credentials", 4) == 0) { + /* ignore */ + } else if (strnicmp(data, "version", 3) == 0) { + /* ignore */ + } else if (strnicmp(data, "rw", 2) == 0) { + vol->rw = TRUE; + } else if ((strnicmp(data, "suid", 4) == 0) || + (strnicmp(data, "nosuid", 6) == 0) || + (strnicmp(data, "exec", 4) == 0) || + (strnicmp(data, "noexec", 6) == 0) || + (strnicmp(data, "nodev", 5) == 0) || + (strnicmp(data, "noauto", 6) == 0) || + (strnicmp(data, "dev", 3) == 0)) { + /* The mount tool or mount.cifs helper (if present) + uses these opts to set flags, and the flags are read + by the kernel vfs layer before we get here (ie + before read super) so there is no point trying to + parse these options again and set anything and it + is ok to just ignore them */ + continue; + } else if (strnicmp(data, "ro", 2) == 0) { + vol->rw = FALSE; + } else if (strnicmp(data, "hard", 4) == 0) { + vol->retry = 1; + } else if (strnicmp(data, "soft", 4) == 0) { + vol->retry = 0; + } else if (strnicmp(data, "nohard", 6) == 0) { + vol->retry = 0; + } else if (strnicmp(data, "nosoft", 6) == 0) { + vol->retry = 1; + } else if (strnicmp(data, "nointr", 6) == 0) { + vol->intr = 0; + } else if (strnicmp(data, "intr", 4) == 0) { + vol->intr = 1; + } else if (strnicmp(data, "noac", 4) == 0) { + printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n"); + } else + printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data); + } + if (vol->UNC == NULL) { + if(devname == NULL) { + printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n"); + return 1; + } + if ((temp_len = strnlen(devname, 300)) < 300) { + vol->UNC = kmalloc(temp_len+1,GFP_KERNEL); + if(vol->UNC == NULL) + return 1; + strcpy(vol->UNC,devname); + if (strncmp(vol->UNC, "//", 2) == 0) { + vol->UNC[0] = '\\'; + vol->UNC[1] = '\\'; + } else if (strncmp(vol->UNC, "\\\\", 2) != 0) { + printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n"); + return 1; + } + } else { + printk(KERN_WARNING "CIFS: UNC name too long\n"); + return 1; + } + } + if(vol->UNCip == 0) + vol->UNCip = &vol->UNC[2]; + + return 0; +} + +static struct cifsSesInfo * +cifs_find_tcp_session(__u32 new_target_ip_addr, + char *userName, struct TCP_Server_Info **psrvTcp) +{ + struct list_head *tmp; + struct cifsSesInfo *ses; + + *psrvTcp = NULL; + read_lock(&GlobalSMBSeslock); + list_for_each(tmp, &GlobalSMBSessionList) { + ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); + if (ses->server) { + if (ses->server->addr.sockAddr.sin_addr.s_addr == + new_target_ip_addr) { + /* BB lock server and tcp session and increment use count here?? */ + *psrvTcp = ses->server; /* found a match on the TCP session */ + /* BB check if reconnection needed */ + if (strncmp + (ses->userName, userName, + MAX_USERNAME_SIZE) == 0){ + read_unlock(&GlobalSMBSeslock); + return ses; /* found exact match on both tcp and SMB sessions */ + } + } + } + /* else tcp and smb sessions need reconnection */ + } + read_unlock(&GlobalSMBSeslock); + return NULL; +} + +static struct cifsTconInfo * +find_unc(__u32 new_target_ip_addr, char *uncName, char *userName) +{ + struct list_head *tmp; + struct cifsTconInfo *tcon; + + read_lock(&GlobalSMBSeslock); + list_for_each(tmp, &GlobalTreeConnectionList) { + cFYI(1, ("Next tcon - ")); + tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); + if (tcon->ses) { + if (tcon->ses->server) { + cFYI(1, + (" old ip addr: %x == new ip %x ?", + tcon->ses->server->addr.sockAddr.sin_addr. + s_addr, new_target_ip_addr)); + if (tcon->ses->server->addr.sockAddr.sin_addr. + s_addr == new_target_ip_addr) { + /* BB lock tcon and server and tcp session and increment use count here? */ + /* found a match on the TCP session */ + /* BB check if reconnection needed */ + cFYI(1,("Matched ip, old UNC: %s == new: %s ?", + tcon->treeName, uncName)); + if (strncmp + (tcon->treeName, uncName, + MAX_TREE_SIZE) == 0) { + cFYI(1, + ("Matched UNC, old user: %s == new: %s ?", + tcon->treeName, uncName)); + if (strncmp + (tcon->ses->userName, + userName, + MAX_USERNAME_SIZE) == 0) { + read_unlock(&GlobalSMBSeslock); + return tcon;/* also matched user (smb session)*/ + } + } + } + } + } + } + read_unlock(&GlobalSMBSeslock); + return NULL; +} + +int +connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, + const char *old_path, const struct nls_table *nls_codepage) +{ + unsigned char *referrals = NULL; + unsigned int num_referrals; + int rc = 0; + + rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage, + &num_referrals, &referrals); + + /* BB Add in code to: if valid refrl, if not ip address contact + the helper that resolves tcp names, mount to it, try to + tcon to it unmount it if fail */ + + if(referrals) + kfree(referrals); + + return rc; +} + +int +get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, + const char *old_path, const struct nls_table *nls_codepage, + unsigned int *pnum_referrals, unsigned char ** preferrals) +{ + char *temp_unc; + int rc = 0; + + *pnum_referrals = 0; + + if (pSesInfo->ipc_tid == 0) { + temp_unc = kmalloc(2 /* for slashes */ + + strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2) + + 1 + 4 /* slash IPC$ */ + 2, + GFP_KERNEL); + if (temp_unc == NULL) + return -ENOMEM; + temp_unc[0] = '\\'; + temp_unc[1] = '\\'; + strcpy(temp_unc + 2, pSesInfo->serverName); + strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$"); + rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage); + cFYI(1, + ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid)); + kfree(temp_unc); + } + if (rc == 0) + rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals, + pnum_referrals, nls_codepage); + + return rc; +} + +/* See RFC1001 section 14 on representation of Netbios names */ +static void rfc1002mangle(char * target,char * source, unsigned int length) +{ + unsigned int i,j; + + for(i=0,j=0;i<(length);i++) { + /* mask a nibble at a time and encode */ + target[j] = 'A' + (0x0F & (source[i] >> 4)); + target[j+1] = 'A' + (0x0F & source[i]); + j+=2; + } + +} + + +static int +ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, + char * netbios_name) +{ + int rc = 0; + int connected = 0; + unsigned short int orig_port = 0; + + if(*csocket == NULL) { + rc = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket); + if (rc < 0) { + cERROR(1, ("Error %d creating socket",rc)); + *csocket = NULL; + return rc; + } else { + /* BB other socket options to set KEEPALIVE, NODELAY? */ + cFYI(1,("Socket created")); + (*csocket)->sk->allocation = GFP_NOFS; + (*csocket)->sk->keepopen = 1; // test jz + } + } + + psin_server->sin_family = AF_INET; + if(psin_server->sin_port) { /* user overrode default port */ + rc = (*csocket)->ops->connect(*csocket, + (struct sockaddr *) psin_server, + sizeof (struct sockaddr_in),0); + if (rc >= 0) + connected = 1; + } + + if(!connected) { + /* save original port so we can retry user specified port + later if fall back ports fail this time */ + orig_port = psin_server->sin_port; + + /* do not retry on the same port we just failed on */ + if(psin_server->sin_port != htons(CIFS_PORT)) { + psin_server->sin_port = htons(CIFS_PORT); + + rc = (*csocket)->ops->connect(*csocket, + (struct sockaddr *) psin_server, + sizeof (struct sockaddr_in),0); + if (rc >= 0) + connected = 1; + } + } + if (!connected) { + psin_server->sin_port = htons(RFC1001_PORT); + rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) + psin_server, sizeof (struct sockaddr_in),0); + if (rc >= 0) + connected = 1; + } + + /* give up here - unless we want to retry on different + protocol families some day */ + if (!connected) { + if(orig_port) + psin_server->sin_port = orig_port; + cFYI(1,("Error %d connecting to server via ipv4",rc)); + sock_release(*csocket); + *csocket = NULL; + return rc; + } + /* Eventually check for other socket options to change from + the default. sock_setsockopt not used because it expects + user space buffer */ + (*csocket)->sk->rcvtimeo = 7 * HZ; + + /* send RFC1001 sessinit */ + + if(psin_server->sin_port == htons(139)) { + /* some servers require RFC1001 sessinit before sending + negprot - BB check reconnection in case where second + sessinit is sent but no second negprot */ + struct rfc1002_session_packet * ses_init_buf; + struct smb_hdr * smb_buf; + ses_init_buf = cifs_kcalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL); + if(ses_init_buf) { + ses_init_buf->trailer.session_req.called_len = 32; + rfc1002mangle(ses_init_buf->trailer.session_req.called_name, + DEFAULT_CIFS_CALLED_NAME,16); + ses_init_buf->trailer.session_req.calling_len = 32; + /* calling name ends in null (byte 16) from old smb + convention. */ + if(netbios_name && (netbios_name[0] !=0)) { + rfc1002mangle(ses_init_buf->trailer.session_req.calling_name, + netbios_name,16); + } else { + rfc1002mangle(ses_init_buf->trailer.session_req.calling_name, + "LINUX_CIFS_CLNT",16); + } + ses_init_buf->trailer.session_req.scope1 = 0; + ses_init_buf->trailer.session_req.scope2 = 0; + smb_buf = (struct smb_hdr *)ses_init_buf; + /* sizeof RFC1002_SESSION_REQUEST with no scope */ + smb_buf->smb_buf_length = 0x81000044; + rc = smb_send(*csocket, smb_buf, 0x44, + (struct sockaddr *)psin_server); + kfree(ses_init_buf); + } + /* else the negprot may still work without this + even though malloc failed */ + + } + + return rc; +} + +static int +ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) +{ + int rc = 0; + int connected = 0; + + if(*csocket == NULL) { + rc = sock_create(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket); + if (rc < 0) { + cERROR(1, ("Error %d creating ipv6 socket",rc)); + *csocket = NULL; + return rc; + } else { + /* BB other socket options to set KEEPALIVE, NODELAY? */ + cFYI(1,("ipv6 Socket created")); + (*csocket)->sk->allocation = GFP_NOFS; + } + } + + psin_server->sin6_family = AF_INET6; + + if(psin_server->sin6_port) { /* user overrode default port */ + rc = (*csocket)->ops->connect(*csocket, + (struct sockaddr *) psin_server, + sizeof (struct sockaddr_in6),0); + if (rc >= 0) + connected = 1; + } + + if(!connected) { + /* do not retry on the same port we just failed on */ + if(psin_server->sin6_port != htons(CIFS_PORT)) { + psin_server->sin6_port = htons(CIFS_PORT); + + rc = (*csocket)->ops->connect(*csocket, + (struct sockaddr *) psin_server, + sizeof (struct sockaddr_in6),0); + if (rc >= 0) + connected = 1; + } + } + if (!connected) { + psin_server->sin6_port = htons(RFC1001_PORT); + rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) + psin_server, sizeof (struct sockaddr_in6),0); + if (rc >= 0) + connected = 1; + } + + /* give up here - unless we want to retry on different + protocol families some day */ + if (!connected) { + cFYI(1,("Error %d connecting to server via ipv6",rc)); + sock_release(*csocket); + *csocket = NULL; + return rc; + } + /* Eventually check for other socket options to change from + the default. sock_setsockopt not used because it expects + user space buffer */ + (*csocket)->sk->rcvtimeo = 7 * HZ; + + return rc; +} + +int +cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, + char *mount_data, const char *devname) +{ + int rc = 0; + int xid; + struct socket *csocket = NULL; + struct sockaddr_in sin_server; + struct sockaddr_in6 sin_server6; + struct smb_vol volume_info; + struct cifsSesInfo *pSesInfo = NULL; + struct cifsSesInfo *existingCifsSes = NULL; + struct cifsTconInfo *tcon = NULL; + struct TCP_Server_Info *srvTcp = NULL; + + xid = GetXid(); + + cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); /* BB removeme BB fixme */ + + memset(&volume_info,0,sizeof(struct smb_vol)); + if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); + FreeXid(xid); + return -EINVAL; + } + + if (volume_info.username) { + cFYI(1, ("Username: %s ", volume_info.username)); + + } else { + cifserror("No username specified "); + /* In userspace mount helper we can get user name from alternate + locations such as env variables and files on disk */ + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); + FreeXid(xid); + return -EINVAL; + } + + if (volume_info.UNCip && volume_info.UNC) { + rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr); + + if(rc == 0) { + /* not ipv4 address, try ipv6 */ + rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u); + } + + if(rc != 1) { + /* we failed translating address */ + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); + FreeXid(xid); + return -EINVAL; + } + + cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip)); + /* success */ + rc = 0; + } else if (volume_info.UNCip){ + /* BB using ip addr as server name connect to the DFS root below */ + cERROR(1,("Connecting to DFS root not implemented yet")); + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); + FreeXid(xid); + return -EINVAL; + } else /* which servers DFS root would we conect to */ { + cERROR(1, + ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified ")); + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); + FreeXid(xid); + return -EINVAL; + } + + /* this is needed for ASCII cp to Unicode converts */ + if(volume_info.iocharset == NULL) { + cifs_sb->local_nls = load_nls_default(); + /* load_nls_default can not return null */ + } else { + cifs_sb->local_nls = load_nls(volume_info.iocharset); + if(cifs_sb->local_nls == NULL) { + cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset)); + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); + FreeXid(xid); + return -ELIBACC; + } + } + + existingCifsSes = + cifs_find_tcp_session(sin_server.sin_addr.s_addr, + volume_info.username, &srvTcp); + if (srvTcp) { + cFYI(1, ("Existing tcp session with server found ")); + } else { /* create socket */ + if(volume_info.port) + sin_server.sin_port = htons(volume_info.port); + else + sin_server.sin_port = 0; + rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name); + if (rc < 0) { + cERROR(1, + ("Error connecting to IPv4 socket. Aborting operation")); + if(csocket != NULL) + sock_release(csocket); + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); + FreeXid(xid); + return rc; + } + + srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL); + if (srvTcp == NULL) { + rc = -ENOMEM; + sock_release(csocket); + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); + FreeXid(xid); + return rc; + } else { + memset(srvTcp, 0, sizeof (struct TCP_Server_Info)); + memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in)); + atomic_set(&srvTcp->inFlight,0); + /* BB Add code for ipv6 case too */ + srvTcp->ssocket = csocket; + srvTcp->protocolType = IPV4; + init_waitqueue_head(&srvTcp->response_q); + init_waitqueue_head(&srvTcp->request_q); + INIT_LIST_HEAD(&srvTcp->pending_mid_q); + /* at this point we are the only ones with the pointer + to the struct since the kernel thread not created yet + so no need to spinlock this init of tcpStatus */ + srvTcp->tcpStatus = CifsNew; + init_MUTEX(&srvTcp->tcpSem); + kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp, + CLONE_FS | CLONE_FILES | CLONE_VM); + memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16); + } + } + + if (existingCifsSes) { + pSesInfo = existingCifsSes; + cFYI(1, ("Existing smb sess found ")); + if(volume_info.password) + kfree(volume_info.password); + /* volume_info.UNC freed at end of function */ + } else if (!rc) { + cFYI(1, ("Existing smb sess not found ")); + pSesInfo = sesInfoAlloc(); + if (pSesInfo == NULL) + rc = -ENOMEM; + else { + pSesInfo->server = srvTcp; + sprintf(pSesInfo->serverName, "%u.%u.%u.%u", + NIPQUAD(sin_server.sin_addr.s_addr)); + } + + if (!rc){ + /* volume_info.password freed at unmount */ + if (volume_info.password) + pSesInfo->password = volume_info.password; + if (volume_info.username) + strncpy(pSesInfo->userName, + volume_info.username,MAX_USERNAME_SIZE); + if (volume_info.domainname) + strncpy(pSesInfo->domainName, + volume_info.domainname,MAX_USERNAME_SIZE); + pSesInfo->linux_uid = volume_info.linux_uid; + down(&pSesInfo->sesSem); + rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls); + up(&pSesInfo->sesSem); + if(!rc) + atomic_inc(&srvTcp->socketUseCount); + } else + if(volume_info.password) + kfree(volume_info.password); + } + + /* search for existing tcon to this server share */ + if (!rc) { + if((volume_info.rsize) && (volume_info.rsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf)) + cifs_sb->rsize = volume_info.rsize; + else + cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */ + if((volume_info.wsize) && (volume_info.wsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf)) + cifs_sb->wsize = volume_info.wsize; + else + cifs_sb->wsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */ + if(cifs_sb->rsize < PAGE_CACHE_SIZE) { + cifs_sb->rsize = PAGE_CACHE_SIZE; + cERROR(1,("Attempt to set readsize for mount to less than one page (4096)")); + } + cifs_sb->mnt_uid = volume_info.linux_uid; + cifs_sb->mnt_gid = volume_info.linux_gid; + cifs_sb->mnt_file_mode = volume_info.file_mode; + cifs_sb->mnt_dir_mode = volume_info.dir_mode; + cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode)); + tcon = + find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, + volume_info.username); + if (tcon) { + cFYI(1, ("Found match on UNC path ")); + /* we can have only one retry value for a connection + to a share so for resources mounted more than once + to the same server share the last value passed in + for the retry flag is used */ + tcon->retry = volume_info.retry; + } else { + tcon = tconInfoAlloc(); + if (tcon == NULL) + rc = -ENOMEM; + else { + /* check for null share name ie connect to dfs root */ + + /* BB check if this works for exactly length three strings */ + if ((strchr(volume_info.UNC + 3, '\\') == NULL) + && (strchr(volume_info.UNC + 3, '/') == + NULL)) { + rc = connect_to_dfs_path(xid, + pSesInfo, + "", + cifs_sb-> + local_nls); + if(volume_info.UNC) + kfree(volume_info.UNC); + FreeXid(xid); + return -ENODEV; + } else { + rc = CIFSTCon(xid, pSesInfo, + volume_info.UNC, + tcon, cifs_sb->local_nls); + cFYI(1, ("CIFS Tcon rc = %d", rc)); + } + if (!rc) { + atomic_inc(&pSesInfo->inUse); + tcon->retry = volume_info.retry; + } + } + } + } + if(pSesInfo) { + if (pSesInfo->capabilities & CAP_LARGE_FILES) { + sb->s_maxbytes = (u64) 1 << 63; + } else + sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */ + } + +/* on error free sesinfo and tcon struct if needed */ + if (rc) { + /* if session setup failed, use count is zero but + we still need to free cifsd thread */ + if(atomic_read(&srvTcp->socketUseCount) == 0) { + spin_lock(&GlobalMid_Lock); + srvTcp->tcpStatus = CifsExiting; + spin_unlock(&GlobalMid_Lock); + if(srvTcp->tsk) + send_sig(SIGKILL,srvTcp->tsk,1); + } + /* If find_unc succeeded then rc == 0 so we can not end */ + if (tcon) /* up accidently freeing someone elses tcon struct */ + tconInfoFree(tcon); + if (existingCifsSes == 0) { + if (pSesInfo) { + if ((pSesInfo->server) && + (pSesInfo->status == CifsGood)) { + int temp_rc; + temp_rc = CIFSSMBLogoff(xid, pSesInfo); + /* if the socketUseCount is now zero */ + if((temp_rc == -ESHUTDOWN) && + (pSesInfo->server->tsk)) + send_sig(SIGKILL,pSesInfo->server->tsk,1); + } else + cFYI(1, ("No session or bad tcon")); + sesInfoFree(pSesInfo); + /* pSesInfo = NULL; */ + } + } + } else { + atomic_inc(&tcon->useCount); + cifs_sb->tcon = tcon; + tcon->ses = pSesInfo; + + /* do not care if following two calls succeed - informational only */ + CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls); + CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls); + if (tcon->ses->capabilities & CAP_UNIX) + CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls); + } + + /* volume_info.password is freed above when existing session found + (in which case it is not needed anymore) but when new sesion is created + the password ptr is put in the new session structure (in which case the + password will be freed at unmount time) */ + if(volume_info.UNC) + kfree(volume_info.UNC); + FreeXid(xid); + return rc; +} + +static int +CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, + char session_key[CIFS_SESSION_KEY_SIZE], + const struct nls_table *nls_codepage) +{ + struct smb_hdr *smb_buffer; + struct smb_hdr *smb_buffer_response; + SESSION_SETUP_ANDX *pSMB; + SESSION_SETUP_ANDX *pSMBr; + char *bcc_ptr; + char *user = ses->userName; + char *domain = ses->domainName; + int rc = 0; + int remaining_words = 0; + int bytes_returned = 0; + int len; + + cFYI(1, ("In sesssetup ")); + + smb_buffer = cifs_buf_get(); + if (smb_buffer == 0) { + return -ENOMEM; + } + smb_buffer_response = smb_buffer; + pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; + + /* send SMBsessionSetup here */ + header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, + NULL /* no tCon exists yet */ , 13 /* wct */ ); + + pSMB->req_no_secext.AndXCommand = 0xFF; + pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); + pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq); + + if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + + pSMB->req_no_secext.Capabilities = + CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS; + if (ses->capabilities & CAP_UNICODE) { + smb_buffer->Flags2 |= SMBFLG2_UNICODE; + pSMB->req_no_secext.Capabilities |= CAP_UNICODE; + } + if (ses->capabilities & CAP_STATUS32) { + smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; + pSMB->req_no_secext.Capabilities |= CAP_STATUS32; + } + if (ses->capabilities & CAP_DFS) { + smb_buffer->Flags2 |= SMBFLG2_DFS; + pSMB->req_no_secext.Capabilities |= CAP_DFS; + } + pSMB->req_no_secext.Capabilities = + cpu_to_le32(pSMB->req_no_secext.Capabilities); + /* pSMB->req_no_secext.CaseInsensitivePasswordLength = + CIFS_SESSION_KEY_SIZE; */ + pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; + pSMB->req_no_secext.CaseSensitivePasswordLength = + cpu_to_le16(CIFS_SESSION_KEY_SIZE); + bcc_ptr = pByteArea(smb_buffer); + /* memcpy(bcc_ptr, (char *) lm_session_key, CIFS_SESSION_KEY_SIZE); + bcc_ptr += CIFS_SESSION_KEY_SIZE; */ + memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); + bcc_ptr += CIFS_SESSION_KEY_SIZE; + + if (ses->capabilities & CAP_UNICODE) { + if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */ + *bcc_ptr = 0; + bcc_ptr++; + } + if(user == NULL) + bytes_returned = 0; /* skill null user */ + else + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, + nls_codepage); + bcc_ptr += 2 * bytes_returned; /* convert num 16 bit words to bytes */ + bcc_ptr += 2; /* trailing null */ + if (domain == NULL) + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, + "CIFS_LINUX_DOM", 32, nls_codepage); + else + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, + nls_codepage); + bcc_ptr += 2 * bytes_returned; + bcc_ptr += 2; + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", + 32, nls_codepage); + bcc_ptr += 2 * bytes_returned; + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32, + nls_codepage); + bcc_ptr += 2 * bytes_returned; + bcc_ptr += 2; + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, + 64, nls_codepage); + bcc_ptr += 2 * bytes_returned; + bcc_ptr += 2; + } else { + if(user != NULL) { + strncpy(bcc_ptr, user, 200); + bcc_ptr += strnlen(user, 200); + } + *bcc_ptr = 0; + bcc_ptr++; + if (domain == NULL) { + strcpy(bcc_ptr, "CIFS_LINUX_DOM"); + bcc_ptr += strlen("CIFS_LINUX_DOM") + 1; + } else { + strncpy(bcc_ptr, domain, 64); + bcc_ptr += strnlen(domain, 64); + *bcc_ptr = 0; + bcc_ptr++; + } + strcpy(bcc_ptr, "Linux version "); + bcc_ptr += strlen("Linux version "); + strcpy(bcc_ptr, UTS_RELEASE); + bcc_ptr += strlen(UTS_RELEASE) + 1; + strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); + bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; + } + BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer); + smb_buffer->smb_buf_length += BCC(smb_buffer); + BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer)); + + rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, + &bytes_returned, 1); + if (rc) { +/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */ + } else if ((smb_buffer_response->WordCount == 3) + || (smb_buffer_response->WordCount == 4)) { + pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action); + if (pSMBr->resp.Action & GUEST_LOGIN) + cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */ + if (ses) { + ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */ + cFYI(1, ("UID = %d ", ses->Suid)); + /* response can have either 3 or 4 word count - Samba sends 3 */ + bcc_ptr = pByteArea(smb_buffer_response); + if ((pSMBr->resp.hdr.WordCount == 3) + || ((pSMBr->resp.hdr.WordCount == 4) + && (pSMBr->resp.SecurityBlobLength < + pSMBr->resp.ByteCount))) { + if (pSMBr->resp.hdr.WordCount == 4) + bcc_ptr += + pSMBr->resp.SecurityBlobLength; + + if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { + if ((long) (bcc_ptr) % 2) { + remaining_words = + (BCC(smb_buffer_response) + - 1) / 2; + bcc_ptr++; /* Unicode strings must be word aligned */ + } else { + remaining_words = + BCC + (smb_buffer_response) / 2; + } + len = + UniStrnlen((wchar_t *) bcc_ptr, + remaining_words - 1); +/* We look for obvious messed up bcc or strings in response so we do not go off + the end since (at least) WIN2K and Windows XP have a major bug in not null + terminating last Unicode string in response */ + ses->serverOS = cifs_kcalloc(2 * (len + 1), GFP_KERNEL); + cifs_strfromUCS_le(ses->serverOS, + (wchar_t *)bcc_ptr, len,nls_codepage); + bcc_ptr += 2 * (len + 1); + remaining_words -= len + 1; + ses->serverOS[2 * len] = 0; + ses->serverOS[1 + (2 * len)] = 0; + if (remaining_words > 0) { + len = UniStrnlen((wchar_t *)bcc_ptr, + remaining_words + - 1); + ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL); + cifs_strfromUCS_le(ses->serverNOS, + (wchar_t *)bcc_ptr,len,nls_codepage); + bcc_ptr += 2 * (len + 1); + ses->serverNOS[2 * len] = 0; + ses->serverNOS[1 + (2 * len)] = 0; + remaining_words -= len + 1; + if (remaining_words > 0) { + len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); + /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ + ses->serverDomain = + cifs_kcalloc(2*(len+1),GFP_KERNEL); + cifs_strfromUCS_le(ses->serverDomain, + (wchar_t *)bcc_ptr,len,nls_codepage); + bcc_ptr += 2 * (len + 1); + ses->serverDomain[2*len] = 0; + ses->serverDomain[1+(2*len)] = 0; + } /* else no more room so create dummy domain string */ + else + ses->serverDomain = + cifs_kcalloc(2, + GFP_KERNEL); + } else { /* no room so create dummy domain and NOS string */ + ses->serverDomain = + cifs_kcalloc(2, GFP_KERNEL); + ses->serverNOS = + cifs_kcalloc(2, GFP_KERNEL); + } + } else { /* ASCII */ + len = strnlen(bcc_ptr, 1024); + if (((long) bcc_ptr + len) - (long) + pByteArea(smb_buffer_response) + <= BCC(smb_buffer_response)) { + ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL); + strncpy(ses->serverOS,bcc_ptr, len); + + bcc_ptr += len; + bcc_ptr[0] = 0; /* null terminate the string */ + bcc_ptr++; + + len = strnlen(bcc_ptr, 1024); + ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL); + strncpy(ses->serverNOS, bcc_ptr, len); + bcc_ptr += len; + bcc_ptr[0] = 0; + bcc_ptr++; + + len = strnlen(bcc_ptr, 1024); + ses->serverDomain = cifs_kcalloc(len + 1,GFP_KERNEL); + strncpy(ses->serverDomain, bcc_ptr, len); + bcc_ptr += len; + bcc_ptr[0] = 0; + bcc_ptr++; + } else + cFYI(1, + ("Variable field of length %d extends beyond end of smb ", + len)); + } + } else { + cERROR(1, + (" Security Blob Length extends beyond end of SMB")); + } + } else { + cERROR(1, ("No session structure passed in.")); + } + } else { + cERROR(1, + (" Invalid Word count %d: ", + smb_buffer_response->WordCount)); + rc = -EIO; + } + + if (smb_buffer) + cifs_buf_release(smb_buffer); + + return rc; +} + +static int +CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, + char *SecurityBlob,int SecurityBlobLength, + const struct nls_table *nls_codepage) +{ + struct smb_hdr *smb_buffer; + struct smb_hdr *smb_buffer_response; + SESSION_SETUP_ANDX *pSMB; + SESSION_SETUP_ANDX *pSMBr; + char *bcc_ptr; + char *user = ses->userName; + char *domain = ses->domainName; + int rc = 0; + int remaining_words = 0; + int bytes_returned = 0; + int len; + + cFYI(1, ("In spnego sesssetup ")); + + smb_buffer = cifs_buf_get(); + if (smb_buffer == 0) { + return -ENOMEM; + } + smb_buffer_response = smb_buffer; + pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; + + /* send SMBsessionSetup here */ + header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, + NULL /* no tCon exists yet */ , 12 /* wct */ ); + pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; + pSMB->req.AndXCommand = 0xFF; + pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); + pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); + + if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + + pSMB->req.Capabilities = + CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | + CAP_EXTENDED_SECURITY; + if (ses->capabilities & CAP_UNICODE) { + smb_buffer->Flags2 |= SMBFLG2_UNICODE; + pSMB->req.Capabilities |= CAP_UNICODE; + } + if (ses->capabilities & CAP_STATUS32) { + smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; + pSMB->req.Capabilities |= CAP_STATUS32; + } + if (ses->capabilities & CAP_DFS) { + smb_buffer->Flags2 |= SMBFLG2_DFS; + pSMB->req.Capabilities |= CAP_DFS; + } + pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities); + + pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); + bcc_ptr = pByteArea(smb_buffer); + memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength); + bcc_ptr += SecurityBlobLength; + + if (ses->capabilities & CAP_UNICODE) { + if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */ + *bcc_ptr = 0; + bcc_ptr++; + } + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage); + bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */ + bcc_ptr += 2; /* trailing null */ + if (domain == NULL) + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, + "CIFS_LINUX_DOM", 32, nls_codepage); + else + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, + nls_codepage); + bcc_ptr += 2 * bytes_returned; + bcc_ptr += 2; + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", + 32, nls_codepage); + bcc_ptr += 2 * bytes_returned; + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32, + nls_codepage); + bcc_ptr += 2 * bytes_returned; + bcc_ptr += 2; + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, + 64, nls_codepage); + bcc_ptr += 2 * bytes_returned; + bcc_ptr += 2; + } else { + strncpy(bcc_ptr, user, 200); + bcc_ptr += strnlen(user, 200); + *bcc_ptr = 0; + bcc_ptr++; + if (domain == NULL) { + strcpy(bcc_ptr, "CIFS_LINUX_DOM"); + bcc_ptr += strlen("CIFS_LINUX_DOM") + 1; + } else { + strncpy(bcc_ptr, domain, 64); + bcc_ptr += strnlen(domain, 64); + *bcc_ptr = 0; + bcc_ptr++; + } + strcpy(bcc_ptr, "Linux version "); + bcc_ptr += strlen("Linux version "); + strcpy(bcc_ptr, UTS_RELEASE); + bcc_ptr += strlen(UTS_RELEASE) + 1; + strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); + bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; + } + BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer); + smb_buffer->smb_buf_length += BCC(smb_buffer); + BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer)); + + rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, + &bytes_returned, 1); + if (rc) { +/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ + } else if ((smb_buffer_response->WordCount == 3) + || (smb_buffer_response->WordCount == 4)) { + pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action); + pSMBr->resp.SecurityBlobLength = + le16_to_cpu(pSMBr->resp.SecurityBlobLength); + if (pSMBr->resp.Action & GUEST_LOGIN) + cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */ + if (ses) { + ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */ + cFYI(1, ("UID = %d ", ses->Suid)); + bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */ + + /* BB Fix below to make endian neutral !! */ + + if ((pSMBr->resp.hdr.WordCount == 3) + || ((pSMBr->resp.hdr.WordCount == 4) + && (pSMBr->resp.SecurityBlobLength < + pSMBr->resp.ByteCount))) { + if (pSMBr->resp.hdr.WordCount == 4) { + bcc_ptr += + pSMBr->resp.SecurityBlobLength; + cFYI(1, + ("Security Blob Length %d ", + pSMBr->resp.SecurityBlobLength)); + } + + if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { + if ((long) (bcc_ptr) % 2) { + remaining_words = + (BCC(smb_buffer_response) + - 1) / 2; + bcc_ptr++; /* Unicode strings must be word aligned */ + } else { + remaining_words = + BCC + (smb_buffer_response) / 2; + } + len = + UniStrnlen((wchar_t *) bcc_ptr, + remaining_words - 1); +/* We look for obvious messed up bcc or strings in response so we do not go off + the end since (at least) WIN2K and Windows XP have a major bug in not null + terminating last Unicode string in response */ + ses->serverOS = + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); + cifs_strfromUCS_le(ses->serverOS, + (wchar_t *) + bcc_ptr, len, + nls_codepage); + bcc_ptr += 2 * (len + 1); + remaining_words -= len + 1; + ses->serverOS[2 * len] = 0; + ses->serverOS[1 + (2 * len)] = 0; + if (remaining_words > 0) { + len = UniStrnlen((wchar_t *)bcc_ptr, + remaining_words + - 1); + ses->serverNOS = + cifs_kcalloc(2 * (len + 1), + GFP_KERNEL); + cifs_strfromUCS_le(ses->serverNOS, + (wchar_t *)bcc_ptr, + len, + nls_codepage); + bcc_ptr += 2 * (len + 1); + ses->serverNOS[2 * len] = 0; + ses->serverNOS[1 + (2 * len)] = 0; + remaining_words -= len + 1; + if (remaining_words > 0) { + len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); + /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ + ses->serverDomain = cifs_kcalloc(2*(len+1),GFP_KERNEL); + cifs_strfromUCS_le(ses->serverDomain, + (wchar_t *)bcc_ptr, + len, + nls_codepage); + bcc_ptr += 2*(len+1); + ses->serverDomain[2*len] = 0; + ses->serverDomain[1+(2*len)] = 0; + } /* else no more room so create dummy domain string */ + else + ses->serverDomain = + cifs_kcalloc(2,GFP_KERNEL); + } else { /* no room so create dummy domain and NOS string */ + ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL); + ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL); + } + } else { /* ASCII */ + + len = strnlen(bcc_ptr, 1024); + if (((long) bcc_ptr + len) - (long) + pByteArea(smb_buffer_response) + <= BCC(smb_buffer_response)) { + ses->serverOS = cifs_kcalloc(len + 1, GFP_KERNEL); + strncpy(ses->serverOS, bcc_ptr, len); + + bcc_ptr += len; + bcc_ptr[0] = 0; /* null terminate the string */ + bcc_ptr++; + + len = strnlen(bcc_ptr, 1024); + ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL); + strncpy(ses->serverNOS, bcc_ptr, len); + bcc_ptr += len; + bcc_ptr[0] = 0; + bcc_ptr++; + + len = strnlen(bcc_ptr, 1024); + ses->serverDomain = cifs_kcalloc(len + 1, GFP_KERNEL); + strncpy(ses->serverDomain, bcc_ptr, len); + bcc_ptr += len; + bcc_ptr[0] = 0; + bcc_ptr++; + } else + cFYI(1, + ("Variable field of length %d extends beyond end of smb ", + len)); + } + } else { + cERROR(1, + (" Security Blob Length extends beyond end of SMB")); + } + } else { + cERROR(1, ("No session structure passed in.")); + } + } else { + cERROR(1, + (" Invalid Word count %d: ", + smb_buffer_response->WordCount)); + rc = -EIO; + } + + if (smb_buffer) + cifs_buf_release(smb_buffer); + + return rc; +} + +static int +CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, + struct cifsSesInfo *ses, int * pNTLMv2_flag, + const struct nls_table *nls_codepage) +{ + struct smb_hdr *smb_buffer; + struct smb_hdr *smb_buffer_response; + SESSION_SETUP_ANDX *pSMB; + SESSION_SETUP_ANDX *pSMBr; + char *bcc_ptr; + char *domain = ses->domainName; + int rc = 0; + int remaining_words = 0; + int bytes_returned = 0; + int len; + int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE); + PNEGOTIATE_MESSAGE SecurityBlob; + PCHALLENGE_MESSAGE SecurityBlob2; + + cFYI(1, ("In NTLMSSP sesssetup (negotiate) ")); + *pNTLMv2_flag = FALSE; + smb_buffer = cifs_buf_get(); + if (smb_buffer == 0) { + return -ENOMEM; + } + smb_buffer_response = smb_buffer; + pSMB = (SESSION_SETUP_ANDX *) smb_buffer; + pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response; + + /* send SMBsessionSetup here */ + header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, + NULL /* no tCon exists yet */ , 12 /* wct */ ); + pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; + pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); + + pSMB->req.AndXCommand = 0xFF; + pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); + pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); + + if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + + pSMB->req.Capabilities = + CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | + CAP_EXTENDED_SECURITY; + if (ses->capabilities & CAP_UNICODE) { + smb_buffer->Flags2 |= SMBFLG2_UNICODE; + pSMB->req.Capabilities |= CAP_UNICODE; + } + if (ses->capabilities & CAP_STATUS32) { + smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; + pSMB->req.Capabilities |= CAP_STATUS32; + } + if (ses->capabilities & CAP_DFS) { + smb_buffer->Flags2 |= SMBFLG2_DFS; + pSMB->req.Capabilities |= CAP_DFS; + } + pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities); + + bcc_ptr = (char *) &pSMB->req.SecurityBlob; + SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr; + strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); + SecurityBlob->MessageType = NtLmNegotiate; + SecurityBlob->NegotiateFlags = + NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM | + NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 | + /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128; + if(sign_CIFS_PDUs) + SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN; + if(ntlmv2_support) + SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2; + /* setup pointers to domain name and workstation name */ + bcc_ptr += SecurityBlobLength; + + SecurityBlob->WorkstationName.Buffer = 0; + SecurityBlob->WorkstationName.Length = 0; + SecurityBlob->WorkstationName.MaximumLength = 0; + + if (domain == NULL) { + SecurityBlob->DomainName.Buffer = 0; + SecurityBlob->DomainName.Length = 0; + SecurityBlob->DomainName.MaximumLength = 0; + } else { + SecurityBlob->NegotiateFlags |= + NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; + strncpy(bcc_ptr, domain, 63); + SecurityBlob->DomainName.Length = strnlen(domain, 64); + SecurityBlob->DomainName.MaximumLength = + cpu_to_le16(SecurityBlob->DomainName.Length); + SecurityBlob->DomainName.Buffer = + cpu_to_le32((long) &SecurityBlob-> + DomainString - + (long) &SecurityBlob->Signature); + bcc_ptr += SecurityBlob->DomainName.Length; + SecurityBlobLength += SecurityBlob->DomainName.Length; + SecurityBlob->DomainName.Length = + cpu_to_le16(SecurityBlob->DomainName.Length); + } + if (ses->capabilities & CAP_UNICODE) { + if ((long) bcc_ptr % 2) { + *bcc_ptr = 0; + bcc_ptr++; + } + + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", + 32, nls_codepage); + bcc_ptr += 2 * bytes_returned; + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32, + nls_codepage); + bcc_ptr += 2 * bytes_returned; + bcc_ptr += 2; /* null terminate Linux version */ + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, + 64, nls_codepage); + bcc_ptr += 2 * bytes_returned; + *(bcc_ptr + 1) = 0; + *(bcc_ptr + 2) = 0; + bcc_ptr += 2; /* null terminate network opsys string */ + *(bcc_ptr + 1) = 0; + *(bcc_ptr + 2) = 0; + bcc_ptr += 2; /* null domain */ + } else { /* ASCII */ + strcpy(bcc_ptr, "Linux version "); + bcc_ptr += strlen("Linux version "); + strcpy(bcc_ptr, UTS_RELEASE); + bcc_ptr += strlen(UTS_RELEASE) + 1; + strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); + bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; + bcc_ptr++; /* empty domain field */ + *bcc_ptr = 0; + } + SecurityBlob->NegotiateFlags = + cpu_to_le32(SecurityBlob->NegotiateFlags); + pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); + BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer); + smb_buffer->smb_buf_length += BCC(smb_buffer); + BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer)); + + rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, + &bytes_returned, 1); + + if (smb_buffer_response->Status.CifsError == + (NT_STATUS_MORE_PROCESSING_REQUIRED)) + rc = 0; + + if (rc) { +/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ + } else if ((smb_buffer_response->WordCount == 3) + || (smb_buffer_response->WordCount == 4)) { + pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action); + pSMBr->resp.SecurityBlobLength = + le16_to_cpu(pSMBr->resp.SecurityBlobLength); + if (pSMBr->resp.Action & GUEST_LOGIN) + cFYI(1, (" Guest login")); + /* Do we want to set anything in SesInfo struct when guest login? */ + + bcc_ptr = pByteArea(smb_buffer_response); + /* response can have either 3 or 4 word count - Samba sends 3 */ + + SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr; + if (SecurityBlob2->MessageType != NtLmChallenge) { + cFYI(1, + ("Unexpected NTLMSSP message type received %d", + SecurityBlob2->MessageType)); + } else if (ses) { + ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ + cFYI(1, ("UID = %d ", ses->Suid)); + if ((pSMBr->resp.hdr.WordCount == 3) + || ((pSMBr->resp.hdr.WordCount == 4) + && (pSMBr->resp.SecurityBlobLength < + pSMBr->resp.ByteCount))) { + if (pSMBr->resp.hdr.WordCount == 4) { + bcc_ptr += + pSMBr->resp.SecurityBlobLength; + cFYI(1, + ("Security Blob Length %d ", + pSMBr->resp.SecurityBlobLength)); + } + + cFYI(1, ("NTLMSSP Challenge rcvd ")); + + memcpy(ses->server->cryptKey, + SecurityBlob2->Challenge, + CIFS_CRYPTO_KEY_SIZE); + if(SecurityBlob2->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLMV2) + *pNTLMv2_flag = TRUE; + + if((SecurityBlob2->NegotiateFlags & + NTLMSSP_NEGOTIATE_ALWAYS_SIGN) + || (sign_CIFS_PDUs > 1)) + ses->server->secMode |= + SECMODE_SIGN_REQUIRED; + if ((SecurityBlob2->NegotiateFlags & + NTLMSSP_NEGOTIATE_SIGN) && (sign_CIFS_PDUs)) + ses->server->secMode |= + SECMODE_SIGN_ENABLED; + + if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { + if ((long) (bcc_ptr) % 2) { + remaining_words = + (BCC(smb_buffer_response) + - 1) / 2; + bcc_ptr++; /* Unicode strings must be word aligned */ + } else { + remaining_words = + BCC + (smb_buffer_response) / 2; + } + len = + UniStrnlen((wchar_t *) bcc_ptr, + remaining_words - 1); +/* We look for obvious messed up bcc or strings in response so we do not go off + the end since (at least) WIN2K and Windows XP have a major bug in not null + terminating last Unicode string in response */ + ses->serverOS = + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); + cifs_strfromUCS_le(ses->serverOS, + (wchar_t *) + bcc_ptr, len, + nls_codepage); + bcc_ptr += 2 * (len + 1); + remaining_words -= len + 1; + ses->serverOS[2 * len] = 0; + ses->serverOS[1 + (2 * len)] = 0; + if (remaining_words > 0) { + len = UniStrnlen((wchar_t *) + bcc_ptr, + remaining_words + - 1); + ses->serverNOS = + cifs_kcalloc(2 * (len + 1), + GFP_KERNEL); + cifs_strfromUCS_le(ses-> + serverNOS, + (wchar_t *) + bcc_ptr, + len, + nls_codepage); + bcc_ptr += 2 * (len + 1); + ses->serverNOS[2 * len] = 0; + ses->serverNOS[1 + + (2 * len)] = 0; + remaining_words -= len + 1; + if (remaining_words > 0) { + len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); + /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ + ses->serverDomain = + cifs_kcalloc(2 * + (len + + 1), + GFP_KERNEL); + cifs_strfromUCS_le + (ses-> + serverDomain, + (wchar_t *) + bcc_ptr, len, + nls_codepage); + bcc_ptr += + 2 * (len + 1); + ses-> + serverDomain[2 + * len] + = 0; + ses-> + serverDomain[1 + + + (2 + * + len)] + = 0; + } /* else no more room so create dummy domain string */ + else + ses->serverDomain = + cifs_kcalloc(2, + GFP_KERNEL); + } else { /* no room so create dummy domain and NOS string */ + ses->serverDomain = + cifs_kcalloc(2, GFP_KERNEL); + ses->serverNOS = + cifs_kcalloc(2, GFP_KERNEL); + } + } else { /* ASCII */ + len = strnlen(bcc_ptr, 1024); + if (((long) bcc_ptr + len) - (long) + pByteArea(smb_buffer_response) + <= BCC(smb_buffer_response)) { + ses->serverOS = + cifs_kcalloc(len + 1, + GFP_KERNEL); + strncpy(ses->serverOS, + bcc_ptr, len); + + bcc_ptr += len; + bcc_ptr[0] = 0; /* null terminate string */ + bcc_ptr++; + + len = strnlen(bcc_ptr, 1024); + ses->serverNOS = + cifs_kcalloc(len + 1, + GFP_KERNEL); + strncpy(ses->serverNOS, bcc_ptr, len); + bcc_ptr += len; + bcc_ptr[0] = 0; + bcc_ptr++; + + len = strnlen(bcc_ptr, 1024); + ses->serverDomain = + cifs_kcalloc(len + 1, + GFP_KERNEL); + strncpy(ses->serverDomain, bcc_ptr, len); + bcc_ptr += len; + bcc_ptr[0] = 0; + bcc_ptr++; + } else + cFYI(1, + ("Variable field of length %d extends beyond end of smb ", + len)); + } + } else { + cERROR(1, + (" Security Blob Length extends beyond end of SMB")); + } + } else { + cERROR(1, ("No session structure passed in.")); + } + } else { + cERROR(1, + (" Invalid Word count %d: ", + smb_buffer_response->WordCount)); + rc = -EIO; + } + + if (smb_buffer) + cifs_buf_release(smb_buffer); + + return rc; +} + +static int +CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, + char *ntlm_session_key, int ntlmv2_flag, + const struct nls_table *nls_codepage) +{ + struct smb_hdr *smb_buffer; + struct smb_hdr *smb_buffer_response; + SESSION_SETUP_ANDX *pSMB; + SESSION_SETUP_ANDX *pSMBr; + char *bcc_ptr; + char *user = ses->userName; + char *domain = ses->domainName; + int rc = 0; + int remaining_words = 0; + int bytes_returned = 0; + int len; + int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE); + PAUTHENTICATE_MESSAGE SecurityBlob; + + cFYI(1, ("In NTLMSSPSessSetup (Authenticate)")); + + smb_buffer = cifs_buf_get(); + if (smb_buffer == 0) { + return -ENOMEM; + } + smb_buffer_response = smb_buffer; + pSMB = (SESSION_SETUP_ANDX *) smb_buffer; + pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response; + + /* send SMBsessionSetup here */ + header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, + NULL /* no tCon exists yet */ , 12 /* wct */ ); + pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); + pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; + pSMB->req.AndXCommand = 0xFF; + pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); + pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); + + pSMB->req.hdr.Uid = ses->Suid; + + if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + + pSMB->req.Capabilities = + CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | + CAP_EXTENDED_SECURITY; + if (ses->capabilities & CAP_UNICODE) { + smb_buffer->Flags2 |= SMBFLG2_UNICODE; + pSMB->req.Capabilities |= CAP_UNICODE; + } + if (ses->capabilities & CAP_STATUS32) { + smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; + pSMB->req.Capabilities |= CAP_STATUS32; + } + if (ses->capabilities & CAP_DFS) { + smb_buffer->Flags2 |= SMBFLG2_DFS; + pSMB->req.Capabilities |= CAP_DFS; + } + pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities); + + bcc_ptr = (char *) &pSMB->req.SecurityBlob; + SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr; + strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); + SecurityBlob->MessageType = NtLmAuthenticate; + bcc_ptr += SecurityBlobLength; + SecurityBlob->NegotiateFlags = + NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | + NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO | + 0x80000000 | NTLMSSP_NEGOTIATE_128; + if(sign_CIFS_PDUs) + SecurityBlob->NegotiateFlags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN; + if(ntlmv2_flag) + SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2; + +/* setup pointers to domain name and workstation name */ + + SecurityBlob->WorkstationName.Buffer = 0; + SecurityBlob->WorkstationName.Length = 0; + SecurityBlob->WorkstationName.MaximumLength = 0; + SecurityBlob->SessionKey.Length = 0; + SecurityBlob->SessionKey.MaximumLength = 0; + SecurityBlob->SessionKey.Buffer = 0; + + SecurityBlob->LmChallengeResponse.Length = 0; + SecurityBlob->LmChallengeResponse.MaximumLength = 0; + SecurityBlob->LmChallengeResponse.Buffer = 0; + + SecurityBlob->NtChallengeResponse.Length = + cpu_to_le16(CIFS_SESSION_KEY_SIZE); + SecurityBlob->NtChallengeResponse.MaximumLength = + cpu_to_le16(CIFS_SESSION_KEY_SIZE); + memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE); + SecurityBlob->NtChallengeResponse.Buffer = + cpu_to_le32(SecurityBlobLength); + SecurityBlobLength += CIFS_SESSION_KEY_SIZE; + bcc_ptr += CIFS_SESSION_KEY_SIZE; + + if (ses->capabilities & CAP_UNICODE) { + if (domain == NULL) { + SecurityBlob->DomainName.Buffer = 0; + SecurityBlob->DomainName.Length = 0; + SecurityBlob->DomainName.MaximumLength = 0; + } else { + SecurityBlob->DomainName.Length = + cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, + nls_codepage); + SecurityBlob->DomainName.Length *= 2; + SecurityBlob->DomainName.MaximumLength = + cpu_to_le16(SecurityBlob->DomainName.Length); + SecurityBlob->DomainName.Buffer = + cpu_to_le32(SecurityBlobLength); + bcc_ptr += SecurityBlob->DomainName.Length; + SecurityBlobLength += SecurityBlob->DomainName.Length; + SecurityBlob->DomainName.Length = + cpu_to_le16(SecurityBlob->DomainName.Length); + } + if (user == NULL) { + SecurityBlob->UserName.Buffer = 0; + SecurityBlob->UserName.Length = 0; + SecurityBlob->UserName.MaximumLength = 0; + } else { + SecurityBlob->UserName.Length = + cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64, + nls_codepage); + SecurityBlob->UserName.Length *= 2; + SecurityBlob->UserName.MaximumLength = + cpu_to_le16(SecurityBlob->UserName.Length); + SecurityBlob->UserName.Buffer = + cpu_to_le32(SecurityBlobLength); + bcc_ptr += SecurityBlob->UserName.Length; + SecurityBlobLength += SecurityBlob->UserName.Length; + SecurityBlob->UserName.Length = + cpu_to_le16(SecurityBlob->UserName.Length); + } + + /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage); + SecurityBlob->WorkstationName.Length *= 2; + SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length); + SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength); + bcc_ptr += SecurityBlob->WorkstationName.Length; + SecurityBlobLength += SecurityBlob->WorkstationName.Length; + SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */ + + if ((long) bcc_ptr % 2) { + *bcc_ptr = 0; + bcc_ptr++; + } + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", + 32, nls_codepage); + bcc_ptr += 2 * bytes_returned; + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32, + nls_codepage); + bcc_ptr += 2 * bytes_returned; + bcc_ptr += 2; /* null term version string */ + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, + 64, nls_codepage); + bcc_ptr += 2 * bytes_returned; + *(bcc_ptr + 1) = 0; + *(bcc_ptr + 2) = 0; + bcc_ptr += 2; /* null terminate network opsys string */ + *(bcc_ptr + 1) = 0; + *(bcc_ptr + 2) = 0; + bcc_ptr += 2; /* null domain */ + } else { /* ASCII */ + if (domain == NULL) { + SecurityBlob->DomainName.Buffer = 0; + SecurityBlob->DomainName.Length = 0; + SecurityBlob->DomainName.MaximumLength = 0; + } else { + SecurityBlob->NegotiateFlags |= + NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; + strncpy(bcc_ptr, domain, 63); + SecurityBlob->DomainName.Length = strnlen(domain, 64); + SecurityBlob->DomainName.MaximumLength = + cpu_to_le16(SecurityBlob->DomainName.Length); + SecurityBlob->DomainName.Buffer = + cpu_to_le32(SecurityBlobLength); + bcc_ptr += SecurityBlob->DomainName.Length; + SecurityBlobLength += SecurityBlob->DomainName.Length; + SecurityBlob->DomainName.Length = + cpu_to_le16(SecurityBlob->DomainName.Length); + } + if (user == NULL) { + SecurityBlob->UserName.Buffer = 0; + SecurityBlob->UserName.Length = 0; + SecurityBlob->UserName.MaximumLength = 0; + } else { + strncpy(bcc_ptr, user, 63); + SecurityBlob->UserName.Length = strnlen(user, 64); + SecurityBlob->UserName.MaximumLength = + cpu_to_le16(SecurityBlob->UserName.Length); + SecurityBlob->UserName.Buffer = + cpu_to_le32(SecurityBlobLength); + bcc_ptr += SecurityBlob->UserName.Length; + SecurityBlobLength += SecurityBlob->UserName.Length; + SecurityBlob->UserName.Length = + cpu_to_le16(SecurityBlob->UserName.Length); + } + /* BB fill in our workstation name if known BB */ + + strcpy(bcc_ptr, "Linux version "); + bcc_ptr += strlen("Linux version "); + strcpy(bcc_ptr, UTS_RELEASE); + bcc_ptr += strlen(UTS_RELEASE) + 1; + strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); + bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; + bcc_ptr++; /* null domain */ + *bcc_ptr = 0; + } + SecurityBlob->NegotiateFlags = + cpu_to_le32(SecurityBlob->NegotiateFlags); + pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); + BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer); + smb_buffer->smb_buf_length += BCC(smb_buffer); + BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer)); + + rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, + &bytes_returned, 1); + if (rc) { +/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ + } else if ((smb_buffer_response->WordCount == 3) + || (smb_buffer_response->WordCount == 4)) { + pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action); + pSMBr->resp.SecurityBlobLength = + le16_to_cpu(pSMBr->resp.SecurityBlobLength); + if (pSMBr->resp.Action & GUEST_LOGIN) + cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */ +/* if(SecurityBlob2->MessageType != NtLm??){ + cFYI("Unexpected message type on auth response is %d ")); + } */ + if (ses) { + cFYI(1, + ("Does UID on challenge %d match auth response UID %d ", + ses->Suid, smb_buffer_response->Uid)); + ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */ + bcc_ptr = pByteArea(smb_buffer_response); + /* response can have either 3 or 4 word count - Samba sends 3 */ + if ((pSMBr->resp.hdr.WordCount == 3) + || ((pSMBr->resp.hdr.WordCount == 4) + && (pSMBr->resp.SecurityBlobLength < + pSMBr->resp.ByteCount))) { + if (pSMBr->resp.hdr.WordCount == 4) { + bcc_ptr += + pSMBr->resp.SecurityBlobLength; + cFYI(1, + ("Security Blob Length %d ", + pSMBr->resp.SecurityBlobLength)); + } + + cFYI(1, + ("NTLMSSP response to Authenticate ")); + + if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { + if ((long) (bcc_ptr) % 2) { + remaining_words = + (BCC(smb_buffer_response) + - 1) / 2; + bcc_ptr++; /* Unicode strings must be word aligned */ + } else { + remaining_words = BCC(smb_buffer_response) / 2; + } + len = + UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1); +/* We look for obvious messed up bcc or strings in response so we do not go off + the end since (at least) WIN2K and Windows XP have a major bug in not null + terminating last Unicode string in response */ + ses->serverOS = + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); + cifs_strfromUCS_le(ses->serverOS, + (wchar_t *) + bcc_ptr, len, + nls_codepage); + bcc_ptr += 2 * (len + 1); + remaining_words -= len + 1; + ses->serverOS[2 * len] = 0; + ses->serverOS[1 + (2 * len)] = 0; + if (remaining_words > 0) { + len = UniStrnlen((wchar_t *) + bcc_ptr, + remaining_words + - 1); + ses->serverNOS = + cifs_kcalloc(2 * (len + 1), + GFP_KERNEL); + cifs_strfromUCS_le(ses-> + serverNOS, + (wchar_t *) + bcc_ptr, + len, + nls_codepage); + bcc_ptr += 2 * (len + 1); + ses->serverNOS[2 * len] = 0; + ses->serverNOS[1+(2*len)] = 0; + remaining_words -= len + 1; + if (remaining_words > 0) { + len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); + /* last string not always null terminated (e.g. for Windows XP & 2000) */ + ses->serverDomain = + cifs_kcalloc(2 * + (len + + 1), + GFP_KERNEL); + cifs_strfromUCS_le + (ses-> + serverDomain, + (wchar_t *) + bcc_ptr, len, + nls_codepage); + bcc_ptr += + 2 * (len + 1); + ses-> + serverDomain[2 + * len] + = 0; + ses-> + serverDomain[1 + + + (2 + * + len)] + = 0; + } /* else no more room so create dummy domain string */ + else + ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL); + } else { /* no room so create dummy domain and NOS string */ + ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL); + ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL); + } + } else { /* ASCII */ + len = strnlen(bcc_ptr, 1024); + if (((long) bcc_ptr + len) - + (long) pByteArea(smb_buffer_response) + <= BCC(smb_buffer_response)) { + ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL); + strncpy(ses->serverOS,bcc_ptr, len); + + bcc_ptr += len; + bcc_ptr[0] = 0; /* null terminate the string */ + bcc_ptr++; + + len = strnlen(bcc_ptr, 1024); + ses->serverNOS = cifs_kcalloc(len+1,GFP_KERNEL); + strncpy(ses->serverNOS, bcc_ptr, len); + bcc_ptr += len; + bcc_ptr[0] = 0; + bcc_ptr++; + + len = strnlen(bcc_ptr, 1024); + ses->serverDomain = cifs_kcalloc(len+1,GFP_KERNEL); + strncpy(ses->serverDomain, bcc_ptr, len); + bcc_ptr += len; + bcc_ptr[0] = 0; + bcc_ptr++; + } else + cFYI(1, + ("Variable field of length %d extends beyond end of smb ", + len)); + } + } else { + cERROR(1, + (" Security Blob Length extends beyond end of SMB")); + } + } else { + cERROR(1, ("No session structure passed in.")); + } + } else { + cERROR(1, + (" Invalid Word count %d: ", + smb_buffer_response->WordCount)); + rc = -EIO; + } + + if (smb_buffer) + cifs_buf_release(smb_buffer); + + return rc; +} + +int +CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, + const char *tree, struct cifsTconInfo *tcon, + const struct nls_table *nls_codepage) +{ + struct smb_hdr *smb_buffer; + struct smb_hdr *smb_buffer_response; + TCONX_REQ *pSMB; + TCONX_RSP *pSMBr; + char *bcc_ptr; + int rc = 0; + int length; + + if (ses == NULL) + return -EIO; + + smb_buffer = cifs_buf_get(); + if (smb_buffer == 0) { + return -ENOMEM; + } + smb_buffer_response = smb_buffer; + + header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, + NULL /*no tid */ , 4 /*wct */ ); + smb_buffer->Uid = ses->Suid; + pSMB = (TCONX_REQ *) smb_buffer; + pSMBr = (TCONX_RSP *) smb_buffer_response; + + pSMB->AndXCommand = 0xFF; + pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO); + pSMB->PasswordLength = cpu_to_le16(1); /* minimum */ + bcc_ptr = &(pSMB->Password[0]); + bcc_ptr++; /* skip password */ + + if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + + if (ses->capabilities & CAP_STATUS32) { + smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; + } + if (ses->capabilities & CAP_DFS) { + smb_buffer->Flags2 |= SMBFLG2_DFS; + } + if (ses->capabilities & CAP_UNICODE) { + smb_buffer->Flags2 |= SMBFLG2_UNICODE; + length = + cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage); + bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */ + bcc_ptr += 2; /* skip trailing null */ + } else { /* ASCII */ + + strcpy(bcc_ptr, tree); + bcc_ptr += strlen(tree) + 1; + } + strcpy(bcc_ptr, "?????"); + bcc_ptr += strlen("?????"); + bcc_ptr += 1; + BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer); + smb_buffer->smb_buf_length += BCC(smb_buffer); + BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer)); + + rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0); + + /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */ + /* above now done in SendReceive */ + if ((rc == 0) && (tcon != NULL)) { + tcon->tidStatus = CifsGood; + tcon->tid = smb_buffer_response->Tid; + bcc_ptr = pByteArea(smb_buffer_response); + length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2); + /* skip service field (NB: this field is always ASCII) */ + bcc_ptr += length + 1; + strncpy(tcon->treeName, tree, MAX_TREE_SIZE); + if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { + length = UniStrnlen((wchar_t *) bcc_ptr, 512); + if (((long) bcc_ptr + (2 * length)) - + (long) pByteArea(smb_buffer_response) <= + BCC(smb_buffer_response)) { + if(tcon->nativeFileSystem) + kfree(tcon->nativeFileSystem); + tcon->nativeFileSystem = + cifs_kcalloc(length + 2, GFP_KERNEL); + cifs_strfromUCS_le(tcon->nativeFileSystem, + (wchar_t *) bcc_ptr, + length, nls_codepage); + bcc_ptr += 2 * length; + bcc_ptr[0] = 0; /* null terminate the string */ + bcc_ptr[1] = 0; + bcc_ptr += 2; + } + /* else do not bother copying these informational fields */ + } else { + length = strnlen(bcc_ptr, 1024); + if (((long) bcc_ptr + length) - + (long) pByteArea(smb_buffer_response) <= + BCC(smb_buffer_response)) { + if(tcon->nativeFileSystem) + kfree(tcon->nativeFileSystem); + tcon->nativeFileSystem = + cifs_kcalloc(length + 1, GFP_KERNEL); + strncpy(tcon->nativeFileSystem, bcc_ptr, + length); + } + /* else do not bother copying these informational fields */ + } + tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); + cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags)); + } else if ((rc == 0) && tcon == NULL) { + /* all we need to save for IPC$ connection */ + ses->ipc_tid = smb_buffer_response->Tid; + } + + if (smb_buffer) + cifs_buf_release(smb_buffer); + return rc; +} + +int +cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) +{ + int rc = 0; + int xid; + struct cifsSesInfo *ses = NULL; + struct task_struct *cifsd_task; + + xid = GetXid(); + + if (cifs_sb->tcon) { + ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/ + rc = CIFSSMBTDis(xid, cifs_sb->tcon); + if (rc == -EBUSY) { + FreeXid(xid); + return 0; + } + tconInfoFree(cifs_sb->tcon); + if ((ses) && (ses->server)) { + /* save off task so we do not refer to ses later */ + cifsd_task = ses->server->tsk; + cFYI(1, ("About to do SMBLogoff ")); + rc = CIFSSMBLogoff(xid, ses); + if (rc == -EBUSY) { + FreeXid(xid); + return 0; + } else if (rc == -ESHUTDOWN) { + cFYI(1,("Waking up socket by sending it signal")); + send_sig(SIGKILL,cifsd_task,1); + rc = 0; + } /* else - we have an smb session + left on this socket do not kill cifsd */ + } else + cFYI(1, ("No session or bad tcon")); + } + + cifs_sb->tcon = NULL; + if (ses) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 2); + } + if (ses) + sesInfoFree(ses); + + FreeXid(xid); + return rc; /* BB check if we should always return zero here */ +} + +int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, + struct nls_table * nls_info) +{ + int rc = 0; + char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; + int ntlmv2_flag = FALSE; + + /* what if server changes its buffer size after dropping the session? */ + if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ { + rc = CIFSSMBNegotiate(xid, pSesInfo); + if(rc == -EAGAIN) /* retry only once on 1st time connection */ { + rc = CIFSSMBNegotiate(xid, pSesInfo); + if(rc == -EAGAIN) + rc = -EHOSTDOWN; + } + if(rc == 0) { + spin_lock(&GlobalMid_Lock); + if(pSesInfo->server->tcpStatus != CifsExiting) + pSesInfo->server->tcpStatus = CifsGood; + else + rc = -EHOSTDOWN; + spin_unlock(&GlobalMid_Lock); + + } + } + if (!rc) { + pSesInfo->capabilities = pSesInfo->server->capabilities; + if(linuxExtEnabled == 0) + pSesInfo->capabilities &= (~CAP_UNIX); + pSesInfo->sequence_number = 0; + cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d", + pSesInfo->server->secMode, + pSesInfo->server->capabilities, + pSesInfo->server->timeZone)); + if (extended_security + && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) + && (pSesInfo->server->secType == NTLMSSP)) { + cFYI(1, ("New style sesssetup ")); + rc = CIFSSpnegoSessSetup(xid, pSesInfo, + NULL /* security blob */, + 0 /* blob length */, + nls_info); + } else if (extended_security + && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) + && (pSesInfo->server->secType == RawNTLMSSP)) { + cFYI(1, ("NTLMSSP sesssetup ")); + rc = CIFSNTLMSSPNegotiateSessSetup(xid, + pSesInfo, + &ntlmv2_flag, + nls_info); + if (!rc) { + if(ntlmv2_flag) { + char * v2_response; + cFYI(1,("Can use more secure NTLM version 2 password hash")); + CalcNTLMv2_partial_mac_key(pSesInfo, + nls_info); + v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL); + if(v2_response) { + CalcNTLMv2_response(pSesInfo,v2_response); +/* cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */ + kfree(v2_response); + /* BB Put dummy sig in SessSetup PDU? */ + } else + rc = -ENOMEM; + + } else { + SMBNTencrypt(pSesInfo->password, + pSesInfo->server->cryptKey, + ntlm_session_key); + + cifs_calculate_mac_key(pSesInfo->mac_signing_key, + ntlm_session_key, + pSesInfo->password); + } + /* for better security the weaker lanman hash not sent + in AuthSessSetup so we no longer calculate it */ + + rc = CIFSNTLMSSPAuthSessSetup(xid, + pSesInfo, + ntlm_session_key, + ntlmv2_flag, + nls_info); + } + } else { /* old style NTLM 0.12 session setup */ + SMBNTencrypt(pSesInfo->password, + pSesInfo->server->cryptKey, + ntlm_session_key); + + cifs_calculate_mac_key(pSesInfo->mac_signing_key, + ntlm_session_key, pSesInfo->password); + rc = CIFSSessSetup(xid, pSesInfo, + ntlm_session_key, nls_info); + } + if (rc) { + cERROR(1,("Send error in SessSetup = %d",rc)); + } else { + cFYI(1,("CIFS Session Established successfully")); + pSesInfo->status = CifsGood; + } + } + return rc; +} + diff --git a/release/src/linux/linux/fs/cifs/dir.c b/release/src/linux/linux/fs/cifs/dir.c new file mode 100644 index 00000000..123b0a6d --- /dev/null +++ b/release/src/linux/linux/fs/cifs/dir.c @@ -0,0 +1,425 @@ +/* + * fs/cifs/dir.c + * + * vfs operations that deal with dentries + * + * Copyright (C) International Business Machines Corp., 2002,2003 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/fs.h> +#include <linux/stat.h> +#include <linux/slab.h> +#include "cifsfs.h" +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_debug.h" +#include "cifs_fs_sb.h" + +void +renew_parental_timestamps(struct dentry *direntry) +{ + /* BB check if there is a way to get the kernel to do this or if we really need this */ + do { + direntry->d_time = jiffies; + direntry = direntry->d_parent; + } while (!IS_ROOT(direntry)); +} + +/* Note: caller must free return buffer */ +char * +build_path_from_dentry(struct dentry *direntry) +{ + struct dentry *temp; + int namelen = 0; + char *full_path; + + if(direntry == NULL) + return NULL; /* not much we can do if dentry is freed and + we need to reopen the file after it was closed implicitly + when the server crashed */ + +cifs_bp_rename_retry: + for (temp = direntry; !IS_ROOT(temp);) { + namelen += (1 + temp->d_name.len); + temp = temp->d_parent; + if(temp == NULL) { + cERROR(1,("corrupt dentry")); + return NULL; + } + } + + full_path = kmalloc(namelen+1, GFP_KERNEL); + if(full_path == NULL) + return full_path; + full_path[namelen] = 0; /* trailing null */ + + for (temp = direntry; !IS_ROOT(temp);) { + namelen -= 1 + temp->d_name.len; + if (namelen < 0) { + break; + } else { + full_path[namelen] = '\\'; + strncpy(full_path + namelen + 1, temp->d_name.name, + temp->d_name.len); + cFYI(0, (" name: %s ", full_path + namelen)); + } + temp = temp->d_parent; + if(temp == NULL) { + cERROR(1,("corrupt dentry")); + kfree(full_path); + return NULL; + } + } + if (namelen != 0) { + cERROR(1, + ("We did not end path lookup where we expected namelen is %d", + namelen)); + /* presumably this is only possible if we were racing with a rename + of one of the parent directories (we can not lock the dentries + above us to prevent this, but retrying should be harmless) */ + kfree(full_path); + namelen = 0; + goto cifs_bp_rename_retry; + } + + return full_path; +} + +/* Note: caller must free return buffer */ +char * +build_wildcard_path_from_dentry(struct dentry *direntry) +{ + struct dentry *temp; + int namelen = 0; + char *full_path; + + if(direntry == NULL) + return NULL; /* not much we can do if dentry is freed and + we need to reopen the file after it was closed implicitly + when the server crashed */ + +cifs_bwp_rename_retry: + for (temp = direntry; !IS_ROOT(temp);) { + namelen += (1 + temp->d_name.len); + temp = temp->d_parent; + if(temp == NULL) { + cERROR(1,("corrupt dentry")); + return NULL; + } + } + + full_path = kmalloc(namelen+3, GFP_KERNEL); + if(full_path == NULL) + return full_path; + + full_path[namelen] = '\\'; + full_path[namelen+1] = '*'; + full_path[namelen+2] = 0; /* trailing null */ + + for (temp = direntry; !IS_ROOT(temp);) { + namelen -= 1 + temp->d_name.len; + if (namelen < 0) { + break; + } else { + full_path[namelen] = '\\'; + strncpy(full_path + namelen + 1, temp->d_name.name, + temp->d_name.len); + cFYI(0, (" name: %s ", full_path + namelen)); + } + temp = temp->d_parent; + if(temp == NULL) { + cERROR(1,("corrupt dentry")); + kfree(full_path); + return NULL; + } + } + if (namelen != 0) { + cERROR(1, + ("We did not end path lookup where we expected namelen is %d", + namelen)); + /* presumably this is only possible if we were racing with a rename + of one of the parent directories (we can not lock the dentries + above us to prevent this, but retrying should be harmless) */ + kfree(full_path); + namelen = 0; + goto cifs_bwp_rename_retry; + } + + return full_path; +} + +/* Inode operations in similar order to how they appear in the Linux file fs.h */ + +int +cifs_create(struct inode *inode, struct dentry *direntry, int mode) +{ + int rc = -ENOENT; + int xid; + int oplock = 0; /* no sense requested oplock if we are just going to + immediately close the file */ + __u16 fileHandle; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + char *full_path = NULL; + FILE_ALL_INFO * buf = NULL; + struct inode *newinode = NULL; + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + + down(&direntry->d_sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(direntry); + up(&direntry->d_sb->s_vfs_rename_sem); + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + + /* BB add processing to set equivalent of mode - e.g. via CreateX with ACLs */ + + buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); + rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OVERWRITE_IF, + GENERIC_WRITE, CREATE_NOT_DIR, + &fileHandle, &oplock, buf, cifs_sb->local_nls); + if (rc) { + cFYI(1, ("cifs_create returned 0x%x ", rc)); + } else { + /* BB for case of overwriting existing file can we use the inode that was + passed in rather than creating new one?? */ + if (pTcon->ses->capabilities & CAP_UNIX) + rc = cifs_get_inode_info_unix(&newinode, full_path, + inode->i_sb,xid); + else + rc = cifs_get_inode_info(&newinode, full_path, + buf, inode->i_sb,xid); + + if (rc != 0) { + cFYI(1,("Create worked but get_inode_info failed with rc = %d", + rc)); + } else { + direntry->d_op = &cifs_dentry_ops; + d_instantiate(direntry, newinode); + } + CIFSSMBClose(xid, pTcon, fileHandle); + + if(newinode) { + newinode->i_mode = mode; + if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) + CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode, + (__u64)-1, + (__u64)-1, + 0 /* dev */, + cifs_sb->local_nls); + else { /* BB implement via Windows security descriptors */ + /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ + /* in the meantime could set r/o dos attribute when perms are eg: + mode & 0222 == 0 */ + } + } + } + + if (buf) + kfree(buf); + if (full_path) + kfree(full_path); + FreeXid(xid); + + return rc; +} + +int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, int device_number) +{ + int rc = -EPERM; + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + char *full_path = NULL; + struct inode * newinode = NULL; + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + + down(&direntry->d_sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(direntry); + up(&direntry->d_sb->s_vfs_rename_sem); + if(full_path == NULL) + rc = -ENOMEM; + + if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) { + rc = CIFSSMBUnixSetPerms(xid, pTcon, + full_path, mode, current->euid, current->egid, + device_number, cifs_sb->local_nls); + if(!rc) { + rc = cifs_get_inode_info_unix(&newinode, full_path, + inode->i_sb,xid); + direntry->d_op = &cifs_dentry_ops; + if(rc == 0) + d_instantiate(direntry, newinode); + } + } + + if (full_path) + kfree(full_path); + FreeXid(xid); + + return rc; +} + + +struct dentry * +cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry) +{ + int xid; + int rc = 0; /* to get around spurious gcc warning, set to zero here */ + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct inode *newInode = NULL; + char *full_path = NULL; + + xid = GetXid(); + + cFYI(1, + (" parent inode = 0x%p name is: %s and dentry = 0x%p", + parent_dir_inode, direntry->d_name.name, direntry)); + + /* BB Add check of incoming data - e.g. frame not longer than maximum SMB - let server check the namelen BB */ + + /* check whether path exists */ + + cifs_sb = CIFS_SB(parent_dir_inode->i_sb); + pTcon = cifs_sb->tcon; + + /* can not grab the rename sem here since it would + deadlock in the cases (beginning of sys_rename itself) + in which we already have the sb rename sem */ + full_path = build_path_from_dentry(direntry); + if(full_path == NULL) { + FreeXid(xid); + return ERR_PTR(-ENOMEM); + } + + if (direntry->d_inode != NULL) { + cFYI(1, (" non-NULL inode in lookup")); + } else { + cFYI(1, (" NULL inode in lookup")); + } + cFYI(1, + (" Full path: %s inode = 0x%p", full_path, direntry->d_inode)); + + if (pTcon->ses->capabilities & CAP_UNIX) + rc = cifs_get_inode_info_unix(&newInode, full_path, + parent_dir_inode->i_sb,xid); + else + rc = cifs_get_inode_info(&newInode, full_path, NULL, + parent_dir_inode->i_sb,xid); + + if ((rc == 0) && (newInode != NULL)) { + direntry->d_op = &cifs_dentry_ops; + d_add(direntry, newInode); + + /* since paths are not looked up by component - the parent directories are presumed to be good here */ + renew_parental_timestamps(direntry); + + } else if (rc == -ENOENT) { + rc = 0; + d_add(direntry, NULL); + } else { + cERROR(1,("Error 0x%x or on cifs_get_inode_info in lookup",rc)); + /* BB special case check for Access Denied - watch security + exposure of returning dir info implicitly via different rc + if file exists or not but no access BB */ + } + + if (full_path) + kfree(full_path); + FreeXid(xid); + return ERR_PTR(rc); +} + +int +cifs_dir_open(struct inode *inode, struct file *file) +{ /* NB: currently unused since searches are opened in readdir */ + int rc = 0; + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + char *full_path = NULL; + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + + if(file->f_dentry) { + down(&file->f_dentry->d_sb->s_vfs_rename_sem); + full_path = build_wildcard_path_from_dentry(file->f_dentry); + up(&file->f_dentry->d_sb->s_vfs_rename_sem); + } else { + FreeXid(xid); + return -EIO; + } + + cFYI(1, ("inode = 0x%p and full path is %s", inode, full_path)); + + if (full_path) + kfree(full_path); + FreeXid(xid); + return rc; +} + +static int +cifs_d_revalidate(struct dentry *direntry, int flags) +{ + int isValid = 1; + +/* lock_kernel(); *//* surely we do not want to lock the kernel for a whole network round trip which could take seconds */ + + if (direntry->d_inode) { + if (cifs_revalidate(direntry)) { + /* unlock_kernel(); */ + return 0; + } + } else { + cFYI(1, + ("In cifs_d_revalidate with no inode but name = %s and dentry 0x%p", + direntry->d_name.name, direntry)); + } + +/* unlock_kernel(); */ + + return isValid; +} + +/* static int cifs_d_delete(struct dentry *direntry) +{ + int rc = 0; + + cFYI(1, ("In cifs d_delete, name = %s", direntry->d_name.name)); + + return rc; +} */ + +struct dentry_operations cifs_dentry_ops = { + .d_revalidate = cifs_d_revalidate, +/* d_delete: cifs_d_delete, *//* not needed except for debugging */ + /* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */ +}; diff --git a/release/src/linux/linux/fs/cifs/file.c b/release/src/linux/linux/fs/cifs/file.c new file mode 100644 index 00000000..d7f3bac6 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/file.c @@ -0,0 +1,2185 @@ +/* + * fs/cifs/file.c + * + * vfs operations that deal with files + * + * Copyright (C) International Business Machines Corp., 2002,2003 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/fs.h> +#include <linux/stat.h> +#include <linux/fcntl.h> +#include <linux/version.h> +#include <linux/pagemap.h> +#include <linux/smp_lock.h> +#include <linux/list.h> +#include <asm/div64.h> +#include <linux/mm.h> +#include <linux/types.h> +#include "cifsfs.h" +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_unicode.h" +#include "cifs_debug.h" +#include "cifs_fs_sb.h" + +int +cifs_open(struct inode *inode, struct file *file) +{ + int rc = -EACCES; + int xid, oplock; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct cifsFileInfo *pCifsFile; + struct cifsInodeInfo *pCifsInode; + char *full_path = NULL; + int desiredAccess = 0x20197; + int disposition; + __u16 netfid; + FILE_ALL_INFO * buf = NULL; + time_t temp; + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + + down(&inode->i_sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(file->f_dentry); + up(&inode->i_sb->s_vfs_rename_sem); + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + + cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path)); + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + desiredAccess = GENERIC_READ; + else if ((file->f_flags & O_ACCMODE) == O_WRONLY) + desiredAccess = GENERIC_WRITE; + else if ((file->f_flags & O_ACCMODE) == O_RDWR) { + /* GENERIC_ALL is too much permission to request */ + /* can cause unnecessary access denied on create */ + /* desiredAccess = GENERIC_ALL; */ + desiredAccess = GENERIC_READ | GENERIC_WRITE; + } + +/********************************************************************* + * open flag mapping table: + * + * POSIX Flag CIFS Disposition + * ---------- ---------------- + * O_CREAT FILE_OPEN_IF + * O_CREAT | O_EXCL FILE_CREATE + * O_CREAT | O_TRUNC FILE_OVERWRITE_IF + * O_TRUNC FILE_OVERWRITE + * none of the above FILE_OPEN + * + * Note that there is not a direct match between disposition + * FILE_SUPERSEDE (ie create whether or not file exists although + * O_CREAT | O_TRUNC is similar but truncates the existing + * file rather than creating a new file as FILE_SUPERSEDE does + * (which uses the attributes / metadata passed in on open call) + *? + *? O_SYNC is a reasonable match to CIFS writethrough flag + *? and the read write flags match reasonably. O_LARGEFILE + *? is irrelevant because largefile support is always used + *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY, + * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation + *********************************************************************/ + + /* For 2.4 case, file was already checked for existence + before create by vfs lookup and created in create + entry point, we are now just opening the newly + created file with the right desiredAccess flags */ + + if((file->f_flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + disposition = FILE_OPEN_IF; + else if((file->f_flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) + disposition = FILE_OVERWRITE_IF; + else if((file->f_flags & O_CREAT) == O_CREAT) + disposition = FILE_OPEN_IF; + else + disposition = FILE_OPEN; + + if (oplockEnabled) + oplock = REQ_OPLOCK; + else + oplock = FALSE; + + /* BB pass O_SYNC flag through on file attributes .. BB */ + + /* Also refresh inode by passing in file_info buf returned by SMBOpen + and calling get_inode_info with returned buf (at least + helps non-Unix server case */ + + /* BB we can not do this if this is the second open of a file + and the first handle has writebehind data, we might be + able to simply do a filemap_fdatawrite/filemap_fdatawait first */ + buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); + if(buf==0) { + if (full_path) + kfree(full_path); + FreeXid(xid); + return -ENOMEM; + } + rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, + CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls); + if (rc) { + cFYI(1, ("cifs_open returned 0x%x ", rc)); + cFYI(1, ("oplock: %d ", oplock)); + } else { + file->private_data = + kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL); + if (file->private_data) { + memset(file->private_data, 0, sizeof(struct cifsFileInfo)); + pCifsFile = (struct cifsFileInfo *) file->private_data; + pCifsFile->netfid = netfid; + pCifsFile->pid = current->pid; + init_MUTEX(&pCifsFile->fh_sem); + pCifsFile->pfile = file; /* needed for writepage */ + pCifsFile->pInode = inode; + pCifsFile->invalidHandle = FALSE; + pCifsFile->closePend = FALSE; + write_lock(&GlobalSMBSeslock); + spin_lock(&files_lock); + list_add(&pCifsFile->tlist,&pTcon->openFileList); + pCifsInode = CIFS_I(file->f_dentry->d_inode); + if(pCifsInode) { + /* want handles we can use to read with first */ + /* in the list so we do not have to walk the */ + /* list to search for one in prepare_write */ + if ((file->f_flags & O_ACCMODE) == O_WRONLY) { + list_add_tail(&pCifsFile->flist,&pCifsInode->openFileList); + } else { + list_add(&pCifsFile->flist,&pCifsInode->openFileList); + } + spin_unlock(&files_lock); + write_unlock(&GlobalSMBSeslock); + if(pCifsInode->clientCanCacheRead) { + /* we have the inode open somewhere else + no need to discard cache data */ + } else { + if(buf) { + /* BB need same check in cifs_create too? */ + + /* if not oplocked, invalidate inode pages if mtime + or file size changed */ + temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime)); + if((file->f_dentry->d_inode->i_mtime == temp) && + (file->f_dentry->d_inode->i_size == (loff_t)le64_to_cpu(buf->EndOfFile))) { + cFYI(1,("inode unchanged on server")); + } else { + if(file->f_dentry->d_inode->i_mapping) { + /* BB no need to lock inode until after invalidate*/ + /* since namei code should already have it locked?*/ + filemap_fdatasync(file->f_dentry->d_inode->i_mapping); + } + cFYI(1,("invalidating remote inode since open detected it changed")); + invalidate_inode_pages(file->f_dentry->d_inode); + } + } + } + if (pTcon->ses->capabilities & CAP_UNIX) + rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode, + full_path, inode->i_sb,xid); + else + rc = cifs_get_inode_info(&file->f_dentry->d_inode, + full_path, buf, inode->i_sb,xid); + + if((oplock & 0xF) == OPLOCK_EXCLUSIVE) { + pCifsInode->clientCanCacheAll = TRUE; + pCifsInode->clientCanCacheRead = TRUE; + cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode)); + } else if((oplock & 0xF) == OPLOCK_READ) + pCifsInode->clientCanCacheRead = TRUE; + } else { + spin_unlock(&files_lock); + write_unlock(&GlobalSMBSeslock); + } + if(oplock & CIFS_CREATE_ACTION) { + /* time to set mode which we can not set earlier due + to problems creating new read-only files */ + if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) + CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode, + (__u64)-1, + (__u64)-1, + 0 /* dev */, + cifs_sb->local_nls); + else {/* BB implement via Windows security descriptors */ + /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ + /* in the meantime could set r/o dos attribute when perms are eg: + mode & 0222 == 0 */ + } + } + } + } + + if (buf) + kfree(buf); + if (full_path) + kfree(full_path); + FreeXid(xid); + return rc; +} + +/* Try to reaquire byte range locks that were released when session */ +/* to server was lost */ +static int cifs_relock_file(struct cifsFileInfo * cifsFile) +{ + int rc = 0; + +/* BB list all locks open on this file and relock */ + + return rc; +} + +static int cifs_reopen_file(struct inode *inode, struct file *file, int can_flush) +{ + int rc = -EACCES; + int xid, oplock; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct cifsFileInfo *pCifsFile; + struct cifsInodeInfo *pCifsInode; + char *full_path = NULL; + int desiredAccess = 0x20197; + int disposition = FILE_OPEN; + __u16 netfid; + + if(inode == NULL) + return -EBADF; + if (file->private_data) { + pCifsFile = (struct cifsFileInfo *) file->private_data; + } else + return -EBADF; + + xid = GetXid(); + down(&pCifsFile->fh_sem); + if(pCifsFile->invalidHandle == FALSE) { + up(&pCifsFile->fh_sem); + FreeXid(xid); + return 0; + } + + if(file->f_dentry == NULL) { + up(&pCifsFile->fh_sem); + cFYI(1,("failed file reopen, no valid name if dentry freed")); + FreeXid(xid); + return -EBADF; + } + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; +/* can not grab rename sem here because various ops, including +those that already have the rename sem can end up causing writepage +to get called and if the server was down that means we end up here, +and we can never tell if the caller already has the rename_sem */ + full_path = build_path_from_dentry(file->f_dentry); + if(full_path == NULL) { + up(&pCifsFile->fh_sem); + FreeXid(xid); + return -ENOMEM; + } + + cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path)); + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + desiredAccess = GENERIC_READ; + else if ((file->f_flags & O_ACCMODE) == O_WRONLY) + desiredAccess = GENERIC_WRITE; + else if ((file->f_flags & O_ACCMODE) == O_RDWR) { + /* GENERIC_ALL is too much permission to request */ + /* can cause unnecessary access denied on create */ + /* desiredAccess = GENERIC_ALL; */ + desiredAccess = GENERIC_READ | GENERIC_WRITE; + } + + if (oplockEnabled) + oplock = REQ_OPLOCK; + else + oplock = FALSE; + + + /* Can not refresh inode by passing in file_info buf to be returned + by SMBOpen and then calling get_inode_info with returned buf + since file might have write behind data that needs to be flushed + and server version of file size can be stale. If we + knew for sure that inode was not dirty locally we could do this */ + +/* buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); + if(buf==0) { + up(&pCifsFile->fh_sem); + if (full_path) + kfree(full_path); + FreeXid(xid); + return -ENOMEM; + }*/ + rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, + CREATE_NOT_DIR, &netfid, &oplock, NULL, cifs_sb->local_nls); + if (rc) { + up(&pCifsFile->fh_sem); + cFYI(1, ("cifs_open returned 0x%x ", rc)); + cFYI(1, ("oplock: %d ", oplock)); + } else { + pCifsFile->netfid = netfid; + pCifsFile->invalidHandle = FALSE; + up(&pCifsFile->fh_sem); + pCifsInode = CIFS_I(inode); + if(pCifsInode) { + if(can_flush) { + filemap_fdatasync(inode->i_mapping); + filemap_fdatawait(inode->i_mapping); + /* temporarily disable caching while we + go to server to get inode info */ + pCifsInode->clientCanCacheAll = FALSE; + pCifsInode->clientCanCacheRead = FALSE; + if (pTcon->ses->capabilities & CAP_UNIX) + rc = cifs_get_inode_info_unix(&inode, + full_path, inode->i_sb,xid); + else + rc = cifs_get_inode_info(&inode, + full_path, NULL, inode->i_sb,xid); + } /* else we are writing out data to server already + and could deadlock if we tried to flush data, and + since we do not know if we have data that would + invalidate the current end of file on the server + we can not go to the server to get the new + inod info */ + if((oplock & 0xF) == OPLOCK_EXCLUSIVE) { + pCifsInode->clientCanCacheAll = TRUE; + pCifsInode->clientCanCacheRead = TRUE; + cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode)); + } else if((oplock & 0xF) == OPLOCK_READ) { + pCifsInode->clientCanCacheRead = TRUE; + pCifsInode->clientCanCacheAll = FALSE; + } else { + pCifsInode->clientCanCacheRead = FALSE; + pCifsInode->clientCanCacheAll = FALSE; + } + cifs_relock_file(pCifsFile); + } + } + + if (full_path) + kfree(full_path); + FreeXid(xid); + return rc; +} + +int +cifs_close(struct inode *inode, struct file *file) +{ + int rc = 0; + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct cifsFileInfo *pSMBFile = + (struct cifsFileInfo *) file->private_data; + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + if (pSMBFile) { + pSMBFile->closePend = TRUE; + spin_lock(&files_lock); + if(pTcon) { + /* no sense reconnecting to close a file that is + already closed */ + if (pTcon->tidStatus != CifsNeedReconnect) { + spin_unlock(&files_lock);
+ rc = CIFSSMBClose(xid,pTcon,pSMBFile->netfid); + spin_lock(&files_lock);
+ } + } + list_del(&pSMBFile->flist); + list_del(&pSMBFile->tlist); + spin_unlock(&files_lock); + if(pSMBFile->search_resume_name) + kfree(pSMBFile->search_resume_name); + kfree(file->private_data); + file->private_data = NULL; + } else + rc = -EBADF; + + if(list_empty(&(CIFS_I(inode)->openFileList))) { + cFYI(1,("closing last open instance for inode %p",inode)); + /* if the file is not open we do not know if we can cache + info on this inode, much less write behind and read ahead */ + CIFS_I(inode)->clientCanCacheRead = FALSE; + CIFS_I(inode)->clientCanCacheAll = FALSE; + } + if((rc ==0) && CIFS_I(inode)->write_behind_rc) + rc = CIFS_I(inode)->write_behind_rc; + FreeXid(xid); + return rc; +} + +int +cifs_closedir(struct inode *inode, struct file *file) +{ + int rc = 0; + int xid; + struct cifsFileInfo *pSMBFileStruct = + (struct cifsFileInfo *) file->private_data; + + cFYI(1, ("Closedir inode = 0x%p with ", inode)); + + xid = GetXid(); + + if (pSMBFileStruct) { + cFYI(1, ("Freeing private data in close dir")); + kfree(file->private_data); + file->private_data = NULL; + } + FreeXid(xid); + return rc; +} + +int +cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) +{ + int rc, xid; + __u32 lockType = LOCKING_ANDX_LARGE_FILES; + __u32 numLock = 0; + __u32 numUnlock = 0; + __u64 length; + int wait_flag = FALSE; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + length = 1 + pfLock->fl_end - pfLock->fl_start; + + rc = -EACCES; + + xid = GetXid(); + + cFYI(1, + ("Lock parm: 0x%x flockflags: 0x%x flocktype: 0x%x start: %lld end: %lld", + cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start, + pfLock->fl_end)); + + if (pfLock->fl_flags & FL_POSIX) + cFYI(1, ("Posix ")); + if (pfLock->fl_flags & FL_FLOCK) + cFYI(1, ("Flock ")); +/* if (pfLock->fl_flags & FL_SLEEP) { + cFYI(1, ("Blocking lock ")); + wait_flag = TRUE; + } */ + if (pfLock->fl_flags & FL_ACCESS) + cFYI(1, ("Process suspended by mandatory locking - not implemented yet ")); + if (pfLock->fl_flags & FL_LEASE) + cFYI(1, ("Lease on file - not implemented yet")); + if (pfLock->fl_flags & (~(FL_POSIX | FL_FLOCK | FL_ACCESS | FL_LEASE))) + cFYI(1, ("Unknown lock flags 0x%x",pfLock->fl_flags)); + + if (pfLock->fl_type == F_WRLCK) { + cFYI(1, ("F_WRLCK ")); + numLock = 1; + } else if (pfLock->fl_type == F_UNLCK) { + cFYI(1, ("F_UNLCK ")); + numUnlock = 1; + } else if (pfLock->fl_type == F_RDLCK) { + cFYI(1, ("F_RDLCK ")); + lockType |= LOCKING_ANDX_SHARED_LOCK; + numLock = 1; + } else if (pfLock->fl_type == F_EXLCK) { + cFYI(1, ("F_EXLCK ")); + numLock = 1; + } else if (pfLock->fl_type == F_SHLCK) { + cFYI(1, ("F_SHLCK ")); + lockType |= LOCKING_ANDX_SHARED_LOCK; + numLock = 1; + } else + cFYI(1, ("Unknown type of lock ")); + + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + pTcon = cifs_sb->tcon; + + if (file->private_data == NULL) { + FreeXid(xid); + return -EBADF; + } + + if (IS_GETLK(cmd)) { + rc = CIFSSMBLock(xid, pTcon, + ((struct cifsFileInfo *) file-> + private_data)->netfid, + length, + pfLock->fl_start, 0, 1, lockType, + 0 /* wait flag */ ); + if (rc == 0) { + rc = CIFSSMBLock(xid, pTcon, + ((struct cifsFileInfo *) file-> + private_data)->netfid, + length, + pfLock->fl_start, 1 /* numUnlock */ , + 0 /* numLock */ , lockType, + 0 /* wait flag */ ); + pfLock->fl_type = F_UNLCK; + if (rc != 0) + cERROR(1, + ("Error unlocking previously locked range %d during test of lock ", + rc)); + rc = 0; + + } else { + /* if rc == ERR_SHARING_VIOLATION ? */ + rc = 0; /* do not change lock type to unlock since range in use */ + } + + FreeXid(xid); + return rc; + } + + rc = CIFSSMBLock(xid, pTcon, + ((struct cifsFileInfo *) file->private_data)-> + netfid, length, + pfLock->fl_start, numUnlock, numLock, lockType, + wait_flag); + FreeXid(xid); + return rc; +} + +ssize_t +cifs_write(struct file * file, const char *write_data, + size_t write_size, loff_t * poffset) +{ + int rc = 0; + unsigned int bytes_written = 0; + unsigned int total_written; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + int xid, long_op; + struct cifsFileInfo * open_file; + + if(file->f_dentry == NULL) + return -EBADF; + + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + if(cifs_sb == NULL) { + return -EBADF; + } + pTcon = cifs_sb->tcon; + + /*cFYI(1, + (" write %d bytes to offset %lld of %s", write_size, + *poffset, file->f_dentry->d_name.name)); */ + + if (file->private_data == NULL) { + return -EBADF; + } else { + open_file = (struct cifsFileInfo *) file->private_data; + } + + xid = GetXid(); + if(file->f_dentry->d_inode == NULL) { + FreeXid(xid); + return -EBADF; + } + + if (*poffset > file->f_dentry->d_inode->i_size) + long_op = 2; /* writes past end of file can take a long time */ + else + long_op = 1; + + for (total_written = 0; write_size > total_written; + total_written += bytes_written) { + rc = -EAGAIN; + while(rc == -EAGAIN) { + if(file->private_data == NULL) { + /* file has been closed on us */ + FreeXid(xid); + /* if we have gotten here we have written some data + and blocked, and the file has been freed on us + while we blocked so return what we managed to write */ + return total_written; + } + if(open_file->closePend) { + FreeXid(xid); + if(total_written) + return total_written; + else + return -EBADF; + } + if (open_file->invalidHandle) { + if((file->f_dentry == NULL) || + (file->f_dentry->d_inode == NULL)) { + FreeXid(xid); + return total_written; + } + /* we could deadlock if we called + filemap_fdatawait from here so tell + reopen_file not to flush data to server now */ + rc = cifs_reopen_file(file->f_dentry->d_inode, + file,FALSE); + if(rc != 0) + break; + } + + rc = CIFSSMBWrite(xid, pTcon, + open_file->netfid, + write_size - total_written, *poffset, + &bytes_written, + write_data + total_written, long_op); + } + if (rc || (bytes_written == 0)) { + if (total_written) + break; + else { + FreeXid(xid); + return rc; + } + } else + *poffset += bytes_written; + long_op = FALSE; /* subsequent writes fast - 15 seconds is plenty */ + } + +#ifdef CONFIG_CIFS_STATS + if(total_written > 0) { + atomic_inc(&pTcon->num_writes); + spin_lock(&pTcon->stat_lock); + pTcon->bytes_written += total_written; + spin_unlock(&pTcon->stat_lock); + } +#endif + + /* since the write may have blocked check these pointers again */ + if(file->f_dentry) { + if(file->f_dentry->d_inode) { + file->f_dentry->d_inode->i_ctime = file->f_dentry->d_inode->i_mtime = + CURRENT_TIME; + if (total_written > 0) { + if (*poffset > file->f_dentry->d_inode->i_size) + file->f_dentry->d_inode->i_size = *poffset; + } + mark_inode_dirty_sync(file->f_dentry->d_inode); + } + } + FreeXid(xid); + return total_written; +} + +static int +cifs_partialpagewrite(struct page *page,unsigned from, unsigned to) +{ + struct address_space *mapping = page->mapping; + loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; + char * write_data; + int rc = -EFAULT; + int bytes_written = 0; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct inode *inode; + struct cifsInodeInfo *cifsInode; + struct cifsFileInfo *open_file = NULL; + struct list_head *tmp; + struct list_head *tmp1; + + if (!mapping) { + return -EFAULT; + } else if(!mapping->host) { + return -EFAULT; + } + + inode = page->mapping->host; + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + + offset += (loff_t)from; + write_data = kmap(page); + write_data += from; + + if((to > PAGE_CACHE_SIZE) || (from > to)) { + kunmap(page); + return -EIO; + } + + /* racing with truncate? */ + if(offset > mapping->host->i_size) { + kunmap(page); + return 0; /* don't care */ + } + + /* check to make sure that we are not extending the file */ + if(mapping->host->i_size - offset < (loff_t)to) + to = (unsigned)(mapping->host->i_size - offset); + + + cifsInode = CIFS_I(mapping->host); + read_lock(&GlobalSMBSeslock); + /* BB we should start at the end */ + list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { + open_file = list_entry(tmp,struct cifsFileInfo, flist); + if(open_file->closePend) + continue; + /* We check if file is open for writing first */ + if((open_file->pfile) && + ((open_file->pfile->f_flags & O_RDWR) || + (open_file->pfile->f_flags & O_WRONLY))) { + read_unlock(&GlobalSMBSeslock); + bytes_written = cifs_write(open_file->pfile, write_data, + to-from, &offset); + read_lock(&GlobalSMBSeslock); + /* Does mm or vfs already set times? */ + inode->i_atime = inode->i_mtime = CURRENT_TIME; + if ((bytes_written > 0) && (offset)) { + rc = 0; + } else if(bytes_written < 0) { + if(rc == -EBADF) { + /* have seen a case in which + kernel seemed to have closed/freed a file + even with writes active so we might as well + see if there are other file structs to try + for the same inode before giving up */ + continue; + } else + rc = bytes_written; + } + break; /* now that we found a valid file handle + and tried to write to it we are done, no + sense continuing to loop looking for another */ + } + if(tmp->next == NULL) { + cFYI(1,("File instance %p removed",tmp)); + break; + } + } + read_unlock(&GlobalSMBSeslock); + if(open_file == NULL) { + cFYI(1,("No writeable filehandles for inode")); + rc = -EIO; + } + + kunmap(page); + return rc; +} + +#if 0 +static int +cifs_writepages(struct address_space *mapping, struct writeback_control *wbc) +{ + int rc = -EFAULT; + int xid; + + xid = GetXid(); +/* call 16K write then Setpageuptodate */ + FreeXid(xid); + return rc; +} +#endif + +static int +cifs_writepage(struct page* page) +{ + int rc = -EFAULT; + int xid; + + xid = GetXid(); +/* BB add check for wbc flags */ + page_cache_get(page); + if (!Page_Uptodate(page)) { + cFYI(1,("ppw - page not up to date")); + } + + rc = cifs_partialpagewrite(page,0,PAGE_CACHE_SIZE); + SetPageUptodate(page); /* BB add check for error and Clearuptodate? */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) + unlock_page(page); +#else + UnlockPage(page); +#endif + page_cache_release(page); + FreeXid(xid); + return rc; +} + +static int +cifs_commit_write(struct file *file, struct page *page, unsigned offset, + unsigned to) +{ + int xid; + int rc = 0; + struct inode *inode = page->mapping->host; + loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + char * page_data; + + xid = GetXid(); + cFYI(1,("commit write for page %p up to position %lld for %d",page,position,to)); + if (position > inode->i_size){ + inode->i_size = position; + /*if (file->private_data == NULL) { + rc = -EBADF; + } else { + open_file = (struct cifsFileInfo *)file->private_data; + cifs_sb = CIFS_SB(inode->i_sb); + rc = -EAGAIN; + while(rc == -EAGAIN) { + if((open_file->invalidHandle) && + (!open_file->closePend)) { + rc = cifs_reopen_file(file->f_dentry->d_inode,file); + if(rc != 0) + break; + } + if(!open_file->closePend) { + rc = CIFSSMBSetFileSize(xid, cifs_sb->tcon, + position, open_file->netfid, + open_file->pid,FALSE); + } else { + rc = -EBADF; + break; + } + } + cFYI(1,(" SetEOF (commit write) rc = %d",rc)); + }*/ + } + if (!Page_Uptodate(page)) { + position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset; + /* can not rely on (or let) writepage write this data */ + if(to < offset) { + cFYI(1,("Illegal offsets, can not copy from %d to %d", + offset,to)); + FreeXid(xid); + return rc; + } + /* this is probably better than directly calling + partialpage_write since in this function + the file handle is known which we might as well + leverage */ + /* BB check if anything else missing out of ppw */ + /* such as updating last write time */ + page_data = kmap(page); + rc = cifs_write(file, page_data+offset,to-offset, + &position); + if(rc > 0) + rc = 0; + /* else if rc < 0 should we set writebehind rc? */ + kunmap(page); + } else { + set_page_dirty(page); + } + + FreeXid(xid); + return rc; +} + +int +cifs_fsync(struct file *file, struct dentry *dentry, int datasync) +{ + int xid; + int rc = 0; + struct inode * inode = file->f_dentry->d_inode; + + xid = GetXid(); + + cFYI(1, ("Sync file - name: %s datasync: 0x%x ", + dentry->d_name.name, datasync)); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,17)) + rc = filemap_fdatasync(inode->i_mapping); +#else + filemap_fdatasync(inode->i_mapping); +#endif + if(rc == 0) + CIFS_I(inode)->write_behind_rc = 0; + FreeXid(xid); + return rc; +} + +static int +cifs_sync_page(struct page *page) +{ + struct address_space *mapping; + struct inode *inode; + unsigned long index = page->index; + unsigned int rpages = 0; + int rc = 0; + + cFYI(1,("sync page %p",page)); + mapping = page->mapping; + if (!mapping) + return 0; + inode = mapping->host; + if (!inode) + return 0; + +/* fill in rpages then + result = cifs_pagein_inode(inode, index, rpages); *//* BB finish */ + + cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index)); + + if (rc < 0) + return rc; + return 0; +} + +/* + * As file closes, flush all cached write data for this inode checking + * for write behind errors. + * + */ +int cifs_flush(struct file *file) +{ + struct inode * inode = file->f_dentry->d_inode; + int rc = 0; + + /* Rather than do the steps manually: */ + /* lock the inode for writing */ + /* loop through pages looking for write behind data (dirty pages) */ + /* coalesce into contiguous 16K (or smaller) chunks to write to server */ + /* send to server (prefer in parallel) */ + /* deal with writebehind errors */ + /* unlock inode for writing */ + /* filemapfdatawrite appears easier for the time being */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,17)) + rc = filemap_fdatasync(inode->i_mapping); +#else + filemap_fdatasync(inode->i_mapping); +#endif + if(rc == 0) /* reset wb rc if we were able to write out dirty pages */ + CIFS_I(inode)->write_behind_rc = 0; + + cFYI(1,("Flush inode %p file %p rc %d",inode,file,rc)); + + return rc; +} + + +ssize_t +cifs_read(struct file * file, char *read_data, size_t read_size, + loff_t * poffset) +{ + int rc = -EACCES; + unsigned int bytes_read = 0; + unsigned int total_read; + unsigned int current_read_size; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + int xid; + char * current_offset; + struct cifsFileInfo * open_file; + + xid = GetXid(); + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + pTcon = cifs_sb->tcon; + + if (file->private_data == NULL) { + FreeXid(xid); + return -EBADF; + } + open_file = (struct cifsFileInfo *)file->private_data; + + if((file->f_flags & O_ACCMODE) == O_WRONLY) { + cFYI(1,("attempting read on write only file instance")); + } + + for (total_read = 0,current_offset=read_data; read_size > total_read; + total_read += bytes_read,current_offset+=bytes_read) { +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15)) + current_read_size = min_t(const int,read_size - total_read,cifs_sb->rsize); +#else + current_read_size = min(read_size - total_read,cifs_sb->rsize); +#endif + rc = -EAGAIN; + while(rc == -EAGAIN) { + if ((open_file->invalidHandle) && (!open_file->closePend)) { + rc = cifs_reopen_file(file->f_dentry->d_inode, + file,TRUE); + if(rc != 0) + break; + } + + rc = CIFSSMBRead(xid, pTcon, + open_file->netfid, + current_read_size, *poffset, + &bytes_read, ¤t_offset); + } + if (rc || (bytes_read == 0)) { + if (total_read) { + break; + } else { + FreeXid(xid); + return rc; + } + } else { +#ifdef CONFIG_CIFS_STATS + atomic_inc(&pTcon->num_reads); + spin_lock(&pTcon->stat_lock); + pTcon->bytes_read += total_read; + spin_unlock(&pTcon->stat_lock); +#endif + *poffset += bytes_read; + } + } + FreeXid(xid); + return total_read; +} + +int cifs_file_mmap(struct file * file, struct vm_area_struct * vma) +{ + struct dentry * dentry = file->f_dentry; + int rc, xid; + + xid = GetXid(); + rc = cifs_revalidate(dentry); + if (rc) { + cFYI(1,("Validation prior to mmap failed, error=%d", rc)); + FreeXid(xid); + return rc; + } + rc = generic_file_mmap(file, vma); + FreeXid(xid); + return rc; +} + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +static void cifs_copy_cache_pages(struct address_space *mapping, + struct list_head *pages, int bytes_read, + char *data,struct pagevec * plru_pvec) +{ + struct page *page; + char * target; + + while (bytes_read > 0) { + if(list_empty(pages)) + break; + + page = list_entry(pages->prev, struct page, lru); + list_del(&page->lru); + + if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) { + page_cache_release(page); + cFYI(1,("Add page cache failed")); + continue; + } + + target = kmap_atomic(page,KM_USER0); + + if(PAGE_CACHE_SIZE > bytes_read) { + memcpy(target,data,bytes_read); + /* zero the tail end of this partial page */ + memset(target+bytes_read,0,PAGE_CACHE_SIZE-bytes_read); + bytes_read = 0; + } else { + memcpy(target,data,PAGE_CACHE_SIZE); + bytes_read -= PAGE_CACHE_SIZE; + } + kunmap_atomic(target,KM_USER0); + + flush_dcache_page(page); + SetPageUptodate(page); + unlock_page(page); + if (!pagevec_add(plru_pvec, page)) + __pagevec_lru_add(plru_pvec); + data += PAGE_CACHE_SIZE; + } + return; +} + + +static int +cifs_readpages(struct file *file, struct address_space *mapping, + struct list_head *page_list, unsigned num_pages) +{ + int rc = -EACCES; + int xid; + loff_t offset; + struct page * page; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + int bytes_read = 0; + unsigned int read_size,i; + char * smb_read_data = NULL; + struct smb_com_read_rsp * pSMBr; + struct pagevec lru_pvec; + struct cifsFileInfo * open_file; + + xid = GetXid(); + if (file->private_data == NULL) { + FreeXid(xid); + return -EBADF; + } + open_file = (struct cifsFileInfo *)file->private_data; + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + pTcon = cifs_sb->tcon; + + pagevec_init(&lru_pvec, 0); + + for(i = 0;i<num_pages;) { + unsigned contig_pages; + struct page * tmp_page; + unsigned long expected_index; + + if(list_empty(page_list)) { + break; + } + page = list_entry(page_list->prev, struct page, lru); + offset = (loff_t)page->index << PAGE_CACHE_SHIFT; + + /* count adjacent pages that we will read into */ + contig_pages = 0; + expected_index = list_entry(page_list->prev,struct page,lru)->index; + list_for_each_entry_reverse(tmp_page,page_list,lru) { + if(tmp_page->index == expected_index) { + contig_pages++; + expected_index++; + } else { + break; + } + } + if(contig_pages + i > num_pages) { + contig_pages = num_pages - i; + } + + /* for reads over a certain size could initiate async read ahead */ + + read_size = contig_pages * PAGE_CACHE_SIZE; + /* Read size needs to be in multiples of one page */ + read_size = min_t(const unsigned int,read_size,cifs_sb->rsize & PAGE_CACHE_MASK); + + rc = -EAGAIN; + while(rc == -EAGAIN) { + if ((open_file->invalidHandle) && (!open_file->closePend)) { + rc = cifs_reopen_file(file->f_dentry->d_inode, + file, TRUE); + if(rc != 0) + break; + } + + rc = CIFSSMBRead(xid, pTcon, + open_file->netfid, + read_size, offset, + &bytes_read, &smb_read_data); + /* BB need to check return code here */ + if(rc== -EAGAIN) { + if(smb_read_data) { + cifs_buf_release(smb_read_data); + smb_read_data = NULL; + } + } + } + if ((rc < 0) || (smb_read_data == NULL)) { + cFYI(1,("Read error in readpages: %d",rc)); + /* clean up remaing pages off list */ + while (!list_empty(page_list) && (i < num_pages)) { + page = list_entry(page_list->prev, struct page, lru); + list_del(&page->lru); + page_cache_release(page); + } + break; + } else if (bytes_read > 0) { + pSMBr = (struct smb_com_read_rsp *)smb_read_data; + cifs_copy_cache_pages(mapping, page_list, bytes_read, + smb_read_data + 4 /* RFC1001 hdr */ + + le16_to_cpu(pSMBr->DataOffset), &lru_pvec); + + i += bytes_read >> PAGE_CACHE_SHIFT; +#ifdef CONFIG_CIFS_STATS + atomic_inc(&pTcon->num_reads); + spin_lock(&pTcon->stat_lock); + pTcon->bytes_read += bytes_read; + spin_unlock(&pTcon->stat_lock); +#endif + if((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { + cFYI(1,("Partial page %d of %d read to cache",i++,num_pages)); + + i++; /* account for partial page */ + + /* server copy of file can have smaller size than client */ + /* BB do we need to verify this common case ? this case is ok - + if we are at server EOF we will hit it on next read */ + + /* while(!list_empty(page_list) && (i < num_pages)) { + page = list_entry(page_list->prev,struct page, list); + list_del(&page->list); + page_cache_release(page); + } + break; */ + } + } else { + cFYI(1,("No bytes read (%d) at offset %lld . Cleaning remaining pages from readahead list",bytes_read,offset)); + /* BB turn off caching and do new lookup on file size at server? */ + while (!list_empty(page_list) && (i < num_pages)) { + page = list_entry(page_list->prev, struct page, lru); + list_del(&page->lru); + page_cache_release(page); /* BB removeme - replace with zero of page? */ + } + break; + } + if(smb_read_data) { + cifs_buf_release(smb_read_data); + smb_read_data = NULL; + } + bytes_read = 0; + } + + pagevec_lru_add(&lru_pvec); + +/* need to free smb_read_data buf before exit */ + if(smb_read_data) { + cifs_buf_release(smb_read_data); + smb_read_data = NULL; + } + + FreeXid(xid); + return rc; +} +#endif + +static int cifs_readpage_worker(struct file *file, struct page *page, loff_t * poffset) +{ + char * read_data; + int rc; + + page_cache_get(page); + read_data = kmap(page); + /* for reads over a certain size could initiate async read ahead */ + + rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset); + + if (rc < 0) + goto io_error; + else { + cFYI(1,("Bytes read %d ",rc)); + } + + file->f_dentry->d_inode->i_atime = CURRENT_TIME; + + if(PAGE_CACHE_SIZE > rc) { + memset(read_data+rc, 0, PAGE_CACHE_SIZE - rc); + } + flush_dcache_page(page); + SetPageUptodate(page); + rc = 0; + +io_error: + kunmap(page); + page_cache_release(page); + return rc; +} + +static int +cifs_readpage(struct file *file, struct page *page) +{ + loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; + int rc = -EACCES; + int xid; + + xid = GetXid(); + + if (file->private_data == NULL) { + FreeXid(xid); + return -EBADF; + } + + cFYI(1,("readpage %p at offset %d 0x%x\n",page,(int)offset,(int)offset)); + + rc = cifs_readpage_worker(file,page,&offset); + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) + unlock_page(page); +#else + UnlockPage(page); +#endif + + FreeXid(xid); + return rc; +} + +/* We do not want to update the file size from server for inodes + open for write - to avoid races with writepage extending + the file - in the future we could consider allowing + refreshing the inode only on increases in the file size + but this is tricky to do without racing with writebehind + page caching in the current Linux kernel design */ + +int is_size_safe_to_change(struct cifsInodeInfo * cifsInode) +{ + struct list_head *tmp; + struct list_head *tmp1; + struct cifsFileInfo *open_file = NULL; + int rc = TRUE; + + if(cifsInode == NULL) + return rc; + + read_lock(&GlobalSMBSeslock); + list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { + open_file = list_entry(tmp,struct cifsFileInfo, flist); + if(open_file == NULL) + break; + if(open_file->closePend) + continue; + /* We check if file is open for writing, + BB we could supplement this with a check to see if file size + changes have been flushed to server - ie inode metadata dirty */ + if((open_file->pfile) && + ((open_file->pfile->f_flags & O_RDWR) || + (open_file->pfile->f_flags & O_WRONLY))) { + rc = FALSE; + break; + } + if(tmp->next == NULL) { + cFYI(1,("File instance %p removed",tmp)); + break; + } + } + read_unlock(&GlobalSMBSeslock); + return rc; +} + + +void +fill_in_inode(struct inode *tmp_inode, + FILE_DIRECTORY_INFO * pfindData, int *pobject_type) +{ + struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); + struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); + + pfindData->ExtFileAttributes = + le32_to_cpu(pfindData->ExtFileAttributes); + pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize); + pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile); + cifsInfo->cifsAttrs = pfindData->ExtFileAttributes; + cifsInfo->time = jiffies; + + /* Linux can not store file creation time unfortunately so ignore it */ + tmp_inode->i_atime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); + tmp_inode->i_mtime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); + tmp_inode->i_ctime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); + /* treat dos attribute of read-only as read-only mode bit e.g. 555? */ + /* 2767 perms - indicate mandatory locking */ + /* BB fill in uid and gid here? with help from winbind? + or retrieve from NTFS stream extended attribute */ + if(atomic_read(&cifsInfo->inUse) == 0) { + tmp_inode->i_uid = cifs_sb->mnt_uid; + tmp_inode->i_gid = cifs_sb->mnt_gid; + /* set default mode. will override for dirs below */ + tmp_inode->i_mode = cifs_sb->mnt_file_mode; + } + + cFYI(0, + ("CIFS FFIRST: Attributes came in as 0x%x", + pfindData->ExtFileAttributes)); + if (pfindData->ExtFileAttributes & ATTR_REPARSE) { + *pobject_type = DT_LNK; + /* BB can this and S_IFREG or S_IFDIR be set as in Windows? */ + tmp_inode->i_mode |= S_IFLNK; + } else if (pfindData->ExtFileAttributes & ATTR_DIRECTORY) { + *pobject_type = DT_DIR; + /* override default perms since we do not lock dirs */ + if(atomic_read(&cifsInfo->inUse) == 0) { + tmp_inode->i_mode = cifs_sb->mnt_dir_mode; + } + tmp_inode->i_mode |= S_IFDIR; + } else { + *pobject_type = DT_REG; + tmp_inode->i_mode |= S_IFREG; + if(pfindData->ExtFileAttributes & ATTR_READONLY) + tmp_inode->i_mode &= ~(S_IWUGO); + + }/* could add code here - to validate if device or weird share type? */ + + /* can not fill in nlink here as in qpathinfo version and Unx search */ + if(atomic_read(&cifsInfo->inUse) == 0) { + atomic_set(&cifsInfo->inUse,1); + } + if(is_size_safe_to_change(cifsInfo)) { + /* can not safely change the file size here if the + client is writing to it due to potential races */ + tmp_inode->i_size = pfindData->EndOfFile; + + /* 512 bytes (2**9) is the fake blocksize that must be used */ + /* for this calculation, even though the reported blocksize is larger */ + tmp_inode->i_blocks = (512 - 1 + pfindData->AllocationSize) >> 9; + } + + if (pfindData->AllocationSize < pfindData->EndOfFile) + cFYI(1, ("Possible sparse file: allocation size less than end of file ")); + cFYI(1, + ("File Size %ld and blocks %ld and blocksize %ld", + (unsigned long) tmp_inode->i_size, tmp_inode->i_blocks, + tmp_inode->i_blksize)); + if (S_ISREG(tmp_inode->i_mode)) { + cFYI(1, (" File inode ")); + tmp_inode->i_op = &cifs_file_inode_ops; + tmp_inode->i_fop = &cifs_file_ops; + tmp_inode->i_data.a_ops = &cifs_addr_ops; + } else if (S_ISDIR(tmp_inode->i_mode)) { + cFYI(1, (" Directory inode")); + tmp_inode->i_op = &cifs_dir_inode_ops; + tmp_inode->i_fop = &cifs_dir_ops; + } else if (S_ISLNK(tmp_inode->i_mode)) { + cFYI(1, (" Symbolic Link inode ")); + tmp_inode->i_op = &cifs_symlink_inode_ops; + } else { + cFYI(1, (" Init special inode ")); + init_special_inode(tmp_inode, tmp_inode->i_mode, + kdev_t_to_nr(tmp_inode->i_rdev)); + } +} + +void +unix_fill_in_inode(struct inode *tmp_inode, + FILE_UNIX_INFO * pfindData, int *pobject_type) +{ + struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); + cifsInfo->time = jiffies; + atomic_inc(&cifsInfo->inUse); + + tmp_inode->i_atime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); + tmp_inode->i_mtime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastModificationTime)); + tmp_inode->i_ctime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange)); + + tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions); + pfindData->Type = le32_to_cpu(pfindData->Type); + if (pfindData->Type == UNIX_FILE) { + *pobject_type = DT_REG; + tmp_inode->i_mode |= S_IFREG; + } else if (pfindData->Type == UNIX_SYMLINK) { + *pobject_type = DT_LNK; + tmp_inode->i_mode |= S_IFLNK; + } else if (pfindData->Type == UNIX_DIR) { + *pobject_type = DT_DIR; + tmp_inode->i_mode |= S_IFDIR; + } else if (pfindData->Type == UNIX_CHARDEV) { + *pobject_type = DT_CHR; + tmp_inode->i_mode |= S_IFCHR; + tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), + le64_to_cpu(pfindData->DevMinor) & MINORMASK); + } else if (pfindData->Type == UNIX_BLOCKDEV) { + *pobject_type = DT_BLK; + tmp_inode->i_mode |= S_IFBLK; + tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), + le64_to_cpu(pfindData->DevMinor) & MINORMASK); + } else if (pfindData->Type == UNIX_FIFO) { + *pobject_type = DT_FIFO; + tmp_inode->i_mode |= S_IFIFO; + } else if (pfindData->Type == UNIX_SOCKET) { + *pobject_type = DT_SOCK; + tmp_inode->i_mode |= S_IFSOCK; + } + + tmp_inode->i_uid = le64_to_cpu(pfindData->Uid); + tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); + tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); + + pfindData->NumOfBytes = le64_to_cpu(pfindData->NumOfBytes); + if(is_size_safe_to_change(cifsInfo)) { + /* can not safely change the file size here if the + client is writing to it due to potential races */ + pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile); + tmp_inode->i_size = pfindData->EndOfFile; + + /* 512 bytes (2**9) is the fake blocksize that must be used */ + /* for this calculation, not the real blocksize */ + tmp_inode->i_blocks = (512 - 1 + pfindData->NumOfBytes) >> 9; + } + + if (S_ISREG(tmp_inode->i_mode)) { + cFYI(1, ("File inode")); + tmp_inode->i_op = &cifs_file_inode_ops; + tmp_inode->i_fop = &cifs_file_ops; + tmp_inode->i_data.a_ops = &cifs_addr_ops; + } else if (S_ISDIR(tmp_inode->i_mode)) { + cFYI(1, ("Directory inode")); + tmp_inode->i_op = &cifs_dir_inode_ops; + tmp_inode->i_fop = &cifs_dir_ops; + } else if (S_ISLNK(tmp_inode->i_mode)) { + cFYI(1, ("Symbolic Link inode")); + tmp_inode->i_op = &cifs_symlink_inode_ops; +/* tmp_inode->i_fop = *//* do not need to set to anything */ + } else { + cFYI(1, ("Special inode")); + init_special_inode(tmp_inode, tmp_inode->i_mode, + kdev_t_to_nr(tmp_inode->i_rdev)); + } +} + +static void +construct_dentry(struct qstr *qstring, struct file *file, + struct inode **ptmp_inode, struct dentry **pnew_dentry) +{ + struct dentry *tmp_dentry; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct cifsInodeInfo *pCifsI; + + cFYI(1, ("For %s ", qstring->name)); + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + pTcon = cifs_sb->tcon; + + qstring->hash = full_name_hash(qstring->name, qstring->len); + tmp_dentry = d_lookup(file->f_dentry, qstring); + if (tmp_dentry) { + cFYI(0, (" existing dentry with inode 0x%p", tmp_dentry->d_inode)); + *ptmp_inode = tmp_dentry->d_inode; + /* BB overwrite the old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len ?? */ + if(*ptmp_inode == NULL) { + *ptmp_inode = new_inode(file->f_dentry->d_sb); + if(*ptmp_inode == NULL) + return; + d_instantiate(tmp_dentry, *ptmp_inode); + insert_inode_hash(*ptmp_inode); + pCifsI = CIFS_I(*ptmp_inode); + INIT_LIST_HEAD(&pCifsI->openFileList); + /* can not enable caching for this inode + until a file instance is open and we + can check the oplock flag on the open + response */ + (*ptmp_inode)->i_blksize = CIFS_MAX_MSGSIZE; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15)) + (*ptmp_inode)->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ +#endif + pCifsI->clientCanCacheRead = FALSE; + pCifsI->clientCanCacheAll = FALSE; + pCifsI->time = 0; + /* do not need to set cifs Attrs since + they are about to be overwritten + in fill_in_inode */ + atomic_set(&pCifsI->inUse, 0); + } + } else { + tmp_dentry = d_alloc(file->f_dentry, qstring); + if(tmp_dentry == NULL) { + cERROR(1,("Failed allocating dentry")); + return; + } + + if(ptmp_inode) { + *ptmp_inode = new_inode(file->f_dentry->d_sb); + if(*ptmp_inode == NULL) + return; + pCifsI = CIFS_I(*ptmp_inode); + insert_inode_hash(*ptmp_inode); + INIT_LIST_HEAD(&pCifsI->openFileList); + /* can not enable caching for this inode + until a file instance is open and we + can check the oplock flag on the open + response */ + (*ptmp_inode)->i_blksize = CIFS_MAX_MSGSIZE; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15)) + (*ptmp_inode)->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ +#endif + pCifsI->clientCanCacheRead = FALSE; + pCifsI->clientCanCacheAll = FALSE; + pCifsI->time = 0; + /* do not need to set cifs Attrs since + they are about to be overwritten + in fill_in_inode */ + atomic_set(&pCifsI->inUse, 0); + } + tmp_dentry->d_op = &cifs_dentry_ops; + d_instantiate(tmp_dentry, *ptmp_inode); + d_rehash(tmp_dentry); + } + + tmp_dentry->d_time = jiffies; + *pnew_dentry = tmp_dentry; +} + +static void reset_resume_key(struct file * dir_file, + unsigned char * filename, + unsigned int len,int Unicode,struct nls_table * nls_tab) { + struct cifsFileInfo *cifsFile; + + cifsFile = (struct cifsFileInfo *)dir_file->private_data; + if(cifsFile == NULL) + return; + if(cifsFile->search_resume_name) { + kfree(cifsFile->search_resume_name); + } + + if(Unicode) + len *= 2; + cifsFile->resume_name_length = len; + + cifsFile->search_resume_name = + kmalloc(cifsFile->resume_name_length, GFP_KERNEL); + + if(cifsFile->search_resume_name == NULL) { + cERROR(1,("failed new resume key allocate, length %d", + cifsFile->resume_name_length)); + return; + } + if(Unicode) + cifs_strtoUCS((wchar_t *) cifsFile->search_resume_name, + filename, len, nls_tab); + else + memcpy(cifsFile->search_resume_name, filename, + cifsFile->resume_name_length); + cFYI(1,("Reset resume key to: %s with len %d",filename,len)); + return; +} + + + +static int +cifs_filldir(struct qstr *pqstring, FILE_DIRECTORY_INFO * pfindData, + struct file *file, filldir_t filldir, void *direntry) +{ + struct inode *tmp_inode; + struct dentry *tmp_dentry; + int object_type,rc; + + pqstring->name = pfindData->FileName; + pqstring->len = pfindData->FileNameLength; + + construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); + if((tmp_inode == NULL) || (tmp_dentry == NULL)) { + return -ENOMEM; + } + fill_in_inode(tmp_inode, pfindData, &object_type); + rc = filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos, + tmp_inode->i_ino, object_type); + if(rc) { + /* due to readdir error we need to recalculate resume + key so next readdir will restart on right entry */ + cFYI(1,("Error %d on filldir of %s",rc ,pfindData->FileName)); + } + dput(tmp_dentry); + return rc; +} + +static int +cifs_filldir_unix(struct qstr *pqstring, + FILE_UNIX_INFO * pUnixFindData, struct file *file, + filldir_t filldir, void *direntry) +{ + struct inode *tmp_inode; + struct dentry *tmp_dentry; + int object_type, rc; + + pqstring->name = pUnixFindData->FileName; + pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF); + + construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); + if((tmp_inode == NULL) || (tmp_dentry == NULL)) { + return -ENOMEM; + } + + unix_fill_in_inode(tmp_inode, pUnixFindData, &object_type); + rc = filldir(direntry, pUnixFindData->FileName, pqstring->len, + file->f_pos, tmp_inode->i_ino, object_type); + if(rc) { + /* due to readdir error we need to recalculate resume + key so next readdir will restart on right entry */ + cFYI(1,("Error %d on filldir of %s",rc ,pUnixFindData->FileName)); + } + dput(tmp_dentry); + return rc; +} + +int +cifs_readdir(struct file *file, void *direntry, filldir_t filldir) +{ + int rc = 0; + int xid; + int Unicode = FALSE; + int UnixSearch = FALSE; + unsigned int bufsize, i; + __u16 searchHandle; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct cifsFileInfo *cifsFile = NULL; + char *full_path = NULL; + char *data; + struct qstr qstring; + T2_FFIRST_RSP_PARMS findParms; + T2_FNEXT_RSP_PARMS findNextParms; + FILE_DIRECTORY_INFO *pfindData; + FILE_DIRECTORY_INFO *lastFindData; + FILE_UNIX_INFO *pfindDataUnix; + + xid = GetXid(); + + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + pTcon = cifs_sb->tcon; + bufsize = pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; + if(bufsize > CIFS_MAX_MSGSIZE) { + FreeXid(xid); + return -EIO; + } + data = kmalloc(bufsize, GFP_KERNEL); + pfindData = (FILE_DIRECTORY_INFO *) data; + + if(file->f_dentry == NULL) { + FreeXid(xid); + return -EIO; + } + down(&file->f_dentry->d_sb->s_vfs_rename_sem); + full_path = build_wildcard_path_from_dentry(file->f_dentry); + up(&file->f_dentry->d_sb->s_vfs_rename_sem); + + + cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos)); + + switch ((int) file->f_pos) { + case 0: + if (filldir(direntry, ".", 1, file->f_pos, + file->f_dentry->d_inode->i_ino, DT_DIR) < 0) { + cERROR(1, ("Filldir for current dir failed ")); + break; + } + file->f_pos++; + /* fallthrough */ + case 1: + if (filldir(direntry, "..", 2, file->f_pos, + file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { + cERROR(1, ("Filldir for parent dir failed ")); + break; + } + file->f_pos++; + /* fallthrough */ + case 2: + if (file->private_data != NULL) { + cifsFile = + (struct cifsFileInfo *) file->private_data; + if (cifsFile->endOfSearch) { + if(cifsFile->emptyDir) { + cFYI(1, ("End of search, empty dir")); + rc = 0; + break; + } + } else { + cifsFile->invalidHandle = TRUE; + CIFSFindClose(xid, pTcon, cifsFile->netfid); + } + if(cifsFile->search_resume_name) { + kfree(cifsFile->search_resume_name); + cifsFile->search_resume_name = NULL; + } + } + rc = CIFSFindFirst(xid, pTcon, full_path, pfindData, + &findParms, cifs_sb->local_nls, + &Unicode, &UnixSearch); + cFYI(1, ("Count: %d End: %d ", findParms.SearchCount, + findParms.EndofSearch)); + + if (rc == 0) { + searchHandle = findParms.SearchHandle; + if(file->private_data == NULL) + file->private_data = + kmalloc(sizeof(struct cifsFileInfo),GFP_KERNEL); + if (file->private_data) { + memset(file->private_data, 0, + sizeof (struct cifsFileInfo)); + cifsFile = + (struct cifsFileInfo *) file->private_data; + cifsFile->netfid = searchHandle; + cifsFile->invalidHandle = FALSE; + init_MUTEX(&cifsFile->fh_sem); + } else { + rc = -ENOMEM; + break; + } + + renew_parental_timestamps(file->f_dentry); + lastFindData = + (FILE_DIRECTORY_INFO *) ((char *) pfindData + + findParms.LastNameOffset); + if((char *)lastFindData > (char *)pfindData + bufsize) { + cFYI(1,("last search entry past end of packet")); + rc = -EIO; + break; + } + /* Offset of resume key same for levels 257 and 514 */ + cifsFile->resume_key = lastFindData->FileIndex; + if(UnixSearch == FALSE) { + cifsFile->resume_name_length = + le32_to_cpu(lastFindData->FileNameLength); + if(cifsFile->resume_name_length > bufsize - 64) { + cFYI(1,("Illegal resume file name length %d", + cifsFile->resume_name_length)); + rc = -ENOMEM; + break; + } + cifsFile->search_resume_name = + kmalloc(cifsFile->resume_name_length, GFP_KERNEL); + cFYI(1,("Last file: %s with name %d bytes long", + lastFindData->FileName, + cifsFile->resume_name_length)); + memcpy(cifsFile->search_resume_name, + lastFindData->FileName, + cifsFile->resume_name_length); + } else { + pfindDataUnix = (FILE_UNIX_INFO *)lastFindData; + if (Unicode == TRUE) { + for(i=0;(pfindDataUnix->FileName[i] + | pfindDataUnix->FileName[i+1]); + i+=2) { + if(i > bufsize-64) + break; + } + cifsFile->resume_name_length = i + 2; + } else { + cifsFile->resume_name_length = + strnlen(pfindDataUnix->FileName, + bufsize-63); + } + if(cifsFile->resume_name_length > bufsize - 64) { + cFYI(1,("Illegal resume file name length %d", + cifsFile->resume_name_length)); + rc = -ENOMEM; + break; + } + cifsFile->search_resume_name = + kmalloc(cifsFile->resume_name_length, GFP_KERNEL); + cFYI(1,("Last file: %s with name %d bytes long", + pfindDataUnix->FileName, + cifsFile->resume_name_length)); + memcpy(cifsFile->search_resume_name, + pfindDataUnix->FileName, + cifsFile->resume_name_length); + } + for (i = 2; i < (unsigned int)findParms.SearchCount + 2; i++) { + if (UnixSearch == FALSE) { + pfindData->FileNameLength = + le32_to_cpu(pfindData->FileNameLength); + if (Unicode == TRUE) + pfindData->FileNameLength = + cifs_strfromUCS_le + (pfindData->FileName, + (wchar_t *) + pfindData->FileName, + (pfindData-> + FileNameLength) / 2, + cifs_sb->local_nls); + qstring.len = pfindData->FileNameLength; + if (((qstring.len != 1) + || (pfindData->FileName[0] != '.')) + && ((qstring.len != 2) + || (pfindData-> + FileName[0] != '.') + || (pfindData-> + FileName[1] != '.'))) { + if(cifs_filldir(&qstring, + pfindData, + file, filldir, + direntry)) { + /* do not end search if + kernel not ready to take + remaining entries yet */ + reset_resume_key(file, pfindData->FileName,qstring.len, + Unicode, cifs_sb->local_nls); + findParms.EndofSearch = 0; + break; + } + file->f_pos++; + } + } else { /* UnixSearch */ + pfindDataUnix = + (FILE_UNIX_INFO *) pfindData; + if (Unicode == TRUE) + qstring.len = + cifs_strfromUCS_le + (pfindDataUnix->FileName, + (wchar_t *) + pfindDataUnix->FileName, + MAX_PATHCONF, + cifs_sb->local_nls); + else + qstring.len = + strnlen(pfindDataUnix-> + FileName, + MAX_PATHCONF); + if (((qstring.len != 1) + || (pfindDataUnix-> + FileName[0] != '.')) + && ((qstring.len != 2) + || (pfindDataUnix-> + FileName[0] != '.') + || (pfindDataUnix-> + FileName[1] != '.'))) { + if(cifs_filldir_unix(&qstring, + pfindDataUnix, + file, + filldir, + direntry)) { + /* do not end search if + kernel not ready to take + remaining entries yet */ + findParms.EndofSearch = 0; + reset_resume_key(file, pfindDataUnix->FileName, + qstring.len,Unicode,cifs_sb->local_nls); + break; + } + file->f_pos++; + } + } + /* works also for Unix ff struct since first field of both */ + pfindData = + (FILE_DIRECTORY_INFO *) ((char *) pfindData + + le32_to_cpu(pfindData->NextEntryOffset)); + /* BB also should check to make sure that pointer is not beyond the end of the SMB */ + /* if(pfindData > lastFindData) rc = -EIO; break; */ + } /* end for loop */ + if ((findParms.EndofSearch != 0) && cifsFile) { + cifsFile->endOfSearch = TRUE; + if(findParms.SearchCount == 2) + cifsFile->emptyDir = TRUE; + } + } else { + if (cifsFile) + cifsFile->endOfSearch = TRUE; + /* unless parent directory gone do not return error */ + rc = 0; + } + break; + default: + if (file->private_data == NULL) { + rc = -EBADF; + cFYI(1, + ("Readdir on closed srch, pos = %lld", + file->f_pos)); + } else { + cifsFile = (struct cifsFileInfo *) file->private_data; + if (cifsFile->endOfSearch) { + rc = 0; + cFYI(1, ("End of search ")); + break; + } + searchHandle = cifsFile->netfid; + rc = CIFSFindNext(xid, pTcon, pfindData, + &findNextParms, searchHandle, + cifsFile->search_resume_name, + cifsFile->resume_name_length, + cifsFile->resume_key, + &Unicode, &UnixSearch); + cFYI(1,("Count: %d End: %d ", + findNextParms.SearchCount, + findNextParms.EndofSearch)); + if ((rc == 0) && (findNextParms.SearchCount != 0)) { + /* BB save off resume key, key name and name length */ + lastFindData = + (FILE_DIRECTORY_INFO *) ((char *) pfindData + + findNextParms.LastNameOffset); + if((char *)lastFindData > (char *)pfindData + bufsize) { + cFYI(1,("last search entry past end of packet")); + rc = -EIO; + break; + } + /* Offset of resume key same for levels 257 and 514 */ + cifsFile->resume_key = lastFindData->FileIndex; + + if(UnixSearch == FALSE) { + cifsFile->resume_name_length = + le32_to_cpu(lastFindData->FileNameLength); + if(cifsFile->resume_name_length > bufsize - 64) { + cFYI(1,("Illegal resume file name length %d", + cifsFile->resume_name_length)); + rc = -ENOMEM; + break; + } + /* Free the memory allocated by previous findfirst + or findnext call - we can not reuse the memory since + the resume name may not be same string length */ + if(cifsFile->search_resume_name) + kfree(cifsFile->search_resume_name); + cifsFile->search_resume_name = + kmalloc(cifsFile->resume_name_length, GFP_KERNEL); + cFYI(1,("Last file: %s with name %d bytes long", + lastFindData->FileName, + cifsFile->resume_name_length)); + memcpy(cifsFile->search_resume_name, + lastFindData->FileName, + cifsFile->resume_name_length); + } else { + pfindDataUnix = (FILE_UNIX_INFO *)lastFindData; + if (Unicode == TRUE) { + for(i=0;(pfindDataUnix->FileName[i] + | pfindDataUnix->FileName[i+1]); + i+=2) { + if(i > bufsize-64) + break; + } + cifsFile->resume_name_length = i + 2; + } else { + cifsFile->resume_name_length = + strnlen(pfindDataUnix-> + FileName, + MAX_PATHCONF); + } + if(cifsFile->resume_name_length > bufsize - 64) { + cFYI(1,("Illegal resume file name length %d", + cifsFile->resume_name_length)); + rc = -ENOMEM; + break; + } + /* Free the memory allocated by previous findfirst + or findnext call - we can not reuse the memory since + the resume name may not be same string length */ + if(cifsFile->search_resume_name) + kfree(cifsFile->search_resume_name); + cifsFile->search_resume_name = + kmalloc(cifsFile->resume_name_length, GFP_KERNEL); + cFYI(1,("fnext last file: %s with name %d bytes long", + pfindDataUnix->FileName, + cifsFile->resume_name_length)); + memcpy(cifsFile->search_resume_name, + pfindDataUnix->FileName, + cifsFile->resume_name_length); + } + + for (i = 0; i < findNextParms.SearchCount; i++) { + pfindData->FileNameLength = + le32_to_cpu(pfindData-> + FileNameLength); + if (UnixSearch == FALSE) { + if (Unicode == TRUE) + pfindData->FileNameLength = + cifs_strfromUCS_le + (pfindData->FileName, + (wchar_t *) + pfindData->FileName, + (pfindData->FileNameLength)/ 2, + cifs_sb->local_nls); + qstring.len = + pfindData->FileNameLength; + if (((qstring.len != 1) + || (pfindData->FileName[0] != '.')) + && ((qstring.len != 2) + || (pfindData->FileName[0] != '.') + || (pfindData->FileName[1] != + '.'))) { + if(cifs_filldir + (&qstring, + pfindData, + file, filldir, + direntry)) { + /* do not end search if + kernel not ready to take + remaining entries yet */ + findNextParms.EndofSearch = 0; + reset_resume_key(file, pfindData->FileName,qstring.len, + Unicode,cifs_sb->local_nls); + break; + } + file->f_pos++; + } + } else { /* UnixSearch */ + pfindDataUnix = + (FILE_UNIX_INFO *) + pfindData; + if (Unicode == TRUE) + qstring.len = + cifs_strfromUCS_le + (pfindDataUnix->FileName, + (wchar_t *) + pfindDataUnix->FileName, + MAX_PATHCONF, + cifs_sb->local_nls); + else + qstring.len = + strnlen + (pfindDataUnix-> + FileName, + MAX_PATHCONF); + if (((qstring.len != 1) + || (pfindDataUnix-> + FileName[0] != '.')) + && ((qstring.len != 2) + || (pfindDataUnix-> + FileName[0] != '.') + || (pfindDataUnix-> + FileName[1] != + '.'))) { + if(cifs_filldir_unix + (&qstring, + pfindDataUnix, + file, filldir, + direntry)) { + /* do not end search if + kernel not ready to take + remaining entries yet */ + findNextParms.EndofSearch = 0; + reset_resume_key(file, pfindDataUnix->FileName,qstring.len, + Unicode,cifs_sb->local_nls); + break; + } + file->f_pos++; + } + } + pfindData = (FILE_DIRECTORY_INFO *) ((char *) pfindData + le32_to_cpu(pfindData->NextEntryOffset)); /* works also for Unix find struct since this is the first field of both */ + /* BB also should check to make sure that pointer is not beyond the end of the SMB */ + } /* end for loop */ + if (findNextParms.EndofSearch != 0) { + cifsFile->endOfSearch = TRUE; + } + } else { + cifsFile->endOfSearch = TRUE; + rc = 0; /* unless parent directory disappeared - do not return error here (eg Access Denied or no more files) */ + } + } + } /* end switch */ + if (data) + kfree(data); + if (full_path) + kfree(full_path); + FreeXid(xid); + + return rc; +} +int cifs_prepare_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + int rc = 0; + loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; + cFYI(1,("prepare write for page %p from %d to %d",page,from,to)); + if (!Page_Uptodate(page)) { + /* if (to - from != PAGE_CACHE_SIZE) { + void *kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr, 0, from); + memset(kaddr + to, 0, PAGE_CACHE_SIZE - to); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + } */ + /* If we are writing a full page it will be up to date, + no need to read from the server */ + if((to==PAGE_CACHE_SIZE) && (from == 0)) + SetPageUptodate(page); + + /* might as well read a page, it is fast enough */ + if((file->f_flags & O_ACCMODE) != O_WRONLY) { + rc = cifs_readpage_worker(file,page,&offset); + } else { + /* should we try using another + file handle if there is one - how would we lock it + to prevent close of that handle racing with this read? */ + /* In any case this will be written out by commit_write */ + } + } + + /* BB should we pass any errors back? e.g. if we do not have read access to the file */ + return 0; +} + + +struct address_space_operations cifs_addr_ops = { + .readpage = cifs_readpage, +/* .readpages = cifs_readpages, */ + .writepage = cifs_writepage, + .prepare_write = cifs_prepare_write, + .commit_write = cifs_commit_write, + .sync_page = cifs_sync_page, + /*.direct_IO = */ +}; diff --git a/release/src/linux/linux/fs/cifs/inode.c b/release/src/linux/linux/fs/cifs/inode.c new file mode 100644 index 00000000..dce55552 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/inode.c @@ -0,0 +1,1079 @@ +/* + * fs/cifs/inode.c + * + * Copyright (C) International Business Machines Corp., 2002,2003 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/fs.h> +#include <linux/stat.h> +#include <linux/pagemap.h> +#include <linux/version.h> +#include <asm/div64.h> +#include "cifsfs.h" +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_debug.h" +#include "cifs_fs_sb.h" + +extern int is_size_safe_to_change(struct cifsInodeInfo *); + +struct inode * get_cifs_inode(struct super_block * sb) +{ + struct inode * newinode; + newinode = new_inode(sb); + cFYI(1,("got new inode %p",newinode)); + if(newinode) { + struct cifsInodeInfo * cifsInfo = CIFS_I(newinode); + cifsInfo->clientCanCacheRead = FALSE; + cifsInfo->clientCanCacheAll = FALSE; + INIT_LIST_HEAD(&cifsInfo->openFileList); + cifsInfo->cifsAttrs = 0x20; /* default */ + newinode->i_blksize = CIFS_MAX_MSGSIZE; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15)) + newinode->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ +#endif + atomic_set(&cifsInfo->inUse, 0); + cifsInfo->time = 0; + insert_inode_hash(newinode); + } + return newinode; + +} + +int +cifs_get_inode_info_unix(struct inode **pinode, + const unsigned char *search_path, + struct super_block *sb,int xid) +{ + int rc = 0; + FILE_UNIX_BASIC_INFO findData; + struct cifsTconInfo *pTcon; + struct inode *inode; + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + char *tmp_path; + + pTcon = cifs_sb->tcon; + cFYI(1, (" Getting info on %s ", search_path)); + /* we could have done a find first instead but this returns more info */ + rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData, + cifs_sb->local_nls); + /* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */ + if (rc) { + if (rc == -EREMOTE) { + tmp_path = + kmalloc(strnlen + (pTcon->treeName, + MAX_TREE_SIZE + 1) + + strnlen(search_path, MAX_PATHCONF) + 1, + GFP_KERNEL); + if (tmp_path == NULL) { + return -ENOMEM; + } + /* have to skip first of the double backslash of UNC name */ + strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); + strncat(tmp_path, search_path, MAX_PATHCONF); + rc = connect_to_dfs_path(xid, pTcon->ses, + /* treename + */ tmp_path, + cifs_sb->local_nls); + kfree(tmp_path); + + /* BB fix up inode etc. */ + } else if (rc) { + return rc; + } + + } else { + struct cifsInodeInfo *cifsInfo; + + /* get new inode */ + if (*pinode == NULL) { + *pinode = get_cifs_inode(sb); + } + if(*pinode == NULL) { + return -ENOMEM; + } + + inode = *pinode; + cifsInfo = CIFS_I(inode); + + cFYI(1, (" Old time %ld ", cifsInfo->time)); + cifsInfo->time = jiffies; + cFYI(1, (" New time %ld ", cifsInfo->time)); + atomic_set(&cifsInfo->inUse,1); /* ok to set on every refresh of inode */ + + inode->i_atime = + cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime)); + inode->i_mtime = + cifs_NTtimeToUnix(le64_to_cpu + (findData.LastModificationTime)); + inode->i_ctime = + cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange)); + inode->i_mode = le64_to_cpu(findData.Permissions); + findData.Type = le32_to_cpu(findData.Type); + if (findData.Type == UNIX_FILE) { + inode->i_mode |= S_IFREG; + } else if (findData.Type == UNIX_SYMLINK) { + inode->i_mode |= S_IFLNK; + } else if (findData.Type == UNIX_DIR) { + inode->i_mode |= S_IFDIR; + } else if (findData.Type == UNIX_CHARDEV) { + inode->i_mode |= S_IFCHR; + inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor), + le64_to_cpu(findData.DevMinor) & MINORMASK); + } else if (findData.Type == UNIX_BLOCKDEV) { + inode->i_mode |= S_IFBLK; + inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor), + le64_to_cpu(findData.DevMinor) & MINORMASK); + } else if (findData.Type == UNIX_FIFO) { + inode->i_mode |= S_IFIFO; + } else if (findData.Type == UNIX_SOCKET) { + inode->i_mode |= S_IFSOCK; + } + inode->i_uid = le64_to_cpu(findData.Uid); + inode->i_gid = le64_to_cpu(findData.Gid); + inode->i_nlink = le64_to_cpu(findData.Nlinks); + findData.NumOfBytes = le64_to_cpu(findData.NumOfBytes); + findData.EndOfFile = le64_to_cpu(findData.EndOfFile); + + if(is_size_safe_to_change(cifsInfo)) { + /* can not safely change the file size here if the + client is writing to it due to potential races */ + inode->i_size = findData.EndOfFile; +/* blksize needs to be multiple of two. So safer to default to blksize + and blkbits set in superblock so 2**blkbits and blksize will match */ +/* inode->i_blksize = + (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ + + /* This seems incredibly stupid but it turns out that + i_blocks is not related to (i_size / i_blksize), instead a + size of 512 is required to be used for calculating num blocks */ + + +/* inode->i_blocks = + (inode->i_blksize - 1 + findData.NumOfBytes) >> inode->i_blkbits;*/ + + /* 512 bytes (2**9) is the fake blocksize that must be used */ + /* for this calculation */ + inode->i_blocks = (512 - 1 + findData.NumOfBytes) >> 9; + } + + if (findData.NumOfBytes < findData.EndOfFile) + cFYI(1, ("Server inconsistency Error: it says allocation size less than end of file ")); + cFYI(1, + ("Size %ld and blocks %ld ", + (unsigned long) inode->i_size, inode->i_blocks)); + if (S_ISREG(inode->i_mode)) { + cFYI(1, (" File inode ")); + inode->i_op = &cifs_file_inode_ops; + inode->i_fop = &cifs_file_ops; + inode->i_data.a_ops = &cifs_addr_ops; + } else if (S_ISDIR(inode->i_mode)) { + cFYI(1, (" Directory inode")); + inode->i_op = &cifs_dir_inode_ops; + inode->i_fop = &cifs_dir_ops; + } else if (S_ISLNK(inode->i_mode)) { + cFYI(1, (" Symbolic Link inode ")); + inode->i_op = &cifs_symlink_inode_ops; +/* tmp_inode->i_fop = *//* do not need to set to anything */ + } else { + cFYI(1, (" Init special inode ")); + init_special_inode(inode, inode->i_mode, + kdev_t_to_nr(inode->i_rdev)); + } + } + return rc; +} + +int +cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, + FILE_ALL_INFO * pfindData, struct super_block *sb, int xid) +{ + int rc = 0; + struct cifsTconInfo *pTcon; + struct inode *inode; + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + char *tmp_path; + char *buf = NULL; + + pTcon = cifs_sb->tcon; + cFYI(1,("Getting info on %s ", search_path)); + + if((pfindData == NULL) && (*pinode != NULL)) { + if(CIFS_I(*pinode)->clientCanCacheRead) { + cFYI(1,("No need to revalidate inode sizes on cached file ")); + return rc; + } + } + + /* if file info not passed in then get it from server */ + if(pfindData == NULL) { + buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); + pfindData = (FILE_ALL_INFO *)buf; + /* could do find first instead but this returns more info */ + rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, + cifs_sb->local_nls); + } + /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ + if (rc) { + if (rc == -EREMOTE) { + tmp_path = + kmalloc(strnlen + (pTcon->treeName, + MAX_TREE_SIZE + 1) + + strnlen(search_path, MAX_PATHCONF) + 1, + GFP_KERNEL); + if (tmp_path == NULL) { + if(buf) + kfree(buf); + return -ENOMEM; + } + + strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); + strncat(tmp_path, search_path, MAX_PATHCONF); + rc = connect_to_dfs_path(xid, pTcon->ses, + /* treename + */ tmp_path, + cifs_sb->local_nls); + kfree(tmp_path); + /* BB fix up inode etc. */ + } else if (rc) { + if(buf) + kfree(buf); + return rc; + } + } else { + struct cifsInodeInfo *cifsInfo; + + /* get new inode */ + if (*pinode == NULL) { + *pinode = get_cifs_inode(sb); + } + if(*pinode == NULL) + return -ENOMEM; + inode = *pinode; + cifsInfo = CIFS_I(inode); + pfindData->Attributes = le32_to_cpu(pfindData->Attributes); + cifsInfo->cifsAttrs = pfindData->Attributes; + cFYI(1, (" Old time %ld ", cifsInfo->time)); + cifsInfo->time = jiffies; + cFYI(1, (" New time %ld ", cifsInfo->time)); + +/* blksize needs to be multiple of two. So safer to default to blksize + and blkbits set in superblock so 2**blkbits and blksize will match */ +/* inode->i_blksize = + (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ + + /* Linux can not store file creation time unfortunately so we ignore it */ + inode->i_atime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); + inode->i_mtime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); + inode->i_ctime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); + cFYI(0, + (" Attributes came in as 0x%x ", pfindData->Attributes)); + + /* set default mode. will override for dirs below */ + if(atomic_read(&cifsInfo->inUse) == 0) + /* new inode, can safely set these fields */ + inode->i_mode = cifs_sb->mnt_file_mode; + + if (pfindData->Attributes & ATTR_REPARSE) { + /* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */ + inode->i_mode |= S_IFLNK; + } else if (pfindData->Attributes & ATTR_DIRECTORY) { + /* override default perms since we do not do byte range locking on dirs */ + inode->i_mode = cifs_sb->mnt_dir_mode; + inode->i_mode |= S_IFDIR; + } else { + inode->i_mode |= S_IFREG; + /* treat the dos attribute of read-only as read-only mode e.g. 555 */ + if(cifsInfo->cifsAttrs & ATTR_READONLY) + inode->i_mode &= ~(S_IWUGO); + /* BB add code here - validate if device or weird share or device type? */ + } + if(is_size_safe_to_change(cifsInfo)) { + /* can not safely change the file size here if the + client is writing to it due to potential races */ + inode->i_size = le64_to_cpu(pfindData->EndOfFile); + + /* 512 bytes (2**9) is the fake blocksize that must be used */ + /* for this calculation */ + inode->i_blocks = (512 - 1 + pfindData->AllocationSize) + >> 9; + } + pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize); + + cFYI(1, + (" Size %ld and blocks %ld ", + (unsigned long) inode->i_size, inode->i_blocks)); + inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); + + /* BB fill in uid and gid here? with help from winbind? + or retrieve from NTFS stream extended attribute */ + if(atomic_read(&cifsInfo->inUse) == 0) { + inode->i_uid = cifs_sb->mnt_uid; + inode->i_gid = cifs_sb->mnt_gid; + /* set so we do not keep refreshing these fields with + bad data after user has changed them in memory */ + atomic_set(&cifsInfo->inUse,1); + } + + if (S_ISREG(inode->i_mode)) { + cFYI(1, (" File inode ")); + inode->i_op = &cifs_file_inode_ops; + inode->i_fop = &cifs_file_ops; + inode->i_data.a_ops = &cifs_addr_ops; + } else if (S_ISDIR(inode->i_mode)) { + cFYI(1, (" Directory inode ")); + inode->i_op = &cifs_dir_inode_ops; + inode->i_fop = &cifs_dir_ops; + } else if (S_ISLNK(inode->i_mode)) { + cFYI(1, (" Symbolic Link inode ")); + inode->i_op = &cifs_symlink_inode_ops; + } else { + init_special_inode(inode, inode->i_mode, + kdev_t_to_nr(inode->i_rdev)); + } + } + if(buf) + kfree(buf); + return rc; +} + +void +cifs_read_inode(struct inode *inode) +{ /* gets root inode */ + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsInodeInfo *cifs_inode; + + cifs_sb = CIFS_SB(inode->i_sb); + xid = GetXid(); + + cifs_inode = CIFS_I(inode); + cifs_inode->cifsAttrs = ATTR_DIRECTORY; + atomic_set(&cifs_inode->inUse, 0); + cifs_inode->time = 0; + inode->i_blksize = CIFS_MAX_MSGSIZE; + inode->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ + + INIT_LIST_HEAD(&cifs_inode->openFileList); + + if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) + cifs_get_inode_info_unix(&inode, "", inode->i_sb,xid); + else + cifs_get_inode_info(&inode, "", NULL, inode->i_sb,xid); + /* can not call macro FreeXid here since in a void func */ + _FreeXid(xid); +} + +int +cifs_unlink(struct inode *inode, struct dentry *direntry) +{ + int rc = 0; + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + char *full_path = NULL; + struct cifsInodeInfo *cifsInode; + FILE_BASIC_INFO * pinfo_buf; + + cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode)); + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + +/* Unlink can be called from rename so we can not grab + the sem here since we deadlock otherwise */ +/* down(&direntry->d_sb->s_vfs_rename_sem);*/ + full_path = build_path_from_dentry(direntry); +/* up(&direntry->d_sb->s_vfs_rename_sem);*/ + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls); + + if (!rc) { + direntry->d_inode->i_nlink--; + } else if (rc == -ENOENT) { + d_drop(direntry); + } else if (rc == -ETXTBSY) { + int oplock = FALSE; + __u16 netfid; + + rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, + CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, + &netfid, &oplock, NULL, cifs_sb->local_nls); + if(rc==0) { + CIFSSMBRenameOpenFile(xid,pTcon,netfid, + NULL, cifs_sb->local_nls); + CIFSSMBClose(xid, pTcon, netfid); + direntry->d_inode->i_nlink--; + } + } else if (rc == -EACCES) { + /* try only if r/o attribute set in local lookup data? */ + pinfo_buf = (FILE_BASIC_INFO *)kmalloc(sizeof(FILE_BASIC_INFO),GFP_KERNEL); + if(pinfo_buf) { + memset(pinfo_buf,0,sizeof(FILE_BASIC_INFO)); + /* ATTRS set to normal clears r/o bit */ + pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL); + rc = CIFSSMBSetTimes(xid, pTcon, full_path, pinfo_buf, + cifs_sb->local_nls); + kfree(pinfo_buf); + } + if(rc==0) { + rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls); + if (!rc) { + direntry->d_inode->i_nlink--; + } else if (rc == -ETXTBSY) { + int oplock = FALSE; + __u16 netfid; + + rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, + CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, + &netfid, &oplock, NULL, cifs_sb->local_nls); + if(rc==0) { + CIFSSMBRenameOpenFile(xid,pTcon,netfid,NULL,cifs_sb->local_nls); + CIFSSMBClose(xid, pTcon, netfid); + direntry->d_inode->i_nlink--; + } + /* BB if rc = -ETXTBUSY goto the rename logic BB */ + } + } + } + cifsInode = CIFS_I(direntry->d_inode); + cifsInode->time = 0; /* will force revalidate to get info when needed */ + direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime = + CURRENT_TIME; + cifsInode = CIFS_I(inode); + cifsInode->time = 0; /* force revalidate of dir as well */ + + if (full_path) + kfree(full_path); + FreeXid(xid); + return rc; +} + +int +cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) +{ + int rc = 0; + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + char *full_path = NULL; + struct inode *newinode = NULL; + + cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode)); + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + + down(&inode->i_sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(direntry); + up(&inode->i_sb->s_vfs_rename_sem); + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + /* BB add setting the equivalent of mode via CreateX w/ACLs */ + rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls); + if (rc) { + cFYI(1, ("cifs_mkdir returned 0x%x ", rc)); + d_drop(direntry); + } else { + inode->i_nlink++; + if (pTcon->ses->capabilities & CAP_UNIX) + rc = cifs_get_inode_info_unix(&newinode, full_path, + inode->i_sb,xid); + else + rc = cifs_get_inode_info(&newinode, full_path,NULL, + inode->i_sb,xid); + + direntry->d_op = &cifs_dentry_ops; + d_instantiate(direntry, newinode); + if(direntry->d_inode) + direntry->d_inode->i_nlink = 2; + if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) + CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, + (__u64)-1, + (__u64)-1, + 0 /* dev_t */, + cifs_sb->local_nls); + else { /* BB to be implemented via Windows secrty descriptors*/ + /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ + } + } + if (full_path) + kfree(full_path); + FreeXid(xid); + + return rc; +} + +int +cifs_rmdir(struct inode *inode, struct dentry *direntry) +{ + int rc = 0; + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + char *full_path = NULL; + struct cifsInodeInfo *cifsInode; + + cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode)); + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + + down(&inode->i_sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(direntry); + up(&inode->i_sb->s_vfs_rename_sem); + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + + rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls); + + if (!rc) { + inode->i_nlink--; + direntry->d_inode->i_size = 0; + direntry->d_inode->i_nlink = 0; + } + + cifsInode = CIFS_I(direntry->d_inode); + cifsInode->time = 0; /* force revalidate to go get info when needed */ + direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime = + CURRENT_TIME; + + if (full_path) + kfree(full_path); + FreeXid(xid); + return rc; +} + +int +cifs_rename(struct inode *source_inode, struct dentry *source_direntry, + struct inode *target_inode, struct dentry *target_direntry) +{ + char *fromName; + char *toName; + struct cifs_sb_info *cifs_sb_source; + struct cifs_sb_info *cifs_sb_target; + struct cifsTconInfo *pTcon; + int xid; + int rc = 0; + + xid = GetXid(); + + cifs_sb_target = CIFS_SB(target_inode->i_sb); + cifs_sb_source = CIFS_SB(source_inode->i_sb); + pTcon = cifs_sb_source->tcon; + + if (pTcon != cifs_sb_target->tcon) { + FreeXid(xid); + return -EXDEV; /* BB actually could be allowed if same server, but + different share. Might eventually add support for this */ + } + + /* we already have the rename sem so we do not need + to grab it again here to protect the path integrity */ + fromName = build_path_from_dentry(source_direntry); + toName = build_path_from_dentry(target_direntry); + if((fromName == NULL) || (toName == NULL)) { + rc = -ENOMEM; + goto cifs_rename_exit; + } + + rc = CIFSSMBRename(xid, pTcon, fromName, toName, + cifs_sb_source->local_nls); + if(rc == -EEXIST) { + /* check if they are the same file + because rename of hardlinked files is a noop */ + FILE_UNIX_BASIC_INFO * info_buf_source; + FILE_UNIX_BASIC_INFO * info_buf_target; + + info_buf_source = + kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),GFP_KERNEL); + if(info_buf_source != NULL) { + info_buf_target = info_buf_source+1; + rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName, + info_buf_source, cifs_sb_source->local_nls); + if(rc == 0) { + rc = CIFSSMBUnixQPathInfo(xid,pTcon,toName, + info_buf_target, + cifs_sb_target->local_nls); + } + if((rc == 0) && + (info_buf_source->UniqueId == + info_buf_target->UniqueId)) { + /* do not rename since the files are hardlinked + which is a noop */ + } else { + /* we either can not tell the files are hardlinked + (as with Windows servers) or files are not hardlinked + so delete the target manually before renaming to + follow POSIX rather than Windows semantics */ + cifs_unlink(target_inode, target_direntry); + rc = CIFSSMBRename(xid, pTcon, fromName, toName, + cifs_sb_source->local_nls); + } + kfree(info_buf_source); + } /* if we can not get memory just leave rc as EEXIST */ + } + + if((rc == -EIO)||(rc == -EEXIST)) { + int oplock = FALSE; + __u16 netfid; + + rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ, + CREATE_NOT_DIR, + &netfid, &oplock, NULL, cifs_sb_source->local_nls); + if(rc==0) { + CIFSSMBRenameOpenFile(xid,pTcon,netfid, + toName, cifs_sb_source->local_nls); + CIFSSMBClose(xid, pTcon, netfid); + } + } + +cifs_rename_exit: + if (fromName) + kfree(fromName); + if (toName) + kfree(toName); + + FreeXid(xid); + return rc; +} + +int +cifs_revalidate(struct dentry *direntry) +{ + int xid; + int rc = 0; + char *full_path; + struct cifs_sb_info *cifs_sb; + struct cifsInodeInfo *cifsInode; + loff_t local_size; + time_t local_mtime; + int invalidate_inode = FALSE; + + if(direntry->d_inode == NULL) + return -ENOENT; + + cifsInode = CIFS_I(direntry->d_inode); + + if(cifsInode == NULL) + return -ENOENT; + + /* no sense revalidating inode info on file that no one can write */ + if(CIFS_I(direntry->d_inode)->clientCanCacheRead) + return rc; + + xid = GetXid(); + + cifs_sb = CIFS_SB(direntry->d_sb); + + /* can not safely grab the rename sem here if + rename calls revalidate since that would deadlock */ + full_path = build_path_from_dentry(direntry); + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + cFYI(1, + ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld", + full_path, direntry->d_inode, + direntry->d_inode->i_count.counter, direntry, + direntry->d_time, jiffies)); + + if (cifsInode->time == 0){ + /* was set to zero previously to force revalidate */ + } else if (time_before(jiffies, cifsInode->time + HZ) && lookupCacheEnabled) { + if((S_ISREG(direntry->d_inode->i_mode) == 0) || + (direntry->d_inode->i_nlink == 1)) { + if (full_path) + kfree(full_path); + FreeXid(xid); + return rc; + } else { + cFYI(1,("Have to revalidate file due to hardlinks")); + } + } + + /* save mtime and size */ + local_mtime = direntry->d_inode->i_mtime; + local_size = direntry->d_inode->i_size; + + if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) { + rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path, + direntry->d_sb,xid); + if(rc) { + cFYI(1,("error on getting revalidate info %d",rc)); +/* if(rc != -ENOENT) + rc = 0; */ /* BB should we cache info on certain errors? */ + } + } else { + rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL, + direntry->d_sb,xid); + if(rc) { + cFYI(1,("error on getting revalidate info %d",rc)); +/* if(rc != -ENOENT) + rc = 0; */ /* BB should we cache info on certain errors? */ + } + } + /* should we remap certain errors, access denied?, to zero */ + + /* if not oplocked, we invalidate inode pages if mtime + or file size had changed on server */ + + if((local_mtime == direntry->d_inode->i_mtime) && + (local_size == direntry->d_inode->i_size)) { + cFYI(1,("cifs_revalidate - inode unchanged")); + } else { + /* file may have changed on server */ + if(cifsInode->clientCanCacheRead) { + /* no need to invalidate inode pages since we were + the only ones who could have modified the file and + the server copy is staler than ours */ + } else { + invalidate_inode = TRUE; + } + } + + /* can not grab this sem since kernel filesys locking + documentation indicates i_sem may be taken by the kernel + on lookup and rename which could deadlock if we grab + the i_sem here as well */ +/* down(&direntry->d_inode->i_sem);*/ + /* need to write out dirty pages here */ + if(direntry->d_inode->i_mapping) { + /* do we need to lock inode until after invalidate completes below? */ + filemap_fdatasync(direntry->d_inode->i_mapping); + } + if(invalidate_inode) { + filemap_fdatawait(direntry->d_inode->i_mapping); + /* may eventually have to do this for open files too */ + if(list_empty(&(cifsInode->openFileList))) { + /* Has changed on server - flush read ahead pages */ + cFYI(1,("Invalidating read ahead data on closed file")); + invalidate_inode_pages(direntry->d_inode); + } + } +/* up(&direntry->d_inode->i_sem);*/ + + if (full_path) + kfree(full_path); + FreeXid(xid); + + return rc; +} + +/* int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) +{ + int err = cifs_revalidate(dentry); + if (!err) + generic_fillattr(dentry->d_inode, stat); + return err; +} */ + +void +cifs_truncate_file(struct inode *inode) +{ /* BB remove - may not need this function after all BB */ + int xid; + int rc = -EIO; + int found = FALSE; + struct cifsFileInfo *open_file = NULL; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct cifsInodeInfo *cifsInode; + struct dentry *dirent; + struct list_head * tmp; + char *full_path = NULL; + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + + /* To avoid spurious oplock breaks from server, in the case + of inodes that we already have open, avoid doing path + based setting of file size if we can do it by handle. + This keeps our caching token (oplock) and avoids + timeouts when the local oplock break takes longer to flush + writebehind data than the SMB timeout for the SetPathInfo + request would allow */ + read_lock(&GlobalSMBSeslock); + cifsInode = CIFS_I(inode); + list_for_each(tmp, &cifsInode->openFileList) { + open_file = list_entry(tmp,struct cifsFileInfo, flist); + /* We check if file is open for writing first */ + if((open_file->pfile) && (!open_file->invalidHandle) && + ((open_file->pfile->f_flags & O_RDWR) || + (open_file->pfile->f_flags & O_WRONLY))) { + read_unlock(&GlobalSMBSeslock); + found = TRUE; + rc = CIFSSMBSetFileSize(xid, pTcon, inode->i_size, + open_file->netfid,open_file->pid,FALSE); + if(rc == 0) { + FreeXid(xid); + return; + } + /* Do not need reopen and retry on EAGAIN since we will + retry by pathname below */ + if(rc == -EAGAIN) + rc = -EHOSTDOWN; + + break; /* now that we found one valid file handle no + sense continuing to loop trying others */ + } + } + if(found == FALSE) + read_unlock(&GlobalSMBSeslock); + + if (list_empty(&inode->i_dentry)) { + cERROR(1, + ("Can not get pathname from empty dentry in inode 0x%p ", + inode)); + FreeXid(xid); + return; + } + + dirent = list_entry(inode->i_dentry.next, struct dentry, d_alias); + if (dirent) { + full_path = build_path_from_dentry(dirent); + rc = CIFSSMBSetEOF(xid, pTcon, full_path, inode->i_size,FALSE, + cifs_sb->local_nls); + cFYI(1,(" SetEOF (truncate) rc = %d",rc)); + if (!rc) + CIFSSMBSetEOF(xid,pTcon,full_path,inode->i_size,TRUE,cifs_sb->local_nls); + /* allocation size setting seems optional so ignore return code */ + } + if (full_path) + kfree(full_path); + FreeXid(xid); + return; +} + +static int cifs_truncate_page(struct address_space *mapping, loff_t from) +{ + unsigned long index = from >> PAGE_CACHE_SHIFT; + unsigned offset = from & (PAGE_CACHE_SIZE-1); + struct page *page; + char *kaddr; + int rc = 0; + + page = grab_cache_page(mapping, index); + if (!page) + return -ENOMEM; + + kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + unlock_page(page); + page_cache_release(page); + return rc; +} + +int +cifs_setattr(struct dentry *direntry, struct iattr *attrs) +{ + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + char *full_path = NULL; + int rc = -EACCES; + int found = FALSE; + struct cifsFileInfo *open_file = NULL; + FILE_BASIC_INFO time_buf; + int set_time = FALSE; + __u64 mode = 0xFFFFFFFFFFFFFFFFULL; + __u64 uid = 0xFFFFFFFFFFFFFFFFULL; + __u64 gid = 0xFFFFFFFFFFFFFFFFULL; + struct cifsInodeInfo *cifsInode; + struct list_head * tmp; + + xid = GetXid(); + + cFYI(1, + (" In cifs_setattr, name = %s attrs->iavalid 0x%x ", + direntry->d_name.name, attrs->ia_valid)); + cifs_sb = CIFS_SB(direntry->d_inode->i_sb); + pTcon = cifs_sb->tcon; + + down(&direntry->d_sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(direntry); + up(&direntry->d_sb->s_vfs_rename_sem); + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + cifsInode = CIFS_I(direntry->d_inode); + + /* BB check if we need to refresh inode from server now ? BB */ + + /* need to flush data before changing file size on server */ + filemap_fdatasync(direntry->d_inode->i_mapping); + + if (attrs->ia_valid & ATTR_SIZE) { + read_lock(&GlobalSMBSeslock); + /* To avoid spurious oplock breaks from server, in the case + of inodes that we already have open, avoid doing path + based setting of file size if we can do it by handle. + This keeps our caching token (oplock) and avoids + timeouts when the local oplock break takes longer to flush + writebehind data than the SMB timeout for the SetPathInfo + request would allow */ + list_for_each(tmp, &cifsInode->openFileList) { + open_file = list_entry(tmp,struct cifsFileInfo, flist); + /* We check if file is open for writing first */ + if((open_file->pfile) && + ((open_file->pfile->f_flags & O_RDWR) || + (open_file->pfile->f_flags & O_WRONLY))) { + if(open_file->invalidHandle == FALSE) { + /* we found a valid, writeable network file + handle to use to try to set the file size */ + __u16 nfid = open_file->netfid; + __u32 npid = open_file->pid; + read_unlock(&GlobalSMBSeslock); + found = TRUE; + rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, + nfid,npid,FALSE); + cFYI(1,("SetFileSize by handle (setattrs) rc = %d",rc)); + /* Do not need reopen and retry on EAGAIN since we will + retry by pathname below */ + + break; /* now that we found one valid file handle no + sense continuing to loop trying others */ + } + } + } + if(found == FALSE) { + read_unlock(&GlobalSMBSeslock); + } + + + if(rc != 0) { + /* Set file size by pathname rather than by handle either + because no valid, writeable file handle for it was found or + because there was an error setting it by handle */ + rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE, + cifs_sb->local_nls); + cFYI(1,(" SetEOF by path (setattrs) rc = %d",rc)); + } + + /* Server is ok setting allocation size implicitly - no need to call: */ + /*CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE, cifs_sb->local_nls);*/ + + if (rc == 0) { + rc = vmtruncate(direntry->d_inode, attrs->ia_size); + cifs_truncate_page(direntry->d_inode->i_mapping, direntry->d_inode->i_size); + } + } + if (attrs->ia_valid & ATTR_UID) { + cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid)); + uid = attrs->ia_uid; + /* entry->uid = cpu_to_le16(attr->ia_uid); */ + } + if (attrs->ia_valid & ATTR_GID) { + cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid)); + gid = attrs->ia_gid; + /* entry->gid = cpu_to_le16(attr->ia_gid); */ + } + + time_buf.Attributes = 0; + if (attrs->ia_valid & ATTR_MODE) { + cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode)); + mode = attrs->ia_mode; + /* entry->mode = cpu_to_le16(attr->ia_mode); */ + } + + if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) + && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID))) + rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid, + 0 /* dev_t */, cifs_sb->local_nls); + else if (attrs->ia_valid & ATTR_MODE) { + if((mode & S_IWUGO) == 0) /* not writeable */ { + if((cifsInode->cifsAttrs & ATTR_READONLY) == 0) + time_buf.Attributes = + cpu_to_le32(cifsInode->cifsAttrs | ATTR_READONLY); + } else if((mode & S_IWUGO) == S_IWUGO) { + if(cifsInode->cifsAttrs & ATTR_READONLY) + time_buf.Attributes = + cpu_to_le32(cifsInode->cifsAttrs & (~ATTR_READONLY)); + } + /* BB to be implemented - via Windows security descriptors or streams */ + /* CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,uid,gid,cifs_sb->local_nls);*/ + } + + if (attrs->ia_valid & ATTR_ATIME) { + set_time = TRUE; + time_buf.LastAccessTime = + cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime)); + } else + time_buf.LastAccessTime = 0; + + if (attrs->ia_valid & ATTR_MTIME) { + set_time = TRUE; + time_buf.LastWriteTime = + cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); + } else + time_buf.LastWriteTime = 0; + + if (attrs->ia_valid & ATTR_CTIME) { + set_time = TRUE; + time_buf.ChangeTime = + cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); + } else + time_buf.ChangeTime = 0; + + if (set_time | time_buf.Attributes) { + /* BB what if setting one attribute fails + (such as size) but time setting works */ + time_buf.CreationTime = 0; /* do not change */ + /* In the future we should experiment - try setting timestamps + via Handle (SetFileInfo) instead of by path */ + rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf, + cifs_sb->local_nls); + } + + /* do not need local check to inode_check_ok since the server does that */ + if (!rc) + rc = inode_setattr(direntry->d_inode, attrs); + if (full_path) + kfree(full_path); + FreeXid(xid); + return rc; +} + +void +cifs_delete_inode(struct inode *inode) +{ + cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode)); + /* may have to add back in if and when safe distributed caching of + directories added e.g. via FindNotify */ +} diff --git a/release/src/linux/linux/fs/cifs/link.c b/release/src/linux/linux/fs/cifs/link.c new file mode 100644 index 00000000..d4e93724 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/link.c @@ -0,0 +1,328 @@ +/* + * fs/cifs/link.c + * + * Copyright (C) International Business Machines Corp., 2002,2003 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/fs.h> +#include <linux/stat.h> +#include "cifsfs.h" +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_debug.h" +#include "cifs_fs_sb.h" + +int +cifs_hardlink(struct dentry *old_file, struct inode *inode, + struct dentry *direntry) +{ + int rc = -EACCES; + int xid; + char *fromName = NULL; + char *toName = NULL; + struct cifs_sb_info *cifs_sb_target; + struct cifsTconInfo *pTcon; + struct cifsInodeInfo *cifsInode; + + xid = GetXid(); + + cifs_sb_target = CIFS_SB(inode->i_sb); + pTcon = cifs_sb_target->tcon; + +/* No need to check for cross device links since server will do that + BB note DFS case in future though (when we may have to check) */ + + down(&inode->i_sb->s_vfs_rename_sem); + fromName = build_path_from_dentry(old_file); + toName = build_path_from_dentry(direntry); + up(&inode->i_sb->s_vfs_rename_sem); + if((fromName == NULL) || (toName == NULL)) { + rc = -ENOMEM; + goto cifs_hl_exit; + } + + if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX) + rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName, + cifs_sb_target->local_nls); + else { + rc = CIFSCreateHardLink(xid, pTcon, fromName, toName, + cifs_sb_target->local_nls); + if(rc == -EIO) + rc = -EOPNOTSUPP; + } + +/* if (!rc) */ + { + /* renew_parental_timestamps(old_file); + inode->i_nlink++; + mark_inode_dirty(inode); + d_instantiate(direntry, inode); */ + /* BB add call to either mark inode dirty or refresh its data and timestamp to current time */ + } + d_drop(direntry); /* force new lookup from server */ + cifsInode = CIFS_I(old_file->d_inode); + cifsInode->time = 0; /* will force revalidate to go get info when needed */ + +cifs_hl_exit: + if (fromName) + kfree(fromName); + if (toName) + kfree(toName); + FreeXid(xid); + return rc; +} + +int +cifs_follow_link(struct dentry *direntry, struct nameidata *nd) +{ + struct inode *inode = direntry->d_inode; + int rc = -EACCES; + int xid; + char *full_path = NULL; + char * target_path; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + + xid = GetXid(); + + down(&direntry->d_sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(direntry); + up(&direntry->d_sb->s_vfs_rename_sem); + + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode)); + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + target_path = kmalloc(PATH_MAX, GFP_KERNEL); + if(target_path == NULL) { + if (full_path) + kfree(full_path); + FreeXid(xid); + return -ENOMEM; + } + /* can not call the following line due to EFAULT in vfs_readlink which is presumably expecting a user space buffer */ + /* length = cifs_readlink(direntry,target_path, sizeof(target_path) - 1); */ + +/* BB add read reparse point symlink code and Unix extensions symlink code here BB */ + if (pTcon->ses->capabilities & CAP_UNIX) + rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, + target_path, + PATH_MAX-1, + cifs_sb->local_nls); + else { + /* rc = CIFSSMBQueryReparseLinkInfo */ + /* BB Add code to Query ReparsePoint info */ + } + /* BB Anything else to do to handle recursive links? */ + /* BB Should we be using page symlink ops here? */ + + if (rc == 0) { + +/* BB Add special case check for Samba DFS symlinks */ + + target_path[PATH_MAX-1] = 0; + rc = vfs_follow_link(nd, target_path); + } + /* else EACCESS */ + + if (target_path) + kfree(target_path); + if (full_path) + kfree(full_path); + FreeXid(xid); + return rc; +} + +int +cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) +{ + int rc = -EOPNOTSUPP; + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + char *full_path = NULL; + struct inode *newinode = NULL; + + xid = GetXid(); + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + + down(&inode->i_sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(direntry); + up(&inode->i_sb->s_vfs_rename_sem); + + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + + cFYI(1, ("Full path: %s ", full_path)); + cFYI(1, ("symname is %s", symname)); + + /* BB what if DFS and this volume is on different share? BB */ + if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) + rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, + cifs_sb->local_nls); + /* else + rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,cifs_sb_target->local_nls); */ + + if (rc == 0) { + if (pTcon->ses->capabilities & CAP_UNIX) + rc = cifs_get_inode_info_unix(&newinode, full_path, + inode->i_sb,xid); + else + rc = cifs_get_inode_info(&newinode, full_path, NULL, + inode->i_sb,xid); + + if (rc != 0) { + cFYI(1, + ("Create symlink worked but get_inode_info failed with rc = %d ", + rc)); + } else { + direntry->d_op = &cifs_dentry_ops; + d_instantiate(direntry, newinode); + } + } + + if (full_path) + kfree(full_path); + FreeXid(xid); + return rc; +} + +int +cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) +{ + struct inode *inode = direntry->d_inode; + int rc = -EACCES; + int xid; + int oplock = FALSE; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + char *full_path = NULL; + char *tmp_path = NULL; + char * tmpbuffer; + unsigned char * referrals = NULL; + int num_referrals = 0; + int len; + __u16 fid; + + xid = GetXid(); + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + +/* BB would it be safe against deadlock to grab this sem + even though rename itself grabs the sem and calls lookup? */ +/* down(&inode->i_sb->s_vfs_rename_sem);*/ + full_path = build_path_from_dentry(direntry); +/* up(&inode->i_sb->s_vfs_rename_sem);*/ + + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + + cFYI(1, + ("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d", + full_path, inode, pBuffer, buflen)); + if(buflen > PATH_MAX) + len = PATH_MAX; + else + len = buflen; + tmpbuffer = kmalloc(len,GFP_KERNEL); + if(tmpbuffer == NULL) { + if (full_path) + kfree(full_path); + FreeXid(xid); + return -ENOMEM; + } + +/* BB add read reparse point symlink code and Unix extensions symlink code here BB */ + if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) + rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, + tmpbuffer, + len - 1, + cifs_sb->local_nls); + else { + rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ, + OPEN_REPARSE_POINT,&fid, &oplock, NULL, cifs_sb->local_nls); + if(!rc) { + rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path, + tmpbuffer, + len - 1, + fid, + cifs_sb->local_nls); + if(CIFSSMBClose(xid, pTcon, fid)) { + cFYI(1,("Error closing junction point (open for ioctl)")); + } + if(rc == -EIO) { + /* Query if DFS Junction */ + tmp_path = + kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1, + GFP_KERNEL); + if (tmp_path) { + strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); + strncat(tmp_path, full_path, MAX_PATHCONF); + rc = get_dfs_path(xid, pTcon->ses, tmp_path, + cifs_sb->local_nls, &num_referrals, &referrals); + cFYI(1,("Get DFS for %s rc = %d ",tmp_path, rc)); + if((num_referrals == 0) && (rc == 0)) + rc = -EACCES; + else { + cFYI(1,("num referral: %d",num_referrals)); + if(referrals) { + cFYI(1,("referral string: %s ",referrals)); + strncpy(tmpbuffer, referrals, len-1); + } + } + if(referrals) + kfree(referrals); + kfree(tmp_path); + if(referrals) { + kfree(referrals); + } + } + /* BB add code like else decode referrals then memcpy to + tmpbuffer and free referrals string array BB */ + } + } + } + /* BB Anything else to do to handle recursive links? */ + /* BB Should we be using page ops here? */ + + /* BB null terminate returned string in pBuffer? BB */ + if (rc == 0) { + rc = vfs_readlink(direntry, pBuffer, len, tmpbuffer); + cFYI(1, + ("vfs_readlink called from cifs_readlink returned %d", + rc)); + } + + if (tmpbuffer) { + kfree(tmpbuffer); + } + if (full_path) { + kfree(full_path); + } + FreeXid(xid); + return rc; +} diff --git a/release/src/linux/linux/fs/cifs/md4.c b/release/src/linux/linux/fs/cifs/md4.c new file mode 100644 index 00000000..1edbe22c --- /dev/null +++ b/release/src/linux/linux/fs/cifs/md4.c @@ -0,0 +1,203 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + a implementation of MD4 designed for use in the SMB authentication protocol + Copyright (C) Andrew Tridgell 1997-1998. + Modified by Steve French (sfrench@us.ibm.com) 2002-2003 + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include <linux/module.h> +#include <linux/fs.h> +/* NOTE: This code makes no attempt to be fast! */ + +static __u32 +F(__u32 X, __u32 Y, __u32 Z) +{ + return (X & Y) | ((~X) & Z); +} + +static __u32 +G(__u32 X, __u32 Y, __u32 Z) +{ + return (X & Y) | (X & Z) | (Y & Z); +} + +static __u32 +H(__u32 X, __u32 Y, __u32 Z) +{ + return X ^ Y ^ Z; +} + +static __u32 +lshift(__u32 x, int s) +{ + x &= 0xFFFFFFFF; + return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s)); +} + +#define ROUND1(a,b,c,d,k,s) (*a) = lshift((*a) + F(*b,*c,*d) + X[k], s) +#define ROUND2(a,b,c,d,k,s) (*a) = lshift((*a) + G(*b,*c,*d) + X[k] + (__u32)0x5A827999,s) +#define ROUND3(a,b,c,d,k,s) (*a) = lshift((*a) + H(*b,*c,*d) + X[k] + (__u32)0x6ED9EBA1,s) + +/* this applies md4 to 64 byte chunks */ +static void +mdfour64(__u32 * M, __u32 * A, __u32 *B, __u32 * C, __u32 *D) +{ + int j; + __u32 AA, BB, CC, DD; + __u32 X[16]; + + + for (j = 0; j < 16; j++) + X[j] = M[j]; + + AA = *A; + BB = *B; + CC = *C; + DD = *D; + + ROUND1(A, B, C, D, 0, 3); + ROUND1(D, A, B, C, 1, 7); + ROUND1(C, D, A, B, 2, 11); + ROUND1(B, C, D, A, 3, 19); + ROUND1(A, B, C, D, 4, 3); + ROUND1(D, A, B, C, 5, 7); + ROUND1(C, D, A, B, 6, 11); + ROUND1(B, C, D, A, 7, 19); + ROUND1(A, B, C, D, 8, 3); + ROUND1(D, A, B, C, 9, 7); + ROUND1(C, D, A, B, 10, 11); + ROUND1(B, C, D, A, 11, 19); + ROUND1(A, B, C, D, 12, 3); + ROUND1(D, A, B, C, 13, 7); + ROUND1(C, D, A, B, 14, 11); + ROUND1(B, C, D, A, 15, 19); + + ROUND2(A, B, C, D, 0, 3); + ROUND2(D, A, B, C, 4, 5); + ROUND2(C, D, A, B, 8, 9); + ROUND2(B, C, D, A, 12, 13); + ROUND2(A, B, C, D, 1, 3); + ROUND2(D, A, B, C, 5, 5); + ROUND2(C, D, A, B, 9, 9); + ROUND2(B, C, D, A, 13, 13); + ROUND2(A, B, C, D, 2, 3); + ROUND2(D, A, B, C, 6, 5); + ROUND2(C, D, A, B, 10, 9); + ROUND2(B, C, D, A, 14, 13); + ROUND2(A, B, C, D, 3, 3); + ROUND2(D, A, B, C, 7, 5); + ROUND2(C, D, A, B, 11, 9); + ROUND2(B, C, D, A, 15, 13); + + ROUND3(A, B, C, D, 0, 3); + ROUND3(D, A, B, C, 8, 9); + ROUND3(C, D, A, B, 4, 11); + ROUND3(B, C, D, A, 12, 15); + ROUND3(A, B, C, D, 2, 3); + ROUND3(D, A, B, C, 10, 9); + ROUND3(C, D, A, B, 6, 11); + ROUND3(B, C, D, A, 14, 15); + ROUND3(A, B, C, D, 1, 3); + ROUND3(D, A, B, C, 9, 9); + ROUND3(C, D, A, B, 5, 11); + ROUND3(B, C, D, A, 13, 15); + ROUND3(A, B, C, D, 3, 3); + ROUND3(D, A, B, C, 11, 9); + ROUND3(C, D, A, B, 7, 11); + ROUND3(B, C, D, A, 15, 15); + + *A += AA; + *B += BB; + *C += CC; + *D += DD; + + *A &= 0xFFFFFFFF; + *B &= 0xFFFFFFFF; + *C &= 0xFFFFFFFF; + *D &= 0xFFFFFFFF; + + for (j = 0; j < 16; j++) + X[j] = 0; +} + +static void +copy64(__u32 * M, unsigned char *in) +{ + int i; + + for (i = 0; i < 16; i++) + M[i] = (in[i * 4 + 3] << 24) | (in[i * 4 + 2] << 16) | + (in[i * 4 + 1] << 8) | (in[i * 4 + 0] << 0); +} + +static void +copy4(unsigned char *out, __u32 x) +{ + out[0] = x & 0xFF; + out[1] = (x >> 8) & 0xFF; + out[2] = (x >> 16) & 0xFF; + out[3] = (x >> 24) & 0xFF; +} + +/* produce a md4 message digest from data of length n bytes */ +void +mdfour(unsigned char *out, unsigned char *in, int n) +{ + unsigned char buf[128]; + __u32 M[16]; + __u32 b = n * 8; + int i; + __u32 A = 0x67452301; + __u32 B = 0xefcdab89; + __u32 C = 0x98badcfe; + __u32 D = 0x10325476; + + while (n > 64) { + copy64(M, in); + mdfour64(M,&A,&B, &C, &D); + in += 64; + n -= 64; + } + + for (i = 0; i < 128; i++) + buf[i] = 0; + memcpy(buf, in, n); + buf[n] = 0x80; + + if (n <= 55) { + copy4(buf + 56, b); + copy64(M, buf); + mdfour64(M, &A, &B, &C, &D); + } else { + copy4(buf + 120, b); + copy64(M, buf); + mdfour64(M, &A, &B, &C, &D); + copy64(M, buf + 64); + mdfour64(M, &A, &B, &C, &D); + } + + for (i = 0; i < 128; i++) + buf[i] = 0; + copy64(M, buf); + + copy4(out, A); + copy4(out + 4, B); + copy4(out + 8, C); + copy4(out + 12, D); + + A = B = C = D = 0; +} diff --git a/release/src/linux/linux/fs/cifs/md5.c b/release/src/linux/linux/fs/cifs/md5.c new file mode 100644 index 00000000..7aa23490 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/md5.c @@ -0,0 +1,363 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +/* This code slightly modified to fit into Samba by + abartlet@samba.org Jun 2001 + and to fit the cifs vfs by + Steve French sfrench@us.ibm.com */ + +#include <linux/string.h> +#include "md5.h" + +static void MD5Transform(__u32 buf[4], __u32 const in[16]); + +/* + * Note: this code is harmless on little-endian machines. + */ +static void +byteReverse(unsigned char *buf, unsigned longs) +{ + __u32 t; + do { + t = (__u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(__u32 *) buf = t; + buf += 4; + } while (--longs); +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void +MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) +{ + register __u32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((__u32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memmove(p, buf, len); + return; + } + memmove(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (__u32 *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memmove(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (__u32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memmove(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void +MD5Final(unsigned char digest[16], struct MD5Context *ctx) +{ + unsigned int count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (__u32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((__u32 *) ctx->in)[14] = ctx->bits[0]; + ((__u32 *) ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (__u32 *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + memmove(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ +} + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void +MD5Transform(__u32 buf[4], __u32 const in[16]) +{ + register __u32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +/*********************************************************************** + the rfc 2104 version of hmac_md5 initialisation. +***********************************************************************/ +void +hmac_md5_init_rfc2104(unsigned char *key, int key_len, + struct HMACMD5Context *ctx) +{ + int i; + + /* if key is longer than 64 bytes reset it to key=MD5(key) */ + if (key_len > 64) { + unsigned char tk[16]; + struct MD5Context tctx; + + MD5Init(&tctx); + MD5Update(&tctx, key, key_len); + MD5Final(tk, &tctx); + + key = tk; + key_len = 16; + } + + /* start out by storing key in pads */ + memset(ctx->k_ipad, 0, sizeof (ctx->k_ipad)); + memset(ctx->k_opad, 0, sizeof (ctx->k_opad)); + memcpy(ctx->k_ipad, key, key_len); + memcpy(ctx->k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < 64; i++) { + ctx->k_ipad[i] ^= 0x36; + ctx->k_opad[i] ^= 0x5c; + } + + MD5Init(&ctx->ctx); + MD5Update(&ctx->ctx, ctx->k_ipad, 64); +} + +/*********************************************************************** + the microsoft version of hmac_md5 initialisation. +***********************************************************************/ +void +hmac_md5_init_limK_to_64(const unsigned char *key, int key_len, + struct HMACMD5Context *ctx) +{ + int i; + + /* if key is longer than 64 bytes truncate it */ + if (key_len > 64) { + key_len = 64; + } + + /* start out by storing key in pads */ + memset(ctx->k_ipad, 0, sizeof (ctx->k_ipad)); + memset(ctx->k_opad, 0, sizeof (ctx->k_opad)); + memcpy(ctx->k_ipad, key, key_len); + memcpy(ctx->k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i = 0; i < 64; i++) { + ctx->k_ipad[i] ^= 0x36; + ctx->k_opad[i] ^= 0x5c; + } + + MD5Init(&ctx->ctx); + MD5Update(&ctx->ctx, ctx->k_ipad, 64); +} + +/*********************************************************************** + update hmac_md5 "inner" buffer +***********************************************************************/ +void +hmac_md5_update(const unsigned char *text, int text_len, + struct HMACMD5Context *ctx) +{ + MD5Update(&ctx->ctx, text, text_len); /* then text of datagram */ +} + +/*********************************************************************** + finish off hmac_md5 "inner" buffer and generate outer one. +***********************************************************************/ +void +hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx) +{ + struct MD5Context ctx_o; + + MD5Final(digest, &ctx->ctx); + + MD5Init(&ctx_o); + MD5Update(&ctx_o, ctx->k_opad, 64); + MD5Update(&ctx_o, digest, 16); + MD5Final(digest, &ctx_o); +} + +/*********************************************************** + single function to calculate an HMAC MD5 digest from data. + use the microsoft hmacmd5 init method because the key is 16 bytes. +************************************************************/ +void +hmac_md5(unsigned char key[16], unsigned char *data, int data_len, + unsigned char *digest) +{ + struct HMACMD5Context ctx; + hmac_md5_init_limK_to_64(key, 16, &ctx); + if (data_len != 0) { + hmac_md5_update(data, data_len, &ctx); + } + hmac_md5_final(digest, &ctx); +} diff --git a/release/src/linux/linux/fs/cifs/md5.h b/release/src/linux/linux/fs/cifs/md5.h new file mode 100644 index 00000000..00e1c539 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/md5.h @@ -0,0 +1,38 @@ +#ifndef MD5_H +#define MD5_H +#ifndef HEADER_MD5_H +/* Try to avoid clashes with OpenSSL */ +#define HEADER_MD5_H +#endif + +struct MD5Context { + __u32 buf[4]; + __u32 bits[2]; + unsigned char in[64]; +}; +#endif /* !MD5_H */ + +#ifndef _HMAC_MD5_H +struct HMACMD5Context { + struct MD5Context ctx; + unsigned char k_ipad[65]; + unsigned char k_opad[65]; +}; +#endif /* _HMAC_MD5_H */ + +void MD5Init(struct MD5Context *context); +void MD5Update(struct MD5Context *context, unsigned char const *buf, + unsigned len); +void MD5Final(unsigned char digest[16], struct MD5Context *context); + +/* The following definitions come from lib/hmacmd5.c */ + +void hmac_md5_init_rfc2104(unsigned char *key, int key_len, + struct HMACMD5Context *ctx); +void hmac_md5_init_limK_to_64(const unsigned char *key, int key_len, + struct HMACMD5Context *ctx); +void hmac_md5_update(const unsigned char *text, int text_len, + struct HMACMD5Context *ctx); +void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx); +void hmac_md5(unsigned char key[16], unsigned char *data, int data_len, + unsigned char *digest); diff --git a/release/src/linux/linux/fs/cifs/misc.c b/release/src/linux/linux/fs/cifs/misc.c new file mode 100644 index 00000000..2241c45e --- /dev/null +++ b/release/src/linux/linux/fs/cifs/misc.c @@ -0,0 +1,463 @@ +/* + * fs/cifs/misc.c + * + * Copyright (C) International Business Machines Corp., 2002,2003 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/slab.h> +#include <linux/ctype.h> +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_debug.h" +#include "smberr.h" +#include "nterr.h" + +extern kmem_cache_t *cifs_req_cachep; +extern struct task_struct * oplockThread; + +__u16 GlobalMid; /* multiplex id - rotating counter */ + +/* The xid serves as a useful identifier for each incoming vfs request, + in a similar way to the mid which is useful to track each sent smb, + and CurrentXid can also provide a running counter (although it + will eventually wrap past zero) of the total vfs operations handled + since the cifs fs was mounted */ + +unsigned int +_GetXid(void) +{ + unsigned int xid; + + spin_lock(&GlobalMid_Lock); + GlobalTotalActiveXid++; + if (GlobalTotalActiveXid > GlobalMaxActiveXid) + GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */ + xid = GlobalCurrentXid++; + spin_unlock(&GlobalMid_Lock); + return xid; +} + +void +_FreeXid(unsigned int xid) +{ + spin_lock(&GlobalMid_Lock); + /* if(GlobalTotalActiveXid == 0) + BUG(); */ + GlobalTotalActiveXid--; + spin_unlock(&GlobalMid_Lock); +} + +struct cifsSesInfo * +sesInfoAlloc(void) +{ + struct cifsSesInfo *ret_buf; + + ret_buf = + (struct cifsSesInfo *) kmalloc(sizeof (struct cifsSesInfo), + GFP_KERNEL); + if (ret_buf) { + memset(ret_buf, 0, sizeof (struct cifsSesInfo)); + write_lock(&GlobalSMBSeslock); + atomic_inc(&sesInfoAllocCount); + ret_buf->status = CifsNew; + list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList); + init_MUTEX(&ret_buf->sesSem); + write_unlock(&GlobalSMBSeslock); + } + return ret_buf; +} + +void +sesInfoFree(struct cifsSesInfo *buf_to_free) +{ + if (buf_to_free == NULL) { + cFYI(1, ("Null buffer passed to sesInfoFree")); + return; + } + + write_lock(&GlobalSMBSeslock); + atomic_dec(&sesInfoAllocCount); + list_del(&buf_to_free->cifsSessionList); + write_unlock(&GlobalSMBSeslock); + if (buf_to_free->serverOS) + kfree(buf_to_free->serverOS); + if (buf_to_free->serverDomain) + kfree(buf_to_free->serverDomain); + if (buf_to_free->serverNOS) + kfree(buf_to_free->serverNOS); + if (buf_to_free->password) + kfree(buf_to_free->password); + kfree(buf_to_free); +} + +struct cifsTconInfo * +tconInfoAlloc(void) +{ + struct cifsTconInfo *ret_buf; + ret_buf = + (struct cifsTconInfo *) kmalloc(sizeof (struct cifsTconInfo), + GFP_KERNEL); + if (ret_buf) { + memset(ret_buf, 0, sizeof (struct cifsTconInfo)); + write_lock(&GlobalSMBSeslock); + atomic_inc(&tconInfoAllocCount); + list_add(&ret_buf->cifsConnectionList, + &GlobalTreeConnectionList); + ret_buf->tidStatus = CifsNew; + INIT_LIST_HEAD(&ret_buf->openFileList); + init_MUTEX(&ret_buf->tconSem); +#ifdef CONFIG_CIFS_STATS + ret_buf->stat_lock = SPIN_LOCK_UNLOCKED; +#endif + write_unlock(&GlobalSMBSeslock); + } + return ret_buf; +} + +void +tconInfoFree(struct cifsTconInfo *buf_to_free) +{ + if (buf_to_free == NULL) { + cFYI(1, ("Null buffer passed to tconInfoFree")); + return; + } + write_lock(&GlobalSMBSeslock); + atomic_dec(&tconInfoAllocCount); + list_del(&buf_to_free->cifsConnectionList); + write_unlock(&GlobalSMBSeslock); + if (buf_to_free->nativeFileSystem) + kfree(buf_to_free->nativeFileSystem); + kfree(buf_to_free); +} + +struct smb_hdr * +cifs_buf_get(void) +{ + struct smb_hdr *ret_buf = NULL; + +/* We could use negotiated size instead of max_msgsize - + but it may be more efficient to always alloc same size + albeit slightly larger than necessary and maxbuffersize + defaults to this and can not be bigger */ + ret_buf = + (struct smb_hdr *) kmem_cache_alloc(cifs_req_cachep, SLAB_KERNEL); + + /* clear the first few header bytes */ + if (ret_buf) { + memset(ret_buf, 0, sizeof (struct smb_hdr)); + atomic_inc(&bufAllocCount); + } + + return ret_buf; +} + +void +cifs_buf_release(void *buf_to_free) +{ + + if (buf_to_free == NULL) { + cFYI(1, ("Null buffer passed to cifs_buf_release")); + return; + } + kmem_cache_free(cifs_req_cachep, buf_to_free); + + atomic_dec(&bufAllocCount); + return; +} + +void +header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , + const struct cifsTconInfo *treeCon, int word_count + /* length of fixed section (word count) in two byte units */ + ) +{ + int i; + __u32 tmp; + struct list_head* temp_item; + struct cifsSesInfo * ses; + char *temp = (char *) buffer; + + for (i = 0; i < MAX_CIFS_HDR_SIZE; i++) { + temp[i] = 0; /* BB is this needed ?? */ + } + + buffer->smb_buf_length = + (2 * word_count) + sizeof (struct smb_hdr) - + 4 /* RFC 1001 length field does not count */ + + 2 /* for bcc field itself */ ; + /* Note that this is the only network field that has to be converted to big endian and it is done just before we send it */ + + buffer->Protocol[0] = 0xFF; + buffer->Protocol[1] = 'S'; + buffer->Protocol[2] = 'M'; + buffer->Protocol[3] = 'B'; + buffer->Command = smb_command; + buffer->Flags = 0x00; /* case sensitive */ + buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES; + tmp = cpu_to_le32(current->pid); + buffer->Pid = tmp & 0xFFFF; + tmp >>= 16; + buffer->PidHigh = tmp & 0xFFFF; + spin_lock(&GlobalMid_Lock); + GlobalMid++; + buffer->Mid = GlobalMid; + spin_unlock(&GlobalMid_Lock); + if (treeCon) { + buffer->Tid = treeCon->tid; + if (treeCon->ses) { + if (treeCon->ses->capabilities & CAP_UNICODE) + buffer->Flags2 |= SMBFLG2_UNICODE; + if (treeCon->ses->capabilities & CAP_STATUS32) { + buffer->Flags2 |= SMBFLG2_ERR_STATUS; + } + + buffer->Uid = treeCon->ses->Suid; /* always in LE format */ + if(multiuser_mount != 0) { + /* For the multiuser case, there are few obvious technically */ + /* possible mechanisms to match the local linux user (uid) */ + /* to a valid remote smb user (smb_uid): */ + /* 1) Query Winbind (or other local pam/nss daemon */ + /* for userid/password/logon_domain or credential */ + /* 2) Query Winbind for uid to sid to username mapping */ + /* and see if we have a matching password for existing*/ + /* session for that user perhas getting password by */ + /* adding a new pam_cifs module that stores passwords */ + /* so that the cifs vfs can get at that for all logged*/ + /* on users */ + /* 3) (Which is the mechanism we have chosen) */ + /* Search through sessions to the same server for a */ + /* a match on the uid that was passed in on mount */ + /* with the current processes uid (or euid?) and use */ + /* that smb uid. If no existing smb session for */ + /* that uid found, use the default smb session ie */ + /* the smb session for the volume mounted which is */ + /* the same as would be used if the multiuser mount */ + /* flag were disabled. */ + + /* BB Add support for establishing new tCon and SMB Session */ + /* with userid/password pairs found on the smb session */ + /* for other target tcp/ip addresses BB */ + if(current->uid != treeCon->ses->linux_uid) { + cFYI(1,("Multiuser mode and UID did not match tcon uid ")); + read_lock(&GlobalSMBSeslock); + list_for_each(temp_item, &GlobalSMBSessionList) { + ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList); + if(ses->linux_uid == current->uid) { + if(ses->server == treeCon->ses->server) { + cFYI(1,("found matching uid substitute right smb_uid")); + buffer->Uid = ses->Suid; + break; + } else { + /* BB eventually call cifs_setup_session here */ + cFYI(1,("local UID found but smb sess with this server does not exist")); + } + } + } + read_unlock(&GlobalSMBSeslock); + } + } + } + if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) + buffer->Flags2 |= SMBFLG2_DFS; + if(treeCon->ses->server) + if(treeCon->ses->server->secMode & + (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + } + +/* endian conversion of flags is now done just before sending */ + buffer->WordCount = (char) word_count; + return; +} + +int +checkSMBhdr(struct smb_hdr *smb, __u16 mid) +{ + /* Make sure that this really is an SMB, that it is a response, + and that the message ids match */ + if ((*(unsigned int *) smb->Protocol == cpu_to_le32(0x424d53ff)) && + (mid == smb->Mid)) { + if(smb->Flags & SMBFLG_RESPONSE) + return 0; + else { + /* only one valid case where server sends us request */ + if(smb->Command == SMB_COM_LOCKING_ANDX) + return 0; + else + cERROR(1, ("Rcvd Request not response ")); + } + } else { /* bad signature or mid */ + if (*(unsigned int *) smb->Protocol != cpu_to_le32(0x424d53ff)) + cERROR(1, + ("Bad protocol string signature header %x ", + *(unsigned int *) smb->Protocol)); + if (mid != smb->Mid) + cERROR(1, ("Mids do not match")); + } + cERROR(1, ("bad smb detected. The Mid=%d", smb->Mid)); + return 1; +} + +int +checkSMB(struct smb_hdr *smb, __u16 mid, int length) +{ + cFYI(0, + ("Entering checkSMB with Length: %x, smb_buf_length: %x ", + length, ntohl(smb->smb_buf_length))); + if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) + || (ntohl(smb->smb_buf_length) > + CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4)) { + if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) { + cERROR(1, ("Length less than 2 + sizeof smb_hdr ")); + if (((unsigned int)length >= sizeof (struct smb_hdr) - 1) + && (smb->Status.CifsError != 0)) + return 0; /* some error cases do not return wct and bcc */ + + } + if (ntohl(smb->smb_buf_length) > + CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4) + cERROR(1, + ("smb_buf_length greater than CIFS_MAX_MSGSIZE ... ")); + cERROR(1, + ("bad smb detected. Illegal length. The mid=%d", + smb->Mid)); + return 1; + } + + if (checkSMBhdr(smb, mid)) + return 1; + + if ((4 + ntohl(smb->smb_buf_length) != smbCalcSize(smb)) + || (4 + ntohl(smb->smb_buf_length) != (unsigned int)length)) { + return 0; + } else { + cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb))); + cERROR(1, + ("bad smb size detected. The Mid=%d", smb->Mid)); + return 1; + } +} +int +is_valid_oplock_break(struct smb_hdr *buf) +{ + struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf; + struct list_head *tmp; + struct list_head *tmp1; + struct cifsTconInfo *tcon; + struct cifsFileInfo *netfile; + + /* could add check for smb response flag 0x80 */ + cFYI(1,("Checking for oplock break")); + if(pSMB->hdr.Command != SMB_COM_LOCKING_ANDX) + return FALSE; + if(pSMB->hdr.Flags & SMBFLG_RESPONSE) { + /* no sense logging error on invalid handle on oplock + break - harmless race between close request and oplock + break response is expected from time to time writing out + large dirty files cached on the client */ + if ((NT_STATUS_INVALID_HANDLE) == + le32_to_cpu(pSMB->hdr.Status.CifsError)) { + cFYI(1,("invalid handle on oplock break")); + return TRUE; + } else if (ERRbadfid == + le16_to_cpu(pSMB->hdr.Status.DosError.Error)) { + return TRUE; + } else { + return FALSE; /* on valid oplock brk we get "request" */ + } + } + if(pSMB->hdr.WordCount != 8) + return FALSE; + + cFYI(1,(" oplock type 0x%d level 0x%d",pSMB->LockType,pSMB->OplockLevel)); + if(!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)) + return FALSE; + + /* look up tcon based on tid & uid */ + read_lock(&GlobalSMBSeslock); + list_for_each(tmp, &GlobalTreeConnectionList) { + tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); + if (tcon->tid == buf->Tid) { +#ifdef CONFIG_CIFS_STATS + atomic_inc(&tcon->num_oplock_brks); +#endif + list_for_each(tmp1,&tcon->openFileList){ + netfile = list_entry(tmp1,struct cifsFileInfo,tlist); + if(pSMB->Fid == netfile->netfid) { + struct cifsInodeInfo *pCifsInode; + read_unlock(&GlobalSMBSeslock); + cFYI(1,("Matching file id, processing oplock break")); + pCifsInode = + CIFS_I(netfile->pInode); + pCifsInode->clientCanCacheAll = FALSE; + if(pSMB->OplockLevel == 0) + pCifsInode->clientCanCacheRead = FALSE; + pCifsInode->oplockPending = TRUE; + AllocOplockQEntry(netfile->pInode, netfile->netfid, tcon); + cFYI(1,("about to wake up oplock thd")); + wake_up_process(oplockThread); + return TRUE; + } + } + read_unlock(&GlobalSMBSeslock); + cFYI(1,("No matching file for oplock break on connection")); + return TRUE; + } + } + read_unlock(&GlobalSMBSeslock); + cFYI(1,("Can not process oplock break for non-existent connection")); + return TRUE; +} + +void +dump_smb(struct smb_hdr *smb_buf, int smb_buf_length) +{ + int i, j; + char debug_line[17]; + unsigned char *buffer; + + if (traceSMB == 0) + return; + + buffer = (unsigned char *) smb_buf; + for (i = 0, j = 0; i < smb_buf_length; i++, j++) { + if (i % 8 == 0) { /* we have reached the beginning of line */ + printk(KERN_DEBUG "| "); + j = 0; + } + printk("%0#4x ", buffer[i]); + debug_line[2 * j] = ' '; + if (isprint(buffer[i])) + debug_line[1 + (2 * j)] = buffer[i]; + else + debug_line[1 + (2 * j)] = '_'; + + if (i % 8 == 7) { /* we have reached end of line, time to print ascii */ + debug_line[16] = 0; + printk(" | %s\n", debug_line); + } + } + for (; j < 8; j++) { + printk(" "); + debug_line[2 * j] = ' '; + debug_line[1 + (2 * j)] = ' '; + } + printk( " | %s\n", debug_line); + return; +} diff --git a/release/src/linux/linux/fs/cifs/netmisc.c b/release/src/linux/linux/fs/cifs/netmisc.c new file mode 100644 index 00000000..0a06be9d --- /dev/null +++ b/release/src/linux/linux/fs/cifs/netmisc.c @@ -0,0 +1,905 @@ +/* + * fs/cifs/netmisc.c + * + * Copyright (c) International Business Machines Corp., 2002 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * Error mapping routines from Samba libsmb/errormap.c + * Copyright (C) Andrew Tridgell 2001 + * + * + * 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 + */ + +#include <linux/net.h> +#include <linux/string.h> +#include <linux/in.h> +#include <linux/ctype.h> +#include <linux/fs.h> +#include <asm/div64.h> +#include <asm/byteorder.h> +#include "cifsfs.h" +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "smberr.h" +#include "cifs_debug.h" +#include "nterr.h" + +struct smb_to_posix_error { + __u16 smb_err; + int posix_code; +}; + +const struct smb_to_posix_error mapping_table_ERRDOS[] = { + {ERRbadfunc, -EINVAL}, + {ERRbadfile, -ENOENT}, + {ERRbadpath, -ENOTDIR}, + {ERRnofids, -EMFILE}, + {ERRnoaccess, -EACCES}, + {ERRbadfid, -EBADF}, + {ERRbadmcb, -EIO}, + {ERRnomem, -ENOMEM}, + {ERRbadmem, -EFAULT}, + {ERRbadenv, -EFAULT}, + {ERRbadformat, -EINVAL}, + {ERRbadaccess, -EACCES}, + {ERRbaddata, -EIO}, + {ERRbaddrive, -ENXIO}, + {ERRremcd, -EACCES}, + {ERRdiffdevice, -EXDEV}, + {ERRnofiles, -ENOENT}, + {ERRbadshare, -ETXTBSY}, + {ERRlock, -EACCES}, + {ERRunsup, -EINVAL}, + {ERRnosuchshare,-ENXIO}, + {ERRfilexists, -EEXIST}, + {ERRinvparm, -EINVAL}, + {ERRdiskfull, -ENOSPC}, + {ERRinvname, -ENOENT}, + {ERRdirnotempty, -ENOTEMPTY}, + {ERRnotlocked, -ENOLCK}, + {ERRalreadyexists, -EEXIST}, + {ERRmoredata, -EOVERFLOW}, + {ErrQuota, -EDQUOT}, + {ErrNotALink, -ENOLINK}, + {ERRnetlogonNotStarted,-ENOPROTOOPT}, + {0, 0} +}; + +const struct smb_to_posix_error mapping_table_ERRSRV[] = { + {ERRerror, -EIO}, + {ERRbadpw, -EPERM}, + {ERRbadtype, -EREMOTE}, + {ERRaccess, -EACCES}, + {ERRinvtid, -ENXIO}, + {ERRinvnetname, -ENODEV}, + {ERRinvdevice, -ENXIO}, + {ERRqfull, -ENOSPC}, + {ERRqtoobig, -ENOSPC}, + {ERRqeof, -EIO}, + {ERRinvpfid, -EBADF}, + {ERRsmbcmd, -EBADRQC}, + {ERRsrverror, -EIO}, + {ERRbadBID, -EIO}, + {ERRfilespecs, -EINVAL}, + {ERRbadLink, -EIO}, + {ERRbadpermits, -EINVAL}, + {ERRbadPID, -ESRCH}, + {ERRsetattrmode, -EINVAL}, + {ERRpaused, -EHOSTDOWN}, + {ERRmsgoff, -EHOSTDOWN}, + {ERRnoroom, -ENOSPC}, + {ERRrmuns, -EUSERS}, + {ERRtimeout, -ETIME}, + {ERRnoresource, -ENOBUFS}, + {ERRtoomanyuids, -EUSERS}, + {ERRbaduid, -EACCES}, + {ERRusempx, -EIO}, + {ERRusestd, -EIO}, + {ERR_NOTIFY_ENUM_DIR, -ENOBUFS}, + {ERRaccountexpired, -EACCES}, + {ERRbadclient, -EACCES}, + {ERRbadLogonTime, -EACCES}, + {ERRpasswordExpired, -EACCES}, + {ERRnosupport, -EINVAL}, + {0, 0} +}; + +const struct smb_to_posix_error mapping_table_ERRHRD[] = { + {0, 0} +}; + +/* Convert string containing dotted ip address to binary form */ +/* returns 0 if invalid address */ + +/* BB add address family, change rc to status flag and return union or for ipv6 */ +/* will need parent to call something like inet_pton to convert ipv6 address BB */ +int +cifs_inet_pton(int address_family, char *cp,void *dst) +{ + struct in_addr address; + int value; + int digit; + int i; + char temp; + char bytes[4]; + char *end = bytes; + static const int addr_class_max[4] = + { 0xffffffff, 0xffffff, 0xffff, 0xff }; + + if(address_family != AF_INET) + return -EAFNOSUPPORT; + + for (i = 0; i < 4; i++) { + bytes[i] = 0; + } + + temp = *cp; + + while (TRUE) { + if (!isdigit(temp)) + return 0; + + value = 0; + digit = 0; + for (;;) { + if (isascii(temp) && isdigit(temp)) { + value = (value * 10) + temp - '0'; + temp = *++cp; + digit = 1; + } else + break; + } + + if (temp == '.') { + if ((end > bytes + 2) || (value > 255)) + return 0; + *end++ = value; + temp = *++cp; + } else if (temp == ':') { + cFYI(1,("IPv6 addresses not supported for CIFS mounts yet")); + return -1; + } else + break; + } + + /* check for last characters */ + if (temp != '\0' && (!isascii(temp) || !isspace(temp))) + if (temp != '\\') { + if (temp != '/') + return 0; + else + (*cp = '\\'); /* switch the slash the expected way */ + } + if (value > addr_class_max[end - bytes]) + return 0; + + address.s_addr = *((int *) bytes) | htonl(value); + *((int *)dst) = address.s_addr; + return 1; /* success */ +} + +/***************************************************************************** +convert a NT status code to a dos class/code + *****************************************************************************/ +/* NT status -> dos error map */ +static const struct { + __u8 dos_class; + __u16 dos_code; + __u32 ntstatus; +} ntstatus_to_dos_map[] = { + { + ERRDOS, ERRgeneral, NT_STATUS_UNSUCCESSFUL}, { + ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED}, { + ERRDOS, 87, NT_STATUS_INVALID_INFO_CLASS}, { + ERRDOS, 24, NT_STATUS_INFO_LENGTH_MISMATCH}, { + ERRHRD, ERRgeneral, NT_STATUS_ACCESS_VIOLATION}, { + ERRHRD, ERRgeneral, NT_STATUS_IN_PAGE_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA}, { + ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_INITIAL_STACK}, { + ERRDOS, 193, NT_STATUS_BAD_INITIAL_PC}, { + ERRDOS, 87, NT_STATUS_INVALID_CID}, { + ERRHRD, ERRgeneral, NT_STATUS_TIMER_NOT_CANCELED}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER}, { + ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_DEVICE}, { + ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE}, { + ERRDOS, ERRbadfunc, NT_STATUS_INVALID_DEVICE_REQUEST}, { + ERRDOS, 38, NT_STATUS_END_OF_FILE}, { + ERRDOS, 34, NT_STATUS_WRONG_VOLUME}, { + ERRDOS, 21, NT_STATUS_NO_MEDIA_IN_DEVICE}, { + ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_MEDIA}, { + ERRDOS, 27, NT_STATUS_NONEXISTENT_SECTOR}, +/* { This NT error code was 'sqashed' + from NT_STATUS_MORE_PROCESSING_REQUIRED to NT_STATUS_OK + during the session setup } */ + { + ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY}, { + ERRDOS, 487, NT_STATUS_CONFLICTING_ADDRESSES}, { + ERRDOS, 487, NT_STATUS_NOT_MAPPED_VIEW}, { + ERRDOS, 87, NT_STATUS_UNABLE_TO_FREE_VM}, { + ERRDOS, 87, NT_STATUS_UNABLE_TO_DELETE_SECTION}, { + ERRDOS, 2142, NT_STATUS_INVALID_SYSTEM_SERVICE}, { + ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_INSTRUCTION}, { + ERRDOS, ERRnoaccess, NT_STATUS_INVALID_LOCK_SEQUENCE}, { + ERRDOS, ERRnoaccess, NT_STATUS_INVALID_VIEW_SIZE}, { + ERRDOS, 193, NT_STATUS_INVALID_FILE_FOR_SECTION}, { + ERRDOS, ERRnoaccess, NT_STATUS_ALREADY_COMMITTED}, +/* { This NT error code was 'sqashed' + from NT_STATUS_ACCESS_DENIED to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE + during the session setup } */ + { + ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED}, { + ERRDOS, 111, NT_STATUS_BUFFER_TOO_SMALL}, { + ERRDOS, ERRbadfid, NT_STATUS_OBJECT_TYPE_MISMATCH}, { + ERRHRD, ERRgeneral, NT_STATUS_NONCONTINUABLE_EXCEPTION}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_DISPOSITION}, { + ERRHRD, ERRgeneral, NT_STATUS_UNWIND}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_STACK}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_UNWIND_TARGET}, { + ERRDOS, 158, NT_STATUS_NOT_LOCKED}, { + ERRHRD, ERRgeneral, NT_STATUS_PARITY_ERROR}, { + ERRDOS, 487, NT_STATUS_UNABLE_TO_DECOMMIT_VM}, { + ERRDOS, 487, NT_STATUS_NOT_COMMITTED}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_PORT_ATTRIBUTES}, { + ERRHRD, ERRgeneral, NT_STATUS_PORT_MESSAGE_TOO_LONG}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_MIX}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_QUOTA_LOWER}, { + ERRHRD, ERRgeneral, NT_STATUS_DISK_CORRUPT_ERROR}, { + ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_INVALID}, { /* mapping changed since shell does lookup on * and expects file not found */ + ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND}, { + ERRDOS, ERRalreadyexists, NT_STATUS_OBJECT_NAME_COLLISION}, { + ERRHRD, ERRgeneral, NT_STATUS_HANDLE_NOT_WAITABLE}, { + ERRDOS, ERRbadfid, NT_STATUS_PORT_DISCONNECTED}, { + ERRHRD, ERRgeneral, NT_STATUS_DEVICE_ALREADY_ATTACHED}, { + ERRDOS, 161, NT_STATUS_OBJECT_PATH_INVALID}, { + ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND}, { + ERRDOS, 161, NT_STATUS_OBJECT_PATH_SYNTAX_BAD}, { + ERRHRD, ERRgeneral, NT_STATUS_DATA_OVERRUN}, { + ERRHRD, ERRgeneral, NT_STATUS_DATA_LATE_ERROR}, { + ERRDOS, 23, NT_STATUS_DATA_ERROR}, { + ERRDOS, 23, NT_STATUS_CRC_ERROR}, { + ERRDOS, ERRnomem, NT_STATUS_SECTION_TOO_BIG}, { + ERRDOS, ERRnoaccess, NT_STATUS_PORT_CONNECTION_REFUSED}, { + ERRDOS, ERRbadfid, NT_STATUS_INVALID_PORT_HANDLE}, { + ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION}, { + ERRHRD, ERRgeneral, NT_STATUS_QUOTA_EXCEEDED}, { + ERRDOS, 87, NT_STATUS_INVALID_PAGE_PROTECTION}, { + ERRDOS, 288, NT_STATUS_MUTANT_NOT_OWNED}, { + ERRDOS, 298, NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED}, { + ERRDOS, 87, NT_STATUS_PORT_ALREADY_SET}, { + ERRDOS, 87, NT_STATUS_SECTION_NOT_IMAGE}, { + ERRDOS, 156, NT_STATUS_SUSPEND_COUNT_EXCEEDED}, { + ERRDOS, ERRnoaccess, NT_STATUS_THREAD_IS_TERMINATING}, { + ERRDOS, 87, NT_STATUS_BAD_WORKING_SET_LIMIT}, { + ERRDOS, 87, NT_STATUS_INCOMPATIBLE_FILE_MAP}, { + ERRDOS, 87, NT_STATUS_SECTION_PROTECTION}, { + ERRDOS, 282, NT_STATUS_EAS_NOT_SUPPORTED}, { + ERRDOS, 255, NT_STATUS_EA_TOO_LARGE}, { + ERRHRD, ERRgeneral, NT_STATUS_NONEXISTENT_EA_ENTRY}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_EAS_ON_FILE}, { + ERRHRD, ERRgeneral, NT_STATUS_EA_CORRUPT_ERROR}, { + ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT}, { + ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED}, { + ERRDOS, ERRbadfile, NT_STATUS_DELETE_PENDING}, { + ERRDOS, ERRunsup, NT_STATUS_CTL_FILE_NOT_SUPPORTED}, { + ERRHRD, ERRgeneral, NT_STATUS_UNKNOWN_REVISION}, { + ERRHRD, ERRgeneral, NT_STATUS_REVISION_MISMATCH}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_OWNER}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_PRIMARY_GROUP}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_IMPERSONATION_TOKEN}, { + ERRHRD, ERRgeneral, NT_STATUS_CANT_DISABLE_MANDATORY}, { + ERRDOS, 2215, NT_STATUS_NO_LOGON_SERVERS}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_LOGON_SESSION}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PRIVILEGE}, { + ERRDOS, ERRnoaccess, NT_STATUS_PRIVILEGE_NOT_HELD}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACCOUNT_NAME}, { + ERRHRD, ERRgeneral, NT_STATUS_USER_EXISTS}, +/* { This NT error code was 'sqashed' + from NT_STATUS_NO_SUCH_USER to NT_STATUS_LOGON_FAILURE + during the session setup } */ + { + ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER}, { + ERRHRD, ERRgeneral, NT_STATUS_GROUP_EXISTS}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_GROUP}, { + ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_GROUP}, { + ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_GROUP}, { + ERRHRD, ERRgeneral, NT_STATUS_LAST_ADMIN}, +/* { This NT error code was 'sqashed' + from NT_STATUS_WRONG_PASSWORD to NT_STATUS_LOGON_FAILURE + during the session setup } */ + { + ERRSRV, ERRbadpw, NT_STATUS_WRONG_PASSWORD}, { + ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_PASSWORD}, { + ERRHRD, ERRgeneral, NT_STATUS_PASSWORD_RESTRICTION}, { + ERRDOS, ERRnoaccess, NT_STATUS_LOGON_FAILURE}, { + ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, { + ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS}, { + ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION}, { + ERRSRV, 2242, NT_STATUS_PASSWORD_EXPIRED}, { + ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED}, { + ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, { + ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, { + ERRHRD, ERRgeneral, NT_STATUS_LUIDS_EXHAUSTED}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_SUB_AUTHORITY}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACL}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_SID}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_SECURITY_DESCR}, { + ERRDOS, 127, NT_STATUS_PROCEDURE_NOT_FOUND}, { + ERRDOS, 193, NT_STATUS_INVALID_IMAGE_FORMAT}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_TOKEN}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_INHERITANCE_ACL}, { + ERRDOS, 158, NT_STATUS_RANGE_NOT_LOCKED}, { + ERRDOS, 112, NT_STATUS_DISK_FULL}, { + ERRHRD, ERRgeneral, NT_STATUS_SERVER_DISABLED}, { + ERRHRD, ERRgeneral, NT_STATUS_SERVER_NOT_DISABLED}, { + ERRDOS, 68, NT_STATUS_TOO_MANY_GUIDS_REQUESTED}, { + ERRDOS, 259, NT_STATUS_GUIDS_EXHAUSTED}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_ID_AUTHORITY}, { + ERRDOS, 259, NT_STATUS_AGENTS_EXHAUSTED}, { + ERRDOS, 154, NT_STATUS_INVALID_VOLUME_LABEL}, { + ERRDOS, 14, NT_STATUS_SECTION_NOT_EXTENDED}, { + ERRDOS, 487, NT_STATUS_NOT_MAPPED_DATA}, { + ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_DATA_NOT_FOUND}, { + ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_TYPE_NOT_FOUND}, { + ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_NAME_NOT_FOUND}, { + ERRHRD, ERRgeneral, NT_STATUS_ARRAY_BOUNDS_EXCEEDED}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DENORMAL_OPERAND}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DIVIDE_BY_ZERO}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INEXACT_RESULT}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INVALID_OPERATION}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOAT_OVERFLOW}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOAT_STACK_CHECK}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOAT_UNDERFLOW}, { + ERRHRD, ERRgeneral, NT_STATUS_INTEGER_DIVIDE_BY_ZERO}, { + ERRDOS, 534, NT_STATUS_INTEGER_OVERFLOW}, { + ERRHRD, ERRgeneral, NT_STATUS_PRIVILEGED_INSTRUCTION}, { + ERRDOS, ERRnomem, NT_STATUS_TOO_MANY_PAGING_FILES}, { + ERRHRD, ERRgeneral, NT_STATUS_FILE_INVALID}, { + ERRHRD, ERRgeneral, NT_STATUS_ALLOTTED_SPACE_EXCEEDED}, +/* { This NT error code was 'sqashed' + from NT_STATUS_INSUFFICIENT_RESOURCES to NT_STATUS_INSUFF_SERVER_RESOURCES + during the session setup } */ + { + ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES}, { + ERRDOS, ERRbadpath, NT_STATUS_DFS_EXIT_PATH_FOUND}, { + ERRDOS, 23, NT_STATUS_DEVICE_DATA_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_CONNECTED}, { + ERRDOS, 21, NT_STATUS_DEVICE_POWER_FAILURE}, { + ERRDOS, 487, NT_STATUS_FREE_VM_NOT_AT_BASE}, { + ERRDOS, 487, NT_STATUS_MEMORY_NOT_ALLOCATED}, { + ERRHRD, ERRgeneral, NT_STATUS_WORKING_SET_QUOTA}, { + ERRDOS, 19, NT_STATUS_MEDIA_WRITE_PROTECTED}, { + ERRDOS, 21, NT_STATUS_DEVICE_NOT_READY}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_GROUP_ATTRIBUTES}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_IMPERSONATION_LEVEL}, { + ERRHRD, ERRgeneral, NT_STATUS_CANT_OPEN_ANONYMOUS}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_VALIDATION_CLASS}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_TOKEN_TYPE}, { + ERRDOS, 87, NT_STATUS_BAD_MASTER_BOOT_RECORD}, { + ERRHRD, ERRgeneral, NT_STATUS_INSTRUCTION_MISALIGNMENT}, { + ERRDOS, ERRpipebusy, NT_STATUS_INSTANCE_NOT_AVAILABLE}, { + ERRDOS, ERRpipebusy, NT_STATUS_PIPE_NOT_AVAILABLE}, { + ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PIPE_STATE}, { + ERRDOS, ERRpipebusy, NT_STATUS_PIPE_BUSY}, { + ERRDOS, ERRbadfunc, NT_STATUS_ILLEGAL_FUNCTION}, { + ERRDOS, ERRnotconnected, NT_STATUS_PIPE_DISCONNECTED}, { + ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_CLOSING}, { + ERRHRD, ERRgeneral, NT_STATUS_PIPE_CONNECTED}, { + ERRHRD, ERRgeneral, NT_STATUS_PIPE_LISTENING}, { + ERRDOS, ERRbadpipe, NT_STATUS_INVALID_READ_MODE}, { + ERRDOS, 121, NT_STATUS_IO_TIMEOUT}, { + ERRDOS, 38, NT_STATUS_FILE_FORCED_CLOSED}, { + ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STARTED}, { + ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STOPPED}, { + ERRHRD, ERRgeneral, NT_STATUS_COULD_NOT_INTERPRET}, { + ERRDOS, ERRnoaccess, NT_STATUS_FILE_IS_A_DIRECTORY}, { + ERRDOS, ERRunsup, NT_STATUS_NOT_SUPPORTED}, { + ERRDOS, 51, NT_STATUS_REMOTE_NOT_LISTENING}, { + ERRDOS, 52, NT_STATUS_DUPLICATE_NAME}, { + ERRDOS, 53, NT_STATUS_BAD_NETWORK_PATH}, { + ERRDOS, 54, NT_STATUS_NETWORK_BUSY}, { + ERRDOS, 55, NT_STATUS_DEVICE_DOES_NOT_EXIST}, { + ERRDOS, 56, NT_STATUS_TOO_MANY_COMMANDS}, { + ERRDOS, 57, NT_STATUS_ADAPTER_HARDWARE_ERROR}, { + ERRDOS, 58, NT_STATUS_INVALID_NETWORK_RESPONSE}, { + ERRDOS, 59, NT_STATUS_UNEXPECTED_NETWORK_ERROR}, { + ERRDOS, 60, NT_STATUS_BAD_REMOTE_ADAPTER}, { + ERRDOS, 61, NT_STATUS_PRINT_QUEUE_FULL}, { + ERRDOS, 62, NT_STATUS_NO_SPOOL_SPACE}, { + ERRDOS, 63, NT_STATUS_PRINT_CANCELLED}, { + ERRDOS, 64, NT_STATUS_NETWORK_NAME_DELETED}, { + ERRDOS, 65, NT_STATUS_NETWORK_ACCESS_DENIED}, { + ERRDOS, 66, NT_STATUS_BAD_DEVICE_TYPE}, { + ERRDOS, ERRnosuchshare, NT_STATUS_BAD_NETWORK_NAME}, { + ERRDOS, 68, NT_STATUS_TOO_MANY_NAMES}, { + ERRDOS, 69, NT_STATUS_TOO_MANY_SESSIONS}, { + ERRDOS, 70, NT_STATUS_SHARING_PAUSED}, { + ERRDOS, 71, NT_STATUS_REQUEST_NOT_ACCEPTED}, { + ERRDOS, 72, NT_STATUS_REDIRECTOR_PAUSED}, { + ERRDOS, 88, NT_STATUS_NET_WRITE_FAULT}, { + ERRHRD, ERRgeneral, NT_STATUS_PROFILING_AT_LIMIT}, { + ERRDOS, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE}, { + ERRDOS, ERRnoaccess, NT_STATUS_FILE_RENAMED}, { + ERRDOS, 240, NT_STATUS_VIRTUAL_CIRCUIT_CLOSED}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_SECURITY_ON_OBJECT}, { + ERRHRD, ERRgeneral, NT_STATUS_CANT_WAIT}, { + ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_EMPTY}, { + ERRHRD, ERRgeneral, NT_STATUS_CANT_ACCESS_DOMAIN_INFO}, { + ERRHRD, ERRgeneral, NT_STATUS_CANT_TERMINATE_SELF}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_SERVER_STATE}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_STATE}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_ROLE}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_DOMAIN}, { + ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_EXISTS}, { + ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_LIMIT_EXCEEDED}, { + ERRDOS, 300, NT_STATUS_OPLOCK_NOT_GRANTED}, { + ERRDOS, 301, NT_STATUS_INVALID_OPLOCK_PROTOCOL}, { + ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_CORRUPTION}, { + ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_GENERIC_NOT_MAPPED}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_DESCRIPTOR_FORMAT}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_USER_BUFFER}, { + ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_IO_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_CREATE_ERR}, { + ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_MAP_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_EXTEND_ERR}, { + ERRHRD, ERRgeneral, NT_STATUS_NOT_LOGON_PROCESS}, { + ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_EXISTS}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_1}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_2}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_3}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_4}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_5}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_6}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_7}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_8}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_9}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_10}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_11}, { + ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_12}, { + ERRDOS, ERRbadpath, NT_STATUS_REDIRECTOR_NOT_STARTED}, { + ERRHRD, ERRgeneral, NT_STATUS_REDIRECTOR_STARTED}, { + ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PACKAGE}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_FUNCTION_TABLE}, { + ERRDOS, 203, 0xc0000100}, { + ERRDOS, 145, NT_STATUS_DIRECTORY_NOT_EMPTY}, { + ERRHRD, ERRgeneral, NT_STATUS_FILE_CORRUPT_ERROR}, { + ERRDOS, 267, NT_STATUS_NOT_A_DIRECTORY}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_LOGON_SESSION_STATE}, { + ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_COLLISION}, { + ERRDOS, 206, NT_STATUS_NAME_TOO_LONG}, { + ERRDOS, 2401, NT_STATUS_FILES_OPEN}, { + ERRDOS, 2404, NT_STATUS_CONNECTION_IN_USE}, { + ERRHRD, ERRgeneral, NT_STATUS_MESSAGE_NOT_FOUND}, { + ERRDOS, ERRnoaccess, NT_STATUS_PROCESS_IS_TERMINATING}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_LOGON_TYPE}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_GUID_TRANSLATION}, { + ERRHRD, ERRgeneral, NT_STATUS_CANNOT_IMPERSONATE}, { + ERRHRD, ERRgeneral, NT_STATUS_IMAGE_ALREADY_LOADED}, { + ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_PRESENT}, { + ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_NOT_EXIST}, { + ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_ALREADY_OWNED}, { + ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_LID_OWNER}, { + ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_COMMAND}, { + ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_LID}, { + ERRHRD, ERRgeneral, NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE}, { + ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_SELECTOR}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_LDT}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_SIZE}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_OFFSET}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_DESCRIPTOR}, { + ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NE_FORMAT}, { + ERRHRD, ERRgeneral, NT_STATUS_RXACT_INVALID_STATE}, { + ERRHRD, ERRgeneral, NT_STATUS_RXACT_COMMIT_FAILURE}, { + ERRHRD, ERRgeneral, NT_STATUS_MAPPED_FILE_SIZE_ZERO}, { + ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES}, { + ERRHRD, ERRgeneral, NT_STATUS_CANCELLED}, { + ERRDOS, ERRnoaccess, NT_STATUS_CANNOT_DELETE}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_COMPUTER_NAME}, { + ERRDOS, ERRnoaccess, NT_STATUS_FILE_DELETED}, { + ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_ACCOUNT}, { + ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_GROUP}, { + ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_USER}, { + ERRHRD, ERRgeneral, NT_STATUS_MEMBERS_PRIMARY_GROUP}, { + ERRDOS, ERRbadfid, NT_STATUS_FILE_CLOSED}, { + ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_THREADS}, { + ERRHRD, ERRgeneral, NT_STATUS_THREAD_NOT_IN_PROCESS}, { + ERRHRD, ERRgeneral, NT_STATUS_TOKEN_ALREADY_IN_USE}, { + ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA_EXCEEDED}, { + ERRHRD, ERRgeneral, NT_STATUS_COMMITMENT_LIMIT}, { + ERRDOS, 193, NT_STATUS_INVALID_IMAGE_LE_FORMAT}, { + ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NOT_MZ}, { + ERRDOS, 193, NT_STATUS_INVALID_IMAGE_PROTECT}, { + ERRDOS, 193, NT_STATUS_INVALID_IMAGE_WIN_16}, { + ERRHRD, ERRgeneral, NT_STATUS_LOGON_SERVER_CONFLICT}, { + ERRHRD, ERRgeneral, NT_STATUS_TIME_DIFFERENCE_AT_DC}, { + ERRHRD, ERRgeneral, NT_STATUS_SYNCHRONIZATION_REQUIRED}, { + ERRDOS, 126, NT_STATUS_DLL_NOT_FOUND}, { + ERRHRD, ERRgeneral, NT_STATUS_OPEN_FAILED}, { + ERRHRD, ERRgeneral, NT_STATUS_IO_PRIVILEGE_FAILED}, { + ERRDOS, 182, NT_STATUS_ORDINAL_NOT_FOUND}, { + ERRDOS, 127, NT_STATUS_ENTRYPOINT_NOT_FOUND}, { + ERRHRD, ERRgeneral, NT_STATUS_CONTROL_C_EXIT}, { + ERRDOS, 64, NT_STATUS_LOCAL_DISCONNECT}, { + ERRDOS, 64, NT_STATUS_REMOTE_DISCONNECT}, { + ERRDOS, 51, NT_STATUS_REMOTE_RESOURCES}, { + ERRDOS, 59, NT_STATUS_LINK_FAILED}, { + ERRDOS, 59, NT_STATUS_LINK_TIMEOUT}, { + ERRDOS, 59, NT_STATUS_INVALID_CONNECTION}, { + ERRDOS, 59, NT_STATUS_INVALID_ADDRESS}, { + ERRHRD, ERRgeneral, NT_STATUS_DLL_INIT_FAILED}, { + ERRHRD, ERRgeneral, NT_STATUS_MISSING_SYSTEMFILE}, { + ERRHRD, ERRgeneral, NT_STATUS_UNHANDLED_EXCEPTION}, { + ERRHRD, ERRgeneral, NT_STATUS_APP_INIT_FAILURE}, { + ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_CREATE_FAILED}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_PAGEFILE}, { + ERRDOS, 124, NT_STATUS_INVALID_LEVEL}, { + ERRDOS, 86, NT_STATUS_WRONG_PASSWORD_CORE}, { + ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_FLOAT_CONTEXT}, { + ERRDOS, 109, NT_STATUS_PIPE_BROKEN}, { + ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_CORRUPT}, { + ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_IO_FAILED}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_EVENT_PAIR}, { + ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_VOLUME}, { + ERRHRD, ERRgeneral, NT_STATUS_SERIAL_NO_DEVICE_INITED}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_ALIAS}, { + ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_ALIAS}, { + ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_ALIAS}, { + ERRHRD, ERRgeneral, NT_STATUS_ALIAS_EXISTS}, { + ERRHRD, ERRgeneral, NT_STATUS_LOGON_NOT_GRANTED}, { + ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SECRETS}, { + ERRHRD, ERRgeneral, NT_STATUS_SECRET_TOO_LONG}, { + ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_FULLSCREEN_MODE}, { + ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_CONTEXT_IDS}, { + ERRDOS, ERRnoaccess, NT_STATUS_LOGON_TYPE_NOT_GRANTED}, { + ERRHRD, ERRgeneral, NT_STATUS_NOT_REGISTRY_FILE}, { + ERRHRD, ERRgeneral, NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED}, { + ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_FT_MISSING_MEMBER}, { + ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_SERVICE_ENTRY}, { + ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_CHARACTER}, { + ERRHRD, ERRgeneral, NT_STATUS_UNMAPPABLE_CHARACTER}, { + ERRHRD, ERRgeneral, NT_STATUS_UNDEFINED_CHARACTER}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_VOLUME}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_WRONG_CYLINDER}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_UNKNOWN_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_BAD_REGISTERS}, { + ERRHRD, ERRgeneral, NT_STATUS_DISK_RECALIBRATE_FAILED}, { + ERRHRD, ERRgeneral, NT_STATUS_DISK_OPERATION_FAILED}, { + ERRHRD, ERRgeneral, NT_STATUS_DISK_RESET_FAILED}, { + ERRHRD, ERRgeneral, NT_STATUS_SHARED_IRQ_BUSY}, { + ERRHRD, ERRgeneral, NT_STATUS_FT_ORPHANING}, { + ERRHRD, ERRgeneral, 0xc000016e}, { + ERRHRD, ERRgeneral, 0xc000016f}, { + ERRHRD, ERRgeneral, 0xc0000170}, { + ERRHRD, ERRgeneral, 0xc0000171}, { + ERRHRD, ERRgeneral, NT_STATUS_PARTITION_FAILURE}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_BLOCK_LENGTH}, { + ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_PARTITIONED}, { + ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_LOCK_MEDIA}, { + ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_UNLOAD_MEDIA}, { + ERRHRD, ERRgeneral, NT_STATUS_EOM_OVERFLOW}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_MEDIA}, { + ERRHRD, ERRgeneral, 0xc0000179}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_MEMBER}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_MEMBER}, { + ERRHRD, ERRgeneral, NT_STATUS_KEY_DELETED}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_LOG_SPACE}, { + ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SIDS}, { + ERRHRD, ERRgeneral, NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED}, { + ERRHRD, ERRgeneral, NT_STATUS_KEY_HAS_CHILDREN}, { + ERRHRD, ERRgeneral, NT_STATUS_CHILD_MUST_BE_VOLATILE}, { + ERRDOS, 87, NT_STATUS_DEVICE_CONFIGURATION_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_DRIVER_INTERNAL_ERROR}, { + ERRDOS, 22, NT_STATUS_INVALID_DEVICE_STATE}, { + ERRHRD, ERRgeneral, NT_STATUS_IO_DEVICE_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_DEVICE_PROTOCOL_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_BACKUP_CONTROLLER}, { + ERRHRD, ERRgeneral, NT_STATUS_LOG_FILE_FULL}, { + ERRDOS, 19, NT_STATUS_TOO_LATE}, { + ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_LSA_SECRET}, +/* { This NT error code was 'sqashed' + from NT_STATUS_NO_TRUST_SAM_ACCOUNT to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE + during the session setup } */ + { + ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_SAM_ACCOUNT}, { + ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_DOMAIN_FAILURE}, { + ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE}, { + ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CORRUPT}, { + ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_CANT_START}, { + ERRDOS, ERRnoaccess, NT_STATUS_TRUST_FAILURE}, { + ERRHRD, ERRgeneral, NT_STATUS_MUTANT_LIMIT_EXCEEDED}, { + ERRDOS, ERRnetlogonNotStarted, NT_STATUS_NETLOGON_NOT_STARTED}, { + ERRSRV, 2239, NT_STATUS_ACCOUNT_EXPIRED}, { + ERRHRD, ERRgeneral, NT_STATUS_POSSIBLE_DEADLOCK}, { + ERRHRD, ERRgeneral, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT}, { + ERRHRD, ERRgeneral, NT_STATUS_REMOTE_SESSION_LIMIT}, { + ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CHANGED}, { + ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT}, { + ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT}, { + ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT}, +/* { This NT error code was 'sqashed' + from NT_STATUS_DOMAIN_TRUST_INCONSISTENT to NT_STATUS_LOGON_FAILURE + during the session setup } */ + { + ERRDOS, ERRnoaccess, NT_STATUS_DOMAIN_TRUST_INCONSISTENT}, { + ERRHRD, ERRgeneral, NT_STATUS_FS_DRIVER_REQUIRED}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_USER_SESSION_KEY}, { + ERRDOS, 59, NT_STATUS_USER_SESSION_DELETED}, { + ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_LANG_NOT_FOUND}, { + ERRDOS, ERRnomem, NT_STATUS_INSUFF_SERVER_RESOURCES}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_BUFFER_SIZE}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_COMPONENT}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_WILDCARD}, { + ERRDOS, 68, NT_STATUS_TOO_MANY_ADDRESSES}, { + ERRDOS, 52, NT_STATUS_ADDRESS_ALREADY_EXISTS}, { + ERRDOS, 64, NT_STATUS_ADDRESS_CLOSED}, { + ERRDOS, 64, NT_STATUS_CONNECTION_DISCONNECTED}, { + ERRDOS, 64, NT_STATUS_CONNECTION_RESET}, { + ERRDOS, 68, NT_STATUS_TOO_MANY_NODES}, { + ERRDOS, 59, NT_STATUS_TRANSACTION_ABORTED}, { + ERRDOS, 59, NT_STATUS_TRANSACTION_TIMED_OUT}, { + ERRDOS, 59, NT_STATUS_TRANSACTION_NO_RELEASE}, { + ERRDOS, 59, NT_STATUS_TRANSACTION_NO_MATCH}, { + ERRDOS, 59, NT_STATUS_TRANSACTION_RESPONDED}, { + ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_ID}, { + ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_TYPE}, { + ERRDOS, ERRunsup, NT_STATUS_NOT_SERVER_SESSION}, { + ERRDOS, ERRunsup, NT_STATUS_NOT_CLIENT_SESSION}, { + ERRHRD, ERRgeneral, NT_STATUS_CANNOT_LOAD_REGISTRY_FILE}, { + ERRHRD, ERRgeneral, NT_STATUS_DEBUG_ATTACH_FAILED}, { + ERRHRD, ERRgeneral, NT_STATUS_SYSTEM_PROCESS_TERMINATED}, { + ERRHRD, ERRgeneral, NT_STATUS_DATA_NOT_ACCEPTED}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_BROWSER_SERVERS_FOUND}, { + ERRHRD, ERRgeneral, NT_STATUS_VDM_HARD_ERROR}, { + ERRHRD, ERRgeneral, NT_STATUS_DRIVER_CANCEL_TIMEOUT}, { + ERRHRD, ERRgeneral, NT_STATUS_REPLY_MESSAGE_MISMATCH}, { + ERRHRD, ERRgeneral, NT_STATUS_MAPPED_ALIGNMENT}, { + ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, { + ERRHRD, ERRgeneral, NT_STATUS_LOST_WRITEBEHIND_DATA}, { + ERRHRD, ERRgeneral, NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID}, { + ERRSRV, 2242, NT_STATUS_PASSWORD_MUST_CHANGE}, { + ERRHRD, ERRgeneral, NT_STATUS_NOT_FOUND}, { + ERRHRD, ERRgeneral, NT_STATUS_NOT_TINY_STREAM}, { + ERRHRD, ERRgeneral, NT_STATUS_RECOVERY_FAILURE}, { + ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW_READ}, { + ERRHRD, ERRgeneral, NT_STATUS_FAIL_CHECK}, { + ERRHRD, ERRgeneral, NT_STATUS_DUPLICATE_OBJECTID}, { + ERRHRD, ERRgeneral, NT_STATUS_OBJECTID_EXISTS}, { + ERRHRD, ERRgeneral, NT_STATUS_CONVERT_TO_LARGE}, { + ERRHRD, ERRgeneral, NT_STATUS_RETRY}, { + ERRHRD, ERRgeneral, NT_STATUS_FOUND_OUT_OF_SCOPE}, { + ERRHRD, ERRgeneral, NT_STATUS_ALLOCATE_BUCKET}, { + ERRHRD, ERRgeneral, NT_STATUS_PROPSET_NOT_FOUND}, { + ERRHRD, ERRgeneral, NT_STATUS_MARSHALL_OVERFLOW}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_VARIANT}, { + ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND}, { + ERRDOS, ERRnoaccess, NT_STATUS_ACCOUNT_LOCKED_OUT}, { + ERRDOS, ERRbadfid, NT_STATUS_HANDLE_NOT_CLOSABLE}, { + ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_REFUSED}, { + ERRHRD, ERRgeneral, NT_STATUS_GRACEFUL_DISCONNECT}, { + ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_ALREADY_ASSOCIATED}, { + ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_NOT_ASSOCIATED}, { + ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_INVALID}, { + ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ACTIVE}, { + ERRHRD, ERRgeneral, NT_STATUS_NETWORK_UNREACHABLE}, { + ERRHRD, ERRgeneral, NT_STATUS_HOST_UNREACHABLE}, { + ERRHRD, ERRgeneral, NT_STATUS_PROTOCOL_UNREACHABLE}, { + ERRHRD, ERRgeneral, NT_STATUS_PORT_UNREACHABLE}, { + ERRHRD, ERRgeneral, NT_STATUS_REQUEST_ABORTED}, { + ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ABORTED}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_COMPRESSION_BUFFER}, { + ERRHRD, ERRgeneral, NT_STATUS_USER_MAPPED_FILE}, { + ERRHRD, ERRgeneral, NT_STATUS_AUDIT_FAILED}, { + ERRHRD, ERRgeneral, NT_STATUS_TIMER_RESOLUTION_NOT_SET}, { + ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_COUNT_LIMIT}, { + ERRHRD, ERRgeneral, NT_STATUS_LOGIN_TIME_RESTRICTION}, { + ERRHRD, ERRgeneral, NT_STATUS_LOGIN_WKSTA_RESTRICTION}, { + ERRDOS, 193, NT_STATUS_IMAGE_MP_UP_MISMATCH}, { + ERRHRD, ERRgeneral, 0xc000024a}, { + ERRHRD, ERRgeneral, 0xc000024b}, { + ERRHRD, ERRgeneral, 0xc000024c}, { + ERRHRD, ERRgeneral, 0xc000024d}, { + ERRHRD, ERRgeneral, 0xc000024e}, { + ERRHRD, ERRgeneral, 0xc000024f}, { + ERRHRD, ERRgeneral, NT_STATUS_INSUFFICIENT_LOGON_INFO}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_DLL_ENTRYPOINT}, { + ERRHRD, ERRgeneral, NT_STATUS_BAD_SERVICE_ENTRYPOINT}, { + ERRHRD, ERRgeneral, NT_STATUS_LPC_REPLY_LOST}, { + ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT1}, { + ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT2}, { + ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_QUOTA_LIMIT}, { + ERRSRV, 3, NT_STATUS_PATH_NOT_COVERED}, { + ERRHRD, ERRgeneral, NT_STATUS_NO_CALLBACK_ACTIVE}, { + ERRHRD, ERRgeneral, NT_STATUS_LICENSE_QUOTA_EXCEEDED}, { + ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_SHORT}, { + ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_RECENT}, { + ERRHRD, ERRgeneral, NT_STATUS_PWD_HISTORY_CONFLICT}, { + ERRHRD, ERRgeneral, 0xc000025d}, { + ERRHRD, ERRgeneral, NT_STATUS_PLUGPLAY_NO_DEVICE}, { + ERRHRD, ERRgeneral, NT_STATUS_UNSUPPORTED_COMPRESSION}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_HW_PROFILE}, { + ERRHRD, ERRgeneral, NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH}, { + ERRDOS, 182, NT_STATUS_DRIVER_ORDINAL_NOT_FOUND}, { + ERRDOS, 127, NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND}, { + ERRDOS, 288, NT_STATUS_RESOURCE_NOT_OWNED}, { + ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LINKS}, { + ERRHRD, ERRgeneral, NT_STATUS_QUOTA_LIST_INCONSISTENT}, { + ERRHRD, ERRgeneral, NT_STATUS_FILE_IS_OFFLINE}, { + ERRDOS, 21, 0xc000026e}, { + ERRDOS, 161, 0xc0000281}, { + ERRDOS, ERRnoaccess, 0xc000028a}, { + ERRDOS, ERRnoaccess, 0xc000028b}, { + ERRHRD, ERRgeneral, 0xc000028c}, { + ERRDOS, ERRnoaccess, 0xc000028d}, { + ERRDOS, ERRnoaccess, 0xc000028e}, { + ERRDOS, ERRnoaccess, 0xc000028f}, { + ERRDOS, ERRnoaccess, 0xc0000290}, { +ERRDOS, ERRbadfunc, 0xc000029c},}; + +/***************************************************************************** + Print an error message from the status code + *****************************************************************************/ +static void +cifs_print_status(__u32 status_code) +{ + int idx = 0; + + while (nt_errs[idx].nt_errstr != NULL) { + if (((nt_errs[idx].nt_errcode) & 0xFFFFFF) == + (status_code & 0xFFFFFF)) { + printk(KERN_NOTICE "Status code returned 0x%08x %s\n", + status_code,nt_errs[idx].nt_errstr); + } + idx++; + } + return; +} + + +static void +ntstatus_to_dos(__u32 ntstatus, __u8 * eclass, __u16 * ecode) +{ + int i; + if (ntstatus == 0) { + *eclass = 0; + *ecode = 0; + return; + } + for (i = 0; ntstatus_to_dos_map[i].ntstatus; i++) { + if (ntstatus == ntstatus_to_dos_map[i].ntstatus) { + *eclass = ntstatus_to_dos_map[i].dos_class; + *ecode = ntstatus_to_dos_map[i].dos_code; + return; + } + } + *eclass = ERRHRD; + *ecode = ERRgeneral; +} + +int +map_smb_to_linux_error(struct smb_hdr *smb) +{ + unsigned int i; + int rc = -EIO; /* if transport error smb error may not be set */ + __u8 smberrclass; + __u16 smberrcode; + + /* BB if NT Status codes - map NT BB */ + + /* old style smb error codes */ + if (smb->Status.CifsError == 0) + return 0; + + if (smb->Flags2 & SMBFLG2_ERR_STATUS) { + /* translate the newer STATUS codes to old style errors and then to POSIX errors */ + smb->Status.CifsError = le32_to_cpu(smb->Status.CifsError); + if(cifsFYI) + cifs_print_status(smb->Status.CifsError); + ntstatus_to_dos(smb->Status.CifsError, &smberrclass, + &smberrcode); + } else { + smberrclass = smb->Status.DosError.ErrorClass; + smb->Status.DosError.Error = + le16_to_cpu(smb->Status.DosError.Error); + smberrcode = smb->Status.DosError.Error; + } + + /* old style errors */ + + /* DOS class smb error codes - map DOS */ + if (smberrclass == ERRDOS) { /* one byte field no need to byte reverse */ + for (i = 0; + i < + sizeof (mapping_table_ERRDOS) / + sizeof (struct smb_to_posix_error); i++) { + if (mapping_table_ERRDOS[i].smb_err == 0) + break; + else if (mapping_table_ERRDOS[i].smb_err == smberrcode) { + rc = mapping_table_ERRDOS[i].posix_code; + break; + } + /* else try the next error mapping one to see if it will match */ + } + } else if (smberrclass == ERRSRV) { /* server class of error codes */ + for (i = 0; + i < + sizeof (mapping_table_ERRSRV) / + sizeof (struct smb_to_posix_error); i++) { + if (mapping_table_ERRSRV[i].smb_err == 0) + break; + else if (mapping_table_ERRSRV[i].smb_err == smberrcode) { + rc = mapping_table_ERRSRV[i].posix_code; + break; + } + /* else try the next error mapping one to see if it will match */ + } + } + /* else ERRHRD class errors or junk - return EIO */ + + cFYI(1, (" !!Mapping smb error code %d to POSIX err %d !!", smberrcode,rc)); + + /* generic corrective action e.g. reconnect SMB session on ERRbaduid could be added */ + + return rc; +} + +/* + * calculate the size of the SMB message based on the fixed header + * portion, the number of word parameters and the data portion of the message + */ +unsigned int +smbCalcSize(struct smb_hdr *ptr) +{ + return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + + BCC(ptr)); +} + +/* The following are taken from fs/ntfs/util.c */ + +#define NTFS_TIME_OFFSET ((u64)(369*365 + 89) * 24 * 3600 * 10000000) + + /* + * Convert the NT UTC (based 1601-01-01, in hundred nanosecond units) + * into Unix UTC (based 1970-01-01, in seconds). + */ +time_t +cifs_NTtimeToUnix(__u64 ntutc) +{ + /* BB what about the timezone? BB */ + + /* Subtract the NTFS time offset, then convert to 1s intervals. */ + u64 t; + + t = ntutc - NTFS_TIME_OFFSET; + do_div(t, 10000000); + return (time_t)t; +} + +/* Convert the Unix UTC into NT UTC. */ +__u64 +cifs_UnixTimeToNT(time_t t) +{ + __u64 dce_time; + /* Convert to 100ns intervals and then add the NTFS time offset. */ + dce_time = (__u64) t * 10000000; + dce_time += NTFS_TIME_OFFSET; + return dce_time; +} diff --git a/release/src/linux/linux/fs/cifs/nterr.c b/release/src/linux/linux/fs/cifs/nterr.c new file mode 100644 index 00000000..4da50cd3 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/nterr.c @@ -0,0 +1,687 @@ +/* + * Unix SMB/Netbios implementation. + * Version 1.9. + * RPC Pipe client / server routines + * Copyright (C) Luke Kenneth Casson Leighton 1997-2001. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* NT error codes - see nterr.h */ +#include <linux/types.h> +#include <linux/fs.h> +#include "nterr.h" + +const struct nt_err_code_struct nt_errs[] = { + {"NT_STATUS_OK", NT_STATUS_OK}, + {"NT_STATUS_UNSUCCESSFUL", NT_STATUS_UNSUCCESSFUL}, + {"NT_STATUS_NOT_IMPLEMENTED", NT_STATUS_NOT_IMPLEMENTED}, + {"NT_STATUS_INVALID_INFO_CLASS", NT_STATUS_INVALID_INFO_CLASS}, + {"NT_STATUS_INFO_LENGTH_MISMATCH", NT_STATUS_INFO_LENGTH_MISMATCH}, + {"NT_STATUS_ACCESS_VIOLATION", NT_STATUS_ACCESS_VIOLATION}, + {"STATUS_BUFFER_OVERFLOW", STATUS_BUFFER_OVERFLOW}, + {"NT_STATUS_IN_PAGE_ERROR", NT_STATUS_IN_PAGE_ERROR}, + {"NT_STATUS_PAGEFILE_QUOTA", NT_STATUS_PAGEFILE_QUOTA}, + {"NT_STATUS_INVALID_HANDLE", NT_STATUS_INVALID_HANDLE}, + {"NT_STATUS_BAD_INITIAL_STACK", NT_STATUS_BAD_INITIAL_STACK}, + {"NT_STATUS_BAD_INITIAL_PC", NT_STATUS_BAD_INITIAL_PC}, + {"NT_STATUS_INVALID_CID", NT_STATUS_INVALID_CID}, + {"NT_STATUS_TIMER_NOT_CANCELED", NT_STATUS_TIMER_NOT_CANCELED}, + {"NT_STATUS_INVALID_PARAMETER", NT_STATUS_INVALID_PARAMETER}, + {"NT_STATUS_NO_SUCH_DEVICE", NT_STATUS_NO_SUCH_DEVICE}, + {"NT_STATUS_NO_SUCH_FILE", NT_STATUS_NO_SUCH_FILE}, + {"NT_STATUS_INVALID_DEVICE_REQUEST", + NT_STATUS_INVALID_DEVICE_REQUEST}, + {"NT_STATUS_END_OF_FILE", NT_STATUS_END_OF_FILE}, + {"NT_STATUS_WRONG_VOLUME", NT_STATUS_WRONG_VOLUME}, + {"NT_STATUS_NO_MEDIA_IN_DEVICE", NT_STATUS_NO_MEDIA_IN_DEVICE}, + {"NT_STATUS_UNRECOGNIZED_MEDIA", NT_STATUS_UNRECOGNIZED_MEDIA}, + {"NT_STATUS_NONEXISTENT_SECTOR", NT_STATUS_NONEXISTENT_SECTOR}, + {"NT_STATUS_MORE_PROCESSING_REQUIRED", + NT_STATUS_MORE_PROCESSING_REQUIRED}, + {"NT_STATUS_NO_MEMORY", NT_STATUS_NO_MEMORY}, + {"NT_STATUS_CONFLICTING_ADDRESSES", + NT_STATUS_CONFLICTING_ADDRESSES}, + {"NT_STATUS_NOT_MAPPED_VIEW", NT_STATUS_NOT_MAPPED_VIEW}, + {"NT_STATUS_UNABLE_TO_FREE_VM", NT_STATUS_UNABLE_TO_FREE_VM}, + {"NT_STATUS_UNABLE_TO_DELETE_SECTION", + NT_STATUS_UNABLE_TO_DELETE_SECTION}, + {"NT_STATUS_INVALID_SYSTEM_SERVICE", + NT_STATUS_INVALID_SYSTEM_SERVICE}, + {"NT_STATUS_ILLEGAL_INSTRUCTION", NT_STATUS_ILLEGAL_INSTRUCTION}, + {"NT_STATUS_INVALID_LOCK_SEQUENCE", + NT_STATUS_INVALID_LOCK_SEQUENCE}, + {"NT_STATUS_INVALID_VIEW_SIZE", NT_STATUS_INVALID_VIEW_SIZE}, + {"NT_STATUS_INVALID_FILE_FOR_SECTION", + NT_STATUS_INVALID_FILE_FOR_SECTION}, + {"NT_STATUS_ALREADY_COMMITTED", NT_STATUS_ALREADY_COMMITTED}, + {"NT_STATUS_ACCESS_DENIED", NT_STATUS_ACCESS_DENIED}, + {"NT_STATUS_BUFFER_TOO_SMALL", NT_STATUS_BUFFER_TOO_SMALL}, + {"NT_STATUS_OBJECT_TYPE_MISMATCH", NT_STATUS_OBJECT_TYPE_MISMATCH}, + {"NT_STATUS_NONCONTINUABLE_EXCEPTION", + NT_STATUS_NONCONTINUABLE_EXCEPTION}, + {"NT_STATUS_INVALID_DISPOSITION", NT_STATUS_INVALID_DISPOSITION}, + {"NT_STATUS_UNWIND", NT_STATUS_UNWIND}, + {"NT_STATUS_BAD_STACK", NT_STATUS_BAD_STACK}, + {"NT_STATUS_INVALID_UNWIND_TARGET", + NT_STATUS_INVALID_UNWIND_TARGET}, + {"NT_STATUS_NOT_LOCKED", NT_STATUS_NOT_LOCKED}, + {"NT_STATUS_PARITY_ERROR", NT_STATUS_PARITY_ERROR}, + {"NT_STATUS_UNABLE_TO_DECOMMIT_VM", + NT_STATUS_UNABLE_TO_DECOMMIT_VM}, + {"NT_STATUS_NOT_COMMITTED", NT_STATUS_NOT_COMMITTED}, + {"NT_STATUS_INVALID_PORT_ATTRIBUTES", + NT_STATUS_INVALID_PORT_ATTRIBUTES}, + {"NT_STATUS_PORT_MESSAGE_TOO_LONG", + NT_STATUS_PORT_MESSAGE_TOO_LONG}, + {"NT_STATUS_INVALID_PARAMETER_MIX", + NT_STATUS_INVALID_PARAMETER_MIX}, + {"NT_STATUS_INVALID_QUOTA_LOWER", NT_STATUS_INVALID_QUOTA_LOWER}, + {"NT_STATUS_DISK_CORRUPT_ERROR", NT_STATUS_DISK_CORRUPT_ERROR}, + {"NT_STATUS_OBJECT_NAME_INVALID", NT_STATUS_OBJECT_NAME_INVALID}, + {"NT_STATUS_OBJECT_NAME_NOT_FOUND", + NT_STATUS_OBJECT_NAME_NOT_FOUND}, + {"NT_STATUS_OBJECT_NAME_COLLISION", + NT_STATUS_OBJECT_NAME_COLLISION}, + {"NT_STATUS_HANDLE_NOT_WAITABLE", NT_STATUS_HANDLE_NOT_WAITABLE}, + {"NT_STATUS_PORT_DISCONNECTED", NT_STATUS_PORT_DISCONNECTED}, + {"NT_STATUS_DEVICE_ALREADY_ATTACHED", + NT_STATUS_DEVICE_ALREADY_ATTACHED}, + {"NT_STATUS_OBJECT_PATH_INVALID", NT_STATUS_OBJECT_PATH_INVALID}, + {"NT_STATUS_OBJECT_PATH_NOT_FOUND", + NT_STATUS_OBJECT_PATH_NOT_FOUND}, + {"NT_STATUS_OBJECT_PATH_SYNTAX_BAD", + NT_STATUS_OBJECT_PATH_SYNTAX_BAD}, + {"NT_STATUS_DATA_OVERRUN", NT_STATUS_DATA_OVERRUN}, + {"NT_STATUS_DATA_LATE_ERROR", NT_STATUS_DATA_LATE_ERROR}, + {"NT_STATUS_DATA_ERROR", NT_STATUS_DATA_ERROR}, + {"NT_STATUS_CRC_ERROR", NT_STATUS_CRC_ERROR}, + {"NT_STATUS_SECTION_TOO_BIG", NT_STATUS_SECTION_TOO_BIG}, + {"NT_STATUS_PORT_CONNECTION_REFUSED", + NT_STATUS_PORT_CONNECTION_REFUSED}, + {"NT_STATUS_INVALID_PORT_HANDLE", NT_STATUS_INVALID_PORT_HANDLE}, + {"NT_STATUS_SHARING_VIOLATION", NT_STATUS_SHARING_VIOLATION}, + {"NT_STATUS_QUOTA_EXCEEDED", NT_STATUS_QUOTA_EXCEEDED}, + {"NT_STATUS_INVALID_PAGE_PROTECTION", + NT_STATUS_INVALID_PAGE_PROTECTION}, + {"NT_STATUS_MUTANT_NOT_OWNED", NT_STATUS_MUTANT_NOT_OWNED}, + {"NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED", + NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED}, + {"NT_STATUS_PORT_ALREADY_SET", NT_STATUS_PORT_ALREADY_SET}, + {"NT_STATUS_SECTION_NOT_IMAGE", NT_STATUS_SECTION_NOT_IMAGE}, + {"NT_STATUS_SUSPEND_COUNT_EXCEEDED", + NT_STATUS_SUSPEND_COUNT_EXCEEDED}, + {"NT_STATUS_THREAD_IS_TERMINATING", + NT_STATUS_THREAD_IS_TERMINATING}, + {"NT_STATUS_BAD_WORKING_SET_LIMIT", + NT_STATUS_BAD_WORKING_SET_LIMIT}, + {"NT_STATUS_INCOMPATIBLE_FILE_MAP", + NT_STATUS_INCOMPATIBLE_FILE_MAP}, + {"NT_STATUS_SECTION_PROTECTION", NT_STATUS_SECTION_PROTECTION}, + {"NT_STATUS_EAS_NOT_SUPPORTED", NT_STATUS_EAS_NOT_SUPPORTED}, + {"NT_STATUS_EA_TOO_LARGE", NT_STATUS_EA_TOO_LARGE}, + {"NT_STATUS_NONEXISTENT_EA_ENTRY", NT_STATUS_NONEXISTENT_EA_ENTRY}, + {"NT_STATUS_NO_EAS_ON_FILE", NT_STATUS_NO_EAS_ON_FILE}, + {"NT_STATUS_EA_CORRUPT_ERROR", NT_STATUS_EA_CORRUPT_ERROR}, + {"NT_STATUS_FILE_LOCK_CONFLICT", NT_STATUS_FILE_LOCK_CONFLICT}, + {"NT_STATUS_LOCK_NOT_GRANTED", NT_STATUS_LOCK_NOT_GRANTED}, + {"NT_STATUS_DELETE_PENDING", NT_STATUS_DELETE_PENDING}, + {"NT_STATUS_CTL_FILE_NOT_SUPPORTED", + NT_STATUS_CTL_FILE_NOT_SUPPORTED}, + {"NT_STATUS_UNKNOWN_REVISION", NT_STATUS_UNKNOWN_REVISION}, + {"NT_STATUS_REVISION_MISMATCH", NT_STATUS_REVISION_MISMATCH}, + {"NT_STATUS_INVALID_OWNER", NT_STATUS_INVALID_OWNER}, + {"NT_STATUS_INVALID_PRIMARY_GROUP", + NT_STATUS_INVALID_PRIMARY_GROUP}, + {"NT_STATUS_NO_IMPERSONATION_TOKEN", + NT_STATUS_NO_IMPERSONATION_TOKEN}, + {"NT_STATUS_CANT_DISABLE_MANDATORY", + NT_STATUS_CANT_DISABLE_MANDATORY}, + {"NT_STATUS_NO_LOGON_SERVERS", NT_STATUS_NO_LOGON_SERVERS}, + {"NT_STATUS_NO_SUCH_LOGON_SESSION", + NT_STATUS_NO_SUCH_LOGON_SESSION}, + {"NT_STATUS_NO_SUCH_PRIVILEGE", NT_STATUS_NO_SUCH_PRIVILEGE}, + {"NT_STATUS_PRIVILEGE_NOT_HELD", NT_STATUS_PRIVILEGE_NOT_HELD}, + {"NT_STATUS_INVALID_ACCOUNT_NAME", NT_STATUS_INVALID_ACCOUNT_NAME}, + {"NT_STATUS_USER_EXISTS", NT_STATUS_USER_EXISTS}, + {"NT_STATUS_NO_SUCH_USER", NT_STATUS_NO_SUCH_USER}, + {"NT_STATUS_GROUP_EXISTS", NT_STATUS_GROUP_EXISTS}, + {"NT_STATUS_NO_SUCH_GROUP", NT_STATUS_NO_SUCH_GROUP}, + {"NT_STATUS_MEMBER_IN_GROUP", NT_STATUS_MEMBER_IN_GROUP}, + {"NT_STATUS_MEMBER_NOT_IN_GROUP", NT_STATUS_MEMBER_NOT_IN_GROUP}, + {"NT_STATUS_LAST_ADMIN", NT_STATUS_LAST_ADMIN}, + {"NT_STATUS_WRONG_PASSWORD", NT_STATUS_WRONG_PASSWORD}, + {"NT_STATUS_ILL_FORMED_PASSWORD", NT_STATUS_ILL_FORMED_PASSWORD}, + {"NT_STATUS_PASSWORD_RESTRICTION", NT_STATUS_PASSWORD_RESTRICTION}, + {"NT_STATUS_LOGON_FAILURE", NT_STATUS_LOGON_FAILURE}, + {"NT_STATUS_ACCOUNT_RESTRICTION", NT_STATUS_ACCOUNT_RESTRICTION}, + {"NT_STATUS_INVALID_LOGON_HOURS", NT_STATUS_INVALID_LOGON_HOURS}, + {"NT_STATUS_INVALID_WORKSTATION", NT_STATUS_INVALID_WORKSTATION}, + {"NT_STATUS_PASSWORD_EXPIRED", NT_STATUS_PASSWORD_EXPIRED}, + {"NT_STATUS_ACCOUNT_DISABLED", NT_STATUS_ACCOUNT_DISABLED}, + {"NT_STATUS_NONE_MAPPED", NT_STATUS_NONE_MAPPED}, + {"NT_STATUS_TOO_MANY_LUIDS_REQUESTED", + NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, + {"NT_STATUS_LUIDS_EXHAUSTED", NT_STATUS_LUIDS_EXHAUSTED}, + {"NT_STATUS_INVALID_SUB_AUTHORITY", + NT_STATUS_INVALID_SUB_AUTHORITY}, + {"NT_STATUS_INVALID_ACL", NT_STATUS_INVALID_ACL}, + {"NT_STATUS_INVALID_SID", NT_STATUS_INVALID_SID}, + {"NT_STATUS_INVALID_SECURITY_DESCR", + NT_STATUS_INVALID_SECURITY_DESCR}, + {"NT_STATUS_PROCEDURE_NOT_FOUND", NT_STATUS_PROCEDURE_NOT_FOUND}, + {"NT_STATUS_INVALID_IMAGE_FORMAT", NT_STATUS_INVALID_IMAGE_FORMAT}, + {"NT_STATUS_NO_TOKEN", NT_STATUS_NO_TOKEN}, + {"NT_STATUS_BAD_INHERITANCE_ACL", NT_STATUS_BAD_INHERITANCE_ACL}, + {"NT_STATUS_RANGE_NOT_LOCKED", NT_STATUS_RANGE_NOT_LOCKED}, + {"NT_STATUS_DISK_FULL", NT_STATUS_DISK_FULL}, + {"NT_STATUS_SERVER_DISABLED", NT_STATUS_SERVER_DISABLED}, + {"NT_STATUS_SERVER_NOT_DISABLED", NT_STATUS_SERVER_NOT_DISABLED}, + {"NT_STATUS_TOO_MANY_GUIDS_REQUESTED", + NT_STATUS_TOO_MANY_GUIDS_REQUESTED}, + {"NT_STATUS_GUIDS_EXHAUSTED", NT_STATUS_GUIDS_EXHAUSTED}, + {"NT_STATUS_INVALID_ID_AUTHORITY", NT_STATUS_INVALID_ID_AUTHORITY}, + {"NT_STATUS_AGENTS_EXHAUSTED", NT_STATUS_AGENTS_EXHAUSTED}, + {"NT_STATUS_INVALID_VOLUME_LABEL", NT_STATUS_INVALID_VOLUME_LABEL}, + {"NT_STATUS_SECTION_NOT_EXTENDED", NT_STATUS_SECTION_NOT_EXTENDED}, + {"NT_STATUS_NOT_MAPPED_DATA", NT_STATUS_NOT_MAPPED_DATA}, + {"NT_STATUS_RESOURCE_DATA_NOT_FOUND", + NT_STATUS_RESOURCE_DATA_NOT_FOUND}, + {"NT_STATUS_RESOURCE_TYPE_NOT_FOUND", + NT_STATUS_RESOURCE_TYPE_NOT_FOUND}, + {"NT_STATUS_RESOURCE_NAME_NOT_FOUND", + NT_STATUS_RESOURCE_NAME_NOT_FOUND}, + {"NT_STATUS_ARRAY_BOUNDS_EXCEEDED", + NT_STATUS_ARRAY_BOUNDS_EXCEEDED}, + {"NT_STATUS_FLOAT_DENORMAL_OPERAND", + NT_STATUS_FLOAT_DENORMAL_OPERAND}, + {"NT_STATUS_FLOAT_DIVIDE_BY_ZERO", NT_STATUS_FLOAT_DIVIDE_BY_ZERO}, + {"NT_STATUS_FLOAT_INEXACT_RESULT", NT_STATUS_FLOAT_INEXACT_RESULT}, + {"NT_STATUS_FLOAT_INVALID_OPERATION", + NT_STATUS_FLOAT_INVALID_OPERATION}, + {"NT_STATUS_FLOAT_OVERFLOW", NT_STATUS_FLOAT_OVERFLOW}, + {"NT_STATUS_FLOAT_STACK_CHECK", NT_STATUS_FLOAT_STACK_CHECK}, + {"NT_STATUS_FLOAT_UNDERFLOW", NT_STATUS_FLOAT_UNDERFLOW}, + {"NT_STATUS_INTEGER_DIVIDE_BY_ZERO", + NT_STATUS_INTEGER_DIVIDE_BY_ZERO}, + {"NT_STATUS_INTEGER_OVERFLOW", NT_STATUS_INTEGER_OVERFLOW}, + {"NT_STATUS_PRIVILEGED_INSTRUCTION", + NT_STATUS_PRIVILEGED_INSTRUCTION}, + {"NT_STATUS_TOO_MANY_PAGING_FILES", + NT_STATUS_TOO_MANY_PAGING_FILES}, + {"NT_STATUS_FILE_INVALID", NT_STATUS_FILE_INVALID}, + {"NT_STATUS_ALLOTTED_SPACE_EXCEEDED", + NT_STATUS_ALLOTTED_SPACE_EXCEEDED}, + {"NT_STATUS_INSUFFICIENT_RESOURCES", + NT_STATUS_INSUFFICIENT_RESOURCES}, + {"NT_STATUS_DFS_EXIT_PATH_FOUND", NT_STATUS_DFS_EXIT_PATH_FOUND}, + {"NT_STATUS_DEVICE_DATA_ERROR", NT_STATUS_DEVICE_DATA_ERROR}, + {"NT_STATUS_DEVICE_NOT_CONNECTED", NT_STATUS_DEVICE_NOT_CONNECTED}, + {"NT_STATUS_DEVICE_POWER_FAILURE", NT_STATUS_DEVICE_POWER_FAILURE}, + {"NT_STATUS_FREE_VM_NOT_AT_BASE", NT_STATUS_FREE_VM_NOT_AT_BASE}, + {"NT_STATUS_MEMORY_NOT_ALLOCATED", NT_STATUS_MEMORY_NOT_ALLOCATED}, + {"NT_STATUS_WORKING_SET_QUOTA", NT_STATUS_WORKING_SET_QUOTA}, + {"NT_STATUS_MEDIA_WRITE_PROTECTED", + NT_STATUS_MEDIA_WRITE_PROTECTED}, + {"NT_STATUS_DEVICE_NOT_READY", NT_STATUS_DEVICE_NOT_READY}, + {"NT_STATUS_INVALID_GROUP_ATTRIBUTES", + NT_STATUS_INVALID_GROUP_ATTRIBUTES}, + {"NT_STATUS_BAD_IMPERSONATION_LEVEL", + NT_STATUS_BAD_IMPERSONATION_LEVEL}, + {"NT_STATUS_CANT_OPEN_ANONYMOUS", NT_STATUS_CANT_OPEN_ANONYMOUS}, + {"NT_STATUS_BAD_VALIDATION_CLASS", NT_STATUS_BAD_VALIDATION_CLASS}, + {"NT_STATUS_BAD_TOKEN_TYPE", NT_STATUS_BAD_TOKEN_TYPE}, + {"NT_STATUS_BAD_MASTER_BOOT_RECORD", + NT_STATUS_BAD_MASTER_BOOT_RECORD}, + {"NT_STATUS_INSTRUCTION_MISALIGNMENT", + NT_STATUS_INSTRUCTION_MISALIGNMENT}, + {"NT_STATUS_INSTANCE_NOT_AVAILABLE", + NT_STATUS_INSTANCE_NOT_AVAILABLE}, + {"NT_STATUS_PIPE_NOT_AVAILABLE", NT_STATUS_PIPE_NOT_AVAILABLE}, + {"NT_STATUS_INVALID_PIPE_STATE", NT_STATUS_INVALID_PIPE_STATE}, + {"NT_STATUS_PIPE_BUSY", NT_STATUS_PIPE_BUSY}, + {"NT_STATUS_ILLEGAL_FUNCTION", NT_STATUS_ILLEGAL_FUNCTION}, + {"NT_STATUS_PIPE_DISCONNECTED", NT_STATUS_PIPE_DISCONNECTED}, + {"NT_STATUS_PIPE_CLOSING", NT_STATUS_PIPE_CLOSING}, + {"NT_STATUS_PIPE_CONNECTED", NT_STATUS_PIPE_CONNECTED}, + {"NT_STATUS_PIPE_LISTENING", NT_STATUS_PIPE_LISTENING}, + {"NT_STATUS_INVALID_READ_MODE", NT_STATUS_INVALID_READ_MODE}, + {"NT_STATUS_IO_TIMEOUT", NT_STATUS_IO_TIMEOUT}, + {"NT_STATUS_FILE_FORCED_CLOSED", NT_STATUS_FILE_FORCED_CLOSED}, + {"NT_STATUS_PROFILING_NOT_STARTED", + NT_STATUS_PROFILING_NOT_STARTED}, + {"NT_STATUS_PROFILING_NOT_STOPPED", + NT_STATUS_PROFILING_NOT_STOPPED}, + {"NT_STATUS_COULD_NOT_INTERPRET", NT_STATUS_COULD_NOT_INTERPRET}, + {"NT_STATUS_FILE_IS_A_DIRECTORY", NT_STATUS_FILE_IS_A_DIRECTORY}, + {"NT_STATUS_NOT_SUPPORTED", NT_STATUS_NOT_SUPPORTED}, + {"NT_STATUS_REMOTE_NOT_LISTENING", NT_STATUS_REMOTE_NOT_LISTENING}, + {"NT_STATUS_DUPLICATE_NAME", NT_STATUS_DUPLICATE_NAME}, + {"NT_STATUS_BAD_NETWORK_PATH", NT_STATUS_BAD_NETWORK_PATH}, + {"NT_STATUS_NETWORK_BUSY", NT_STATUS_NETWORK_BUSY}, + {"NT_STATUS_DEVICE_DOES_NOT_EXIST", + NT_STATUS_DEVICE_DOES_NOT_EXIST}, + {"NT_STATUS_TOO_MANY_COMMANDS", NT_STATUS_TOO_MANY_COMMANDS}, + {"NT_STATUS_ADAPTER_HARDWARE_ERROR", + NT_STATUS_ADAPTER_HARDWARE_ERROR}, + {"NT_STATUS_INVALID_NETWORK_RESPONSE", + NT_STATUS_INVALID_NETWORK_RESPONSE}, + {"NT_STATUS_UNEXPECTED_NETWORK_ERROR", + NT_STATUS_UNEXPECTED_NETWORK_ERROR}, + {"NT_STATUS_BAD_REMOTE_ADAPTER", NT_STATUS_BAD_REMOTE_ADAPTER}, + {"NT_STATUS_PRINT_QUEUE_FULL", NT_STATUS_PRINT_QUEUE_FULL}, + {"NT_STATUS_NO_SPOOL_SPACE", NT_STATUS_NO_SPOOL_SPACE}, + {"NT_STATUS_PRINT_CANCELLED", NT_STATUS_PRINT_CANCELLED}, + {"NT_STATUS_NETWORK_NAME_DELETED", NT_STATUS_NETWORK_NAME_DELETED}, + {"NT_STATUS_NETWORK_ACCESS_DENIED", + NT_STATUS_NETWORK_ACCESS_DENIED}, + {"NT_STATUS_BAD_DEVICE_TYPE", NT_STATUS_BAD_DEVICE_TYPE}, + {"NT_STATUS_BAD_NETWORK_NAME", NT_STATUS_BAD_NETWORK_NAME}, + {"NT_STATUS_TOO_MANY_NAMES", NT_STATUS_TOO_MANY_NAMES}, + {"NT_STATUS_TOO_MANY_SESSIONS", NT_STATUS_TOO_MANY_SESSIONS}, + {"NT_STATUS_SHARING_PAUSED", NT_STATUS_SHARING_PAUSED}, + {"NT_STATUS_REQUEST_NOT_ACCEPTED", NT_STATUS_REQUEST_NOT_ACCEPTED}, + {"NT_STATUS_REDIRECTOR_PAUSED", NT_STATUS_REDIRECTOR_PAUSED}, + {"NT_STATUS_NET_WRITE_FAULT", NT_STATUS_NET_WRITE_FAULT}, + {"NT_STATUS_PROFILING_AT_LIMIT", NT_STATUS_PROFILING_AT_LIMIT}, + {"NT_STATUS_NOT_SAME_DEVICE", NT_STATUS_NOT_SAME_DEVICE}, + {"NT_STATUS_FILE_RENAMED", NT_STATUS_FILE_RENAMED}, + {"NT_STATUS_VIRTUAL_CIRCUIT_CLOSED", + NT_STATUS_VIRTUAL_CIRCUIT_CLOSED}, + {"NT_STATUS_NO_SECURITY_ON_OBJECT", + NT_STATUS_NO_SECURITY_ON_OBJECT}, + {"NT_STATUS_CANT_WAIT", NT_STATUS_CANT_WAIT}, + {"NT_STATUS_PIPE_EMPTY", NT_STATUS_PIPE_EMPTY}, + {"NT_STATUS_CANT_ACCESS_DOMAIN_INFO", + NT_STATUS_CANT_ACCESS_DOMAIN_INFO}, + {"NT_STATUS_CANT_TERMINATE_SELF", NT_STATUS_CANT_TERMINATE_SELF}, + {"NT_STATUS_INVALID_SERVER_STATE", NT_STATUS_INVALID_SERVER_STATE}, + {"NT_STATUS_INVALID_DOMAIN_STATE", NT_STATUS_INVALID_DOMAIN_STATE}, + {"NT_STATUS_INVALID_DOMAIN_ROLE", NT_STATUS_INVALID_DOMAIN_ROLE}, + {"NT_STATUS_NO_SUCH_DOMAIN", NT_STATUS_NO_SUCH_DOMAIN}, + {"NT_STATUS_DOMAIN_EXISTS", NT_STATUS_DOMAIN_EXISTS}, + {"NT_STATUS_DOMAIN_LIMIT_EXCEEDED", + NT_STATUS_DOMAIN_LIMIT_EXCEEDED}, + {"NT_STATUS_OPLOCK_NOT_GRANTED", NT_STATUS_OPLOCK_NOT_GRANTED}, + {"NT_STATUS_INVALID_OPLOCK_PROTOCOL", + NT_STATUS_INVALID_OPLOCK_PROTOCOL}, + {"NT_STATUS_INTERNAL_DB_CORRUPTION", + NT_STATUS_INTERNAL_DB_CORRUPTION}, + {"NT_STATUS_INTERNAL_ERROR", NT_STATUS_INTERNAL_ERROR}, + {"NT_STATUS_GENERIC_NOT_MAPPED", NT_STATUS_GENERIC_NOT_MAPPED}, + {"NT_STATUS_BAD_DESCRIPTOR_FORMAT", + NT_STATUS_BAD_DESCRIPTOR_FORMAT}, + {"NT_STATUS_INVALID_USER_BUFFER", NT_STATUS_INVALID_USER_BUFFER}, + {"NT_STATUS_UNEXPECTED_IO_ERROR", NT_STATUS_UNEXPECTED_IO_ERROR}, + {"NT_STATUS_UNEXPECTED_MM_CREATE_ERR", + NT_STATUS_UNEXPECTED_MM_CREATE_ERR}, + {"NT_STATUS_UNEXPECTED_MM_MAP_ERROR", + NT_STATUS_UNEXPECTED_MM_MAP_ERROR}, + {"NT_STATUS_UNEXPECTED_MM_EXTEND_ERR", + NT_STATUS_UNEXPECTED_MM_EXTEND_ERR}, + {"NT_STATUS_NOT_LOGON_PROCESS", NT_STATUS_NOT_LOGON_PROCESS}, + {"NT_STATUS_LOGON_SESSION_EXISTS", NT_STATUS_LOGON_SESSION_EXISTS}, + {"NT_STATUS_INVALID_PARAMETER_1", NT_STATUS_INVALID_PARAMETER_1}, + {"NT_STATUS_INVALID_PARAMETER_2", NT_STATUS_INVALID_PARAMETER_2}, + {"NT_STATUS_INVALID_PARAMETER_3", NT_STATUS_INVALID_PARAMETER_3}, + {"NT_STATUS_INVALID_PARAMETER_4", NT_STATUS_INVALID_PARAMETER_4}, + {"NT_STATUS_INVALID_PARAMETER_5", NT_STATUS_INVALID_PARAMETER_5}, + {"NT_STATUS_INVALID_PARAMETER_6", NT_STATUS_INVALID_PARAMETER_6}, + {"NT_STATUS_INVALID_PARAMETER_7", NT_STATUS_INVALID_PARAMETER_7}, + {"NT_STATUS_INVALID_PARAMETER_8", NT_STATUS_INVALID_PARAMETER_8}, + {"NT_STATUS_INVALID_PARAMETER_9", NT_STATUS_INVALID_PARAMETER_9}, + {"NT_STATUS_INVALID_PARAMETER_10", NT_STATUS_INVALID_PARAMETER_10}, + {"NT_STATUS_INVALID_PARAMETER_11", NT_STATUS_INVALID_PARAMETER_11}, + {"NT_STATUS_INVALID_PARAMETER_12", NT_STATUS_INVALID_PARAMETER_12}, + {"NT_STATUS_REDIRECTOR_NOT_STARTED", + NT_STATUS_REDIRECTOR_NOT_STARTED}, + {"NT_STATUS_REDIRECTOR_STARTED", NT_STATUS_REDIRECTOR_STARTED}, + {"NT_STATUS_STACK_OVERFLOW", NT_STATUS_STACK_OVERFLOW}, + {"NT_STATUS_NO_SUCH_PACKAGE", NT_STATUS_NO_SUCH_PACKAGE}, + {"NT_STATUS_BAD_FUNCTION_TABLE", NT_STATUS_BAD_FUNCTION_TABLE}, + {"NT_STATUS_DIRECTORY_NOT_EMPTY", NT_STATUS_DIRECTORY_NOT_EMPTY}, + {"NT_STATUS_FILE_CORRUPT_ERROR", NT_STATUS_FILE_CORRUPT_ERROR}, + {"NT_STATUS_NOT_A_DIRECTORY", NT_STATUS_NOT_A_DIRECTORY}, + {"NT_STATUS_BAD_LOGON_SESSION_STATE", + NT_STATUS_BAD_LOGON_SESSION_STATE}, + {"NT_STATUS_LOGON_SESSION_COLLISION", + NT_STATUS_LOGON_SESSION_COLLISION}, + {"NT_STATUS_NAME_TOO_LONG", NT_STATUS_NAME_TOO_LONG}, + {"NT_STATUS_FILES_OPEN", NT_STATUS_FILES_OPEN}, + {"NT_STATUS_CONNECTION_IN_USE", NT_STATUS_CONNECTION_IN_USE}, + {"NT_STATUS_MESSAGE_NOT_FOUND", NT_STATUS_MESSAGE_NOT_FOUND}, + {"NT_STATUS_PROCESS_IS_TERMINATING", + NT_STATUS_PROCESS_IS_TERMINATING}, + {"NT_STATUS_INVALID_LOGON_TYPE", NT_STATUS_INVALID_LOGON_TYPE}, + {"NT_STATUS_NO_GUID_TRANSLATION", NT_STATUS_NO_GUID_TRANSLATION}, + {"NT_STATUS_CANNOT_IMPERSONATE", NT_STATUS_CANNOT_IMPERSONATE}, + {"NT_STATUS_IMAGE_ALREADY_LOADED", NT_STATUS_IMAGE_ALREADY_LOADED}, + {"NT_STATUS_ABIOS_NOT_PRESENT", NT_STATUS_ABIOS_NOT_PRESENT}, + {"NT_STATUS_ABIOS_LID_NOT_EXIST", NT_STATUS_ABIOS_LID_NOT_EXIST}, + {"NT_STATUS_ABIOS_LID_ALREADY_OWNED", + NT_STATUS_ABIOS_LID_ALREADY_OWNED}, + {"NT_STATUS_ABIOS_NOT_LID_OWNER", NT_STATUS_ABIOS_NOT_LID_OWNER}, + {"NT_STATUS_ABIOS_INVALID_COMMAND", + NT_STATUS_ABIOS_INVALID_COMMAND}, + {"NT_STATUS_ABIOS_INVALID_LID", NT_STATUS_ABIOS_INVALID_LID}, + {"NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE", + NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE}, + {"NT_STATUS_ABIOS_INVALID_SELECTOR", + NT_STATUS_ABIOS_INVALID_SELECTOR}, + {"NT_STATUS_NO_LDT", NT_STATUS_NO_LDT}, + {"NT_STATUS_INVALID_LDT_SIZE", NT_STATUS_INVALID_LDT_SIZE}, + {"NT_STATUS_INVALID_LDT_OFFSET", NT_STATUS_INVALID_LDT_OFFSET}, + {"NT_STATUS_INVALID_LDT_DESCRIPTOR", + NT_STATUS_INVALID_LDT_DESCRIPTOR}, + {"NT_STATUS_INVALID_IMAGE_NE_FORMAT", + NT_STATUS_INVALID_IMAGE_NE_FORMAT}, + {"NT_STATUS_RXACT_INVALID_STATE", NT_STATUS_RXACT_INVALID_STATE}, + {"NT_STATUS_RXACT_COMMIT_FAILURE", NT_STATUS_RXACT_COMMIT_FAILURE}, + {"NT_STATUS_MAPPED_FILE_SIZE_ZERO", + NT_STATUS_MAPPED_FILE_SIZE_ZERO}, + {"NT_STATUS_TOO_MANY_OPENED_FILES", + NT_STATUS_TOO_MANY_OPENED_FILES}, + {"NT_STATUS_CANCELLED", NT_STATUS_CANCELLED}, + {"NT_STATUS_CANNOT_DELETE", NT_STATUS_CANNOT_DELETE}, + {"NT_STATUS_INVALID_COMPUTER_NAME", + NT_STATUS_INVALID_COMPUTER_NAME}, + {"NT_STATUS_FILE_DELETED", NT_STATUS_FILE_DELETED}, + {"NT_STATUS_SPECIAL_ACCOUNT", NT_STATUS_SPECIAL_ACCOUNT}, + {"NT_STATUS_SPECIAL_GROUP", NT_STATUS_SPECIAL_GROUP}, + {"NT_STATUS_SPECIAL_USER", NT_STATUS_SPECIAL_USER}, + {"NT_STATUS_MEMBERS_PRIMARY_GROUP", + NT_STATUS_MEMBERS_PRIMARY_GROUP}, + {"NT_STATUS_FILE_CLOSED", NT_STATUS_FILE_CLOSED}, + {"NT_STATUS_TOO_MANY_THREADS", NT_STATUS_TOO_MANY_THREADS}, + {"NT_STATUS_THREAD_NOT_IN_PROCESS", + NT_STATUS_THREAD_NOT_IN_PROCESS}, + {"NT_STATUS_TOKEN_ALREADY_IN_USE", NT_STATUS_TOKEN_ALREADY_IN_USE}, + {"NT_STATUS_PAGEFILE_QUOTA_EXCEEDED", + NT_STATUS_PAGEFILE_QUOTA_EXCEEDED}, + {"NT_STATUS_COMMITMENT_LIMIT", NT_STATUS_COMMITMENT_LIMIT}, + {"NT_STATUS_INVALID_IMAGE_LE_FORMAT", + NT_STATUS_INVALID_IMAGE_LE_FORMAT}, + {"NT_STATUS_INVALID_IMAGE_NOT_MZ", NT_STATUS_INVALID_IMAGE_NOT_MZ}, + {"NT_STATUS_INVALID_IMAGE_PROTECT", + NT_STATUS_INVALID_IMAGE_PROTECT}, + {"NT_STATUS_INVALID_IMAGE_WIN_16", NT_STATUS_INVALID_IMAGE_WIN_16}, + {"NT_STATUS_LOGON_SERVER_CONFLICT", + NT_STATUS_LOGON_SERVER_CONFLICT}, + {"NT_STATUS_TIME_DIFFERENCE_AT_DC", + NT_STATUS_TIME_DIFFERENCE_AT_DC}, + {"NT_STATUS_SYNCHRONIZATION_REQUIRED", + NT_STATUS_SYNCHRONIZATION_REQUIRED}, + {"NT_STATUS_DLL_NOT_FOUND", NT_STATUS_DLL_NOT_FOUND}, + {"NT_STATUS_OPEN_FAILED", NT_STATUS_OPEN_FAILED}, + {"NT_STATUS_IO_PRIVILEGE_FAILED", NT_STATUS_IO_PRIVILEGE_FAILED}, + {"NT_STATUS_ORDINAL_NOT_FOUND", NT_STATUS_ORDINAL_NOT_FOUND}, + {"NT_STATUS_ENTRYPOINT_NOT_FOUND", NT_STATUS_ENTRYPOINT_NOT_FOUND}, + {"NT_STATUS_CONTROL_C_EXIT", NT_STATUS_CONTROL_C_EXIT}, + {"NT_STATUS_LOCAL_DISCONNECT", NT_STATUS_LOCAL_DISCONNECT}, + {"NT_STATUS_REMOTE_DISCONNECT", NT_STATUS_REMOTE_DISCONNECT}, + {"NT_STATUS_REMOTE_RESOURCES", NT_STATUS_REMOTE_RESOURCES}, + {"NT_STATUS_LINK_FAILED", NT_STATUS_LINK_FAILED}, + {"NT_STATUS_LINK_TIMEOUT", NT_STATUS_LINK_TIMEOUT}, + {"NT_STATUS_INVALID_CONNECTION", NT_STATUS_INVALID_CONNECTION}, + {"NT_STATUS_INVALID_ADDRESS", NT_STATUS_INVALID_ADDRESS}, + {"NT_STATUS_DLL_INIT_FAILED", NT_STATUS_DLL_INIT_FAILED}, + {"NT_STATUS_MISSING_SYSTEMFILE", NT_STATUS_MISSING_SYSTEMFILE}, + {"NT_STATUS_UNHANDLED_EXCEPTION", NT_STATUS_UNHANDLED_EXCEPTION}, + {"NT_STATUS_APP_INIT_FAILURE", NT_STATUS_APP_INIT_FAILURE}, + {"NT_STATUS_PAGEFILE_CREATE_FAILED", + NT_STATUS_PAGEFILE_CREATE_FAILED}, + {"NT_STATUS_NO_PAGEFILE", NT_STATUS_NO_PAGEFILE}, + {"NT_STATUS_INVALID_LEVEL", NT_STATUS_INVALID_LEVEL}, + {"NT_STATUS_WRONG_PASSWORD_CORE", NT_STATUS_WRONG_PASSWORD_CORE}, + {"NT_STATUS_ILLEGAL_FLOAT_CONTEXT", + NT_STATUS_ILLEGAL_FLOAT_CONTEXT}, + {"NT_STATUS_PIPE_BROKEN", NT_STATUS_PIPE_BROKEN}, + {"NT_STATUS_REGISTRY_CORRUPT", NT_STATUS_REGISTRY_CORRUPT}, + {"NT_STATUS_REGISTRY_IO_FAILED", NT_STATUS_REGISTRY_IO_FAILED}, + {"NT_STATUS_NO_EVENT_PAIR", NT_STATUS_NO_EVENT_PAIR}, + {"NT_STATUS_UNRECOGNIZED_VOLUME", NT_STATUS_UNRECOGNIZED_VOLUME}, + {"NT_STATUS_SERIAL_NO_DEVICE_INITED", + NT_STATUS_SERIAL_NO_DEVICE_INITED}, + {"NT_STATUS_NO_SUCH_ALIAS", NT_STATUS_NO_SUCH_ALIAS}, + {"NT_STATUS_MEMBER_NOT_IN_ALIAS", NT_STATUS_MEMBER_NOT_IN_ALIAS}, + {"NT_STATUS_MEMBER_IN_ALIAS", NT_STATUS_MEMBER_IN_ALIAS}, + {"NT_STATUS_ALIAS_EXISTS", NT_STATUS_ALIAS_EXISTS}, + {"NT_STATUS_LOGON_NOT_GRANTED", NT_STATUS_LOGON_NOT_GRANTED}, + {"NT_STATUS_TOO_MANY_SECRETS", NT_STATUS_TOO_MANY_SECRETS}, + {"NT_STATUS_SECRET_TOO_LONG", NT_STATUS_SECRET_TOO_LONG}, + {"NT_STATUS_INTERNAL_DB_ERROR", NT_STATUS_INTERNAL_DB_ERROR}, + {"NT_STATUS_FULLSCREEN_MODE", NT_STATUS_FULLSCREEN_MODE}, + {"NT_STATUS_TOO_MANY_CONTEXT_IDS", NT_STATUS_TOO_MANY_CONTEXT_IDS}, + {"NT_STATUS_LOGON_TYPE_NOT_GRANTED", + NT_STATUS_LOGON_TYPE_NOT_GRANTED}, + {"NT_STATUS_NOT_REGISTRY_FILE", NT_STATUS_NOT_REGISTRY_FILE}, + {"NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED", + NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED}, + {"NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR", + NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR}, + {"NT_STATUS_FT_MISSING_MEMBER", NT_STATUS_FT_MISSING_MEMBER}, + {"NT_STATUS_ILL_FORMED_SERVICE_ENTRY", + NT_STATUS_ILL_FORMED_SERVICE_ENTRY}, + {"NT_STATUS_ILLEGAL_CHARACTER", NT_STATUS_ILLEGAL_CHARACTER}, + {"NT_STATUS_UNMAPPABLE_CHARACTER", NT_STATUS_UNMAPPABLE_CHARACTER}, + {"NT_STATUS_UNDEFINED_CHARACTER", NT_STATUS_UNDEFINED_CHARACTER}, + {"NT_STATUS_FLOPPY_VOLUME", NT_STATUS_FLOPPY_VOLUME}, + {"NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND", + NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND}, + {"NT_STATUS_FLOPPY_WRONG_CYLINDER", + NT_STATUS_FLOPPY_WRONG_CYLINDER}, + {"NT_STATUS_FLOPPY_UNKNOWN_ERROR", NT_STATUS_FLOPPY_UNKNOWN_ERROR}, + {"NT_STATUS_FLOPPY_BAD_REGISTERS", NT_STATUS_FLOPPY_BAD_REGISTERS}, + {"NT_STATUS_DISK_RECALIBRATE_FAILED", + NT_STATUS_DISK_RECALIBRATE_FAILED}, + {"NT_STATUS_DISK_OPERATION_FAILED", + NT_STATUS_DISK_OPERATION_FAILED}, + {"NT_STATUS_DISK_RESET_FAILED", NT_STATUS_DISK_RESET_FAILED}, + {"NT_STATUS_SHARED_IRQ_BUSY", NT_STATUS_SHARED_IRQ_BUSY}, + {"NT_STATUS_FT_ORPHANING", NT_STATUS_FT_ORPHANING}, + {"NT_STATUS_PARTITION_FAILURE", NT_STATUS_PARTITION_FAILURE}, + {"NT_STATUS_INVALID_BLOCK_LENGTH", NT_STATUS_INVALID_BLOCK_LENGTH}, + {"NT_STATUS_DEVICE_NOT_PARTITIONED", + NT_STATUS_DEVICE_NOT_PARTITIONED}, + {"NT_STATUS_UNABLE_TO_LOCK_MEDIA", NT_STATUS_UNABLE_TO_LOCK_MEDIA}, + {"NT_STATUS_UNABLE_TO_UNLOAD_MEDIA", + NT_STATUS_UNABLE_TO_UNLOAD_MEDIA}, + {"NT_STATUS_EOM_OVERFLOW", NT_STATUS_EOM_OVERFLOW}, + {"NT_STATUS_NO_MEDIA", NT_STATUS_NO_MEDIA}, + {"NT_STATUS_NO_SUCH_MEMBER", NT_STATUS_NO_SUCH_MEMBER}, + {"NT_STATUS_INVALID_MEMBER", NT_STATUS_INVALID_MEMBER}, + {"NT_STATUS_KEY_DELETED", NT_STATUS_KEY_DELETED}, + {"NT_STATUS_NO_LOG_SPACE", NT_STATUS_NO_LOG_SPACE}, + {"NT_STATUS_TOO_MANY_SIDS", NT_STATUS_TOO_MANY_SIDS}, + {"NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED", + NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED}, + {"NT_STATUS_KEY_HAS_CHILDREN", NT_STATUS_KEY_HAS_CHILDREN}, + {"NT_STATUS_CHILD_MUST_BE_VOLATILE", + NT_STATUS_CHILD_MUST_BE_VOLATILE}, + {"NT_STATUS_DEVICE_CONFIGURATION_ERROR", + NT_STATUS_DEVICE_CONFIGURATION_ERROR}, + {"NT_STATUS_DRIVER_INTERNAL_ERROR", + NT_STATUS_DRIVER_INTERNAL_ERROR}, + {"NT_STATUS_INVALID_DEVICE_STATE", NT_STATUS_INVALID_DEVICE_STATE}, + {"NT_STATUS_IO_DEVICE_ERROR", NT_STATUS_IO_DEVICE_ERROR}, + {"NT_STATUS_DEVICE_PROTOCOL_ERROR", + NT_STATUS_DEVICE_PROTOCOL_ERROR}, + {"NT_STATUS_BACKUP_CONTROLLER", NT_STATUS_BACKUP_CONTROLLER}, + {"NT_STATUS_LOG_FILE_FULL", NT_STATUS_LOG_FILE_FULL}, + {"NT_STATUS_TOO_LATE", NT_STATUS_TOO_LATE}, + {"NT_STATUS_NO_TRUST_LSA_SECRET", NT_STATUS_NO_TRUST_LSA_SECRET}, + {"NT_STATUS_NO_TRUST_SAM_ACCOUNT", NT_STATUS_NO_TRUST_SAM_ACCOUNT}, + {"NT_STATUS_TRUSTED_DOMAIN_FAILURE", + NT_STATUS_TRUSTED_DOMAIN_FAILURE}, + {"NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE", + NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE}, + {"NT_STATUS_EVENTLOG_FILE_CORRUPT", + NT_STATUS_EVENTLOG_FILE_CORRUPT}, + {"NT_STATUS_EVENTLOG_CANT_START", NT_STATUS_EVENTLOG_CANT_START}, + {"NT_STATUS_TRUST_FAILURE", NT_STATUS_TRUST_FAILURE}, + {"NT_STATUS_MUTANT_LIMIT_EXCEEDED", + NT_STATUS_MUTANT_LIMIT_EXCEEDED}, + {"NT_STATUS_NETLOGON_NOT_STARTED", NT_STATUS_NETLOGON_NOT_STARTED}, + {"NT_STATUS_ACCOUNT_EXPIRED", NT_STATUS_ACCOUNT_EXPIRED}, + {"NT_STATUS_POSSIBLE_DEADLOCK", NT_STATUS_POSSIBLE_DEADLOCK}, + {"NT_STATUS_NETWORK_CREDENTIAL_CONFLICT", + NT_STATUS_NETWORK_CREDENTIAL_CONFLICT}, + {"NT_STATUS_REMOTE_SESSION_LIMIT", NT_STATUS_REMOTE_SESSION_LIMIT}, + {"NT_STATUS_EVENTLOG_FILE_CHANGED", + NT_STATUS_EVENTLOG_FILE_CHANGED}, + {"NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT", + NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT}, + {"NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT", + NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT}, + {"NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT", + NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT}, + {"NT_STATUS_DOMAIN_TRUST_INCONSISTENT", + NT_STATUS_DOMAIN_TRUST_INCONSISTENT}, + {"NT_STATUS_FS_DRIVER_REQUIRED", NT_STATUS_FS_DRIVER_REQUIRED}, + {"NT_STATUS_NO_USER_SESSION_KEY", NT_STATUS_NO_USER_SESSION_KEY}, + {"NT_STATUS_USER_SESSION_DELETED", NT_STATUS_USER_SESSION_DELETED}, + {"NT_STATUS_RESOURCE_LANG_NOT_FOUND", + NT_STATUS_RESOURCE_LANG_NOT_FOUND}, + {"NT_STATUS_INSUFF_SERVER_RESOURCES", + NT_STATUS_INSUFF_SERVER_RESOURCES}, + {"NT_STATUS_INVALID_BUFFER_SIZE", NT_STATUS_INVALID_BUFFER_SIZE}, + {"NT_STATUS_INVALID_ADDRESS_COMPONENT", + NT_STATUS_INVALID_ADDRESS_COMPONENT}, + {"NT_STATUS_INVALID_ADDRESS_WILDCARD", + NT_STATUS_INVALID_ADDRESS_WILDCARD}, + {"NT_STATUS_TOO_MANY_ADDRESSES", NT_STATUS_TOO_MANY_ADDRESSES}, + {"NT_STATUS_ADDRESS_ALREADY_EXISTS", + NT_STATUS_ADDRESS_ALREADY_EXISTS}, + {"NT_STATUS_ADDRESS_CLOSED", NT_STATUS_ADDRESS_CLOSED}, + {"NT_STATUS_CONNECTION_DISCONNECTED", + NT_STATUS_CONNECTION_DISCONNECTED}, + {"NT_STATUS_CONNECTION_RESET", NT_STATUS_CONNECTION_RESET}, + {"NT_STATUS_TOO_MANY_NODES", NT_STATUS_TOO_MANY_NODES}, + {"NT_STATUS_TRANSACTION_ABORTED", NT_STATUS_TRANSACTION_ABORTED}, + {"NT_STATUS_TRANSACTION_TIMED_OUT", + NT_STATUS_TRANSACTION_TIMED_OUT}, + {"NT_STATUS_TRANSACTION_NO_RELEASE", + NT_STATUS_TRANSACTION_NO_RELEASE}, + {"NT_STATUS_TRANSACTION_NO_MATCH", NT_STATUS_TRANSACTION_NO_MATCH}, + {"NT_STATUS_TRANSACTION_RESPONDED", + NT_STATUS_TRANSACTION_RESPONDED}, + {"NT_STATUS_TRANSACTION_INVALID_ID", + NT_STATUS_TRANSACTION_INVALID_ID}, + {"NT_STATUS_TRANSACTION_INVALID_TYPE", + NT_STATUS_TRANSACTION_INVALID_TYPE}, + {"NT_STATUS_NOT_SERVER_SESSION", NT_STATUS_NOT_SERVER_SESSION}, + {"NT_STATUS_NOT_CLIENT_SESSION", NT_STATUS_NOT_CLIENT_SESSION}, + {"NT_STATUS_CANNOT_LOAD_REGISTRY_FILE", + NT_STATUS_CANNOT_LOAD_REGISTRY_FILE}, + {"NT_STATUS_DEBUG_ATTACH_FAILED", NT_STATUS_DEBUG_ATTACH_FAILED}, + {"NT_STATUS_SYSTEM_PROCESS_TERMINATED", + NT_STATUS_SYSTEM_PROCESS_TERMINATED}, + {"NT_STATUS_DATA_NOT_ACCEPTED", NT_STATUS_DATA_NOT_ACCEPTED}, + {"NT_STATUS_NO_BROWSER_SERVERS_FOUND", + NT_STATUS_NO_BROWSER_SERVERS_FOUND}, + {"NT_STATUS_VDM_HARD_ERROR", NT_STATUS_VDM_HARD_ERROR}, + {"NT_STATUS_DRIVER_CANCEL_TIMEOUT", + NT_STATUS_DRIVER_CANCEL_TIMEOUT}, + {"NT_STATUS_REPLY_MESSAGE_MISMATCH", + NT_STATUS_REPLY_MESSAGE_MISMATCH}, + {"NT_STATUS_MAPPED_ALIGNMENT", NT_STATUS_MAPPED_ALIGNMENT}, + {"NT_STATUS_IMAGE_CHECKSUM_MISMATCH", + NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, + {"NT_STATUS_LOST_WRITEBEHIND_DATA", + NT_STATUS_LOST_WRITEBEHIND_DATA}, + {"NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID", + NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID}, + {"NT_STATUS_PASSWORD_MUST_CHANGE", NT_STATUS_PASSWORD_MUST_CHANGE}, + {"NT_STATUS_NOT_FOUND", NT_STATUS_NOT_FOUND}, + {"NT_STATUS_NOT_TINY_STREAM", NT_STATUS_NOT_TINY_STREAM}, + {"NT_STATUS_RECOVERY_FAILURE", NT_STATUS_RECOVERY_FAILURE}, + {"NT_STATUS_STACK_OVERFLOW_READ", NT_STATUS_STACK_OVERFLOW_READ}, + {"NT_STATUS_FAIL_CHECK", NT_STATUS_FAIL_CHECK}, + {"NT_STATUS_DUPLICATE_OBJECTID", NT_STATUS_DUPLICATE_OBJECTID}, + {"NT_STATUS_OBJECTID_EXISTS", NT_STATUS_OBJECTID_EXISTS}, + {"NT_STATUS_CONVERT_TO_LARGE", NT_STATUS_CONVERT_TO_LARGE}, + {"NT_STATUS_RETRY", NT_STATUS_RETRY}, + {"NT_STATUS_FOUND_OUT_OF_SCOPE", NT_STATUS_FOUND_OUT_OF_SCOPE}, + {"NT_STATUS_ALLOCATE_BUCKET", NT_STATUS_ALLOCATE_BUCKET}, + {"NT_STATUS_PROPSET_NOT_FOUND", NT_STATUS_PROPSET_NOT_FOUND}, + {"NT_STATUS_MARSHALL_OVERFLOW", NT_STATUS_MARSHALL_OVERFLOW}, + {"NT_STATUS_INVALID_VARIANT", NT_STATUS_INVALID_VARIANT}, + {"NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND", + NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND}, + {"NT_STATUS_ACCOUNT_LOCKED_OUT", NT_STATUS_ACCOUNT_LOCKED_OUT}, + {"NT_STATUS_HANDLE_NOT_CLOSABLE", NT_STATUS_HANDLE_NOT_CLOSABLE}, + {"NT_STATUS_CONNECTION_REFUSED", NT_STATUS_CONNECTION_REFUSED}, + {"NT_STATUS_GRACEFUL_DISCONNECT", NT_STATUS_GRACEFUL_DISCONNECT}, + {"NT_STATUS_ADDRESS_ALREADY_ASSOCIATED", + NT_STATUS_ADDRESS_ALREADY_ASSOCIATED}, + {"NT_STATUS_ADDRESS_NOT_ASSOCIATED", + NT_STATUS_ADDRESS_NOT_ASSOCIATED}, + {"NT_STATUS_CONNECTION_INVALID", NT_STATUS_CONNECTION_INVALID}, + {"NT_STATUS_CONNECTION_ACTIVE", NT_STATUS_CONNECTION_ACTIVE}, + {"NT_STATUS_NETWORK_UNREACHABLE", NT_STATUS_NETWORK_UNREACHABLE}, + {"NT_STATUS_HOST_UNREACHABLE", NT_STATUS_HOST_UNREACHABLE}, + {"NT_STATUS_PROTOCOL_UNREACHABLE", NT_STATUS_PROTOCOL_UNREACHABLE}, + {"NT_STATUS_PORT_UNREACHABLE", NT_STATUS_PORT_UNREACHABLE}, + {"NT_STATUS_REQUEST_ABORTED", NT_STATUS_REQUEST_ABORTED}, + {"NT_STATUS_CONNECTION_ABORTED", NT_STATUS_CONNECTION_ABORTED}, + {"NT_STATUS_BAD_COMPRESSION_BUFFER", + NT_STATUS_BAD_COMPRESSION_BUFFER}, + {"NT_STATUS_USER_MAPPED_FILE", NT_STATUS_USER_MAPPED_FILE}, + {"NT_STATUS_AUDIT_FAILED", NT_STATUS_AUDIT_FAILED}, + {"NT_STATUS_TIMER_RESOLUTION_NOT_SET", + NT_STATUS_TIMER_RESOLUTION_NOT_SET}, + {"NT_STATUS_CONNECTION_COUNT_LIMIT", + NT_STATUS_CONNECTION_COUNT_LIMIT}, + {"NT_STATUS_LOGIN_TIME_RESTRICTION", + NT_STATUS_LOGIN_TIME_RESTRICTION}, + {"NT_STATUS_LOGIN_WKSTA_RESTRICTION", + NT_STATUS_LOGIN_WKSTA_RESTRICTION}, + {"NT_STATUS_IMAGE_MP_UP_MISMATCH", NT_STATUS_IMAGE_MP_UP_MISMATCH}, + {"NT_STATUS_INSUFFICIENT_LOGON_INFO", + NT_STATUS_INSUFFICIENT_LOGON_INFO}, + {"NT_STATUS_BAD_DLL_ENTRYPOINT", NT_STATUS_BAD_DLL_ENTRYPOINT}, + {"NT_STATUS_BAD_SERVICE_ENTRYPOINT", + NT_STATUS_BAD_SERVICE_ENTRYPOINT}, + {"NT_STATUS_LPC_REPLY_LOST", NT_STATUS_LPC_REPLY_LOST}, + {"NT_STATUS_IP_ADDRESS_CONFLICT1", NT_STATUS_IP_ADDRESS_CONFLICT1}, + {"NT_STATUS_IP_ADDRESS_CONFLICT2", NT_STATUS_IP_ADDRESS_CONFLICT2}, + {"NT_STATUS_REGISTRY_QUOTA_LIMIT", NT_STATUS_REGISTRY_QUOTA_LIMIT}, + {"NT_STATUS_PATH_NOT_COVERED", NT_STATUS_PATH_NOT_COVERED}, + {"NT_STATUS_NO_CALLBACK_ACTIVE", NT_STATUS_NO_CALLBACK_ACTIVE}, + {"NT_STATUS_LICENSE_QUOTA_EXCEEDED", + NT_STATUS_LICENSE_QUOTA_EXCEEDED}, + {"NT_STATUS_PWD_TOO_SHORT", NT_STATUS_PWD_TOO_SHORT}, + {"NT_STATUS_PWD_TOO_RECENT", NT_STATUS_PWD_TOO_RECENT}, + {"NT_STATUS_PWD_HISTORY_CONFLICT", NT_STATUS_PWD_HISTORY_CONFLICT}, + {"NT_STATUS_PLUGPLAY_NO_DEVICE", NT_STATUS_PLUGPLAY_NO_DEVICE}, + {"NT_STATUS_UNSUPPORTED_COMPRESSION", + NT_STATUS_UNSUPPORTED_COMPRESSION}, + {"NT_STATUS_INVALID_HW_PROFILE", NT_STATUS_INVALID_HW_PROFILE}, + {"NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH", + NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH}, + {"NT_STATUS_DRIVER_ORDINAL_NOT_FOUND", + NT_STATUS_DRIVER_ORDINAL_NOT_FOUND}, + {"NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND", + NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND}, + {"NT_STATUS_RESOURCE_NOT_OWNED", NT_STATUS_RESOURCE_NOT_OWNED}, + {"NT_STATUS_TOO_MANY_LINKS", NT_STATUS_TOO_MANY_LINKS}, + {"NT_STATUS_QUOTA_LIST_INCONSISTENT", + NT_STATUS_QUOTA_LIST_INCONSISTENT}, + {"NT_STATUS_FILE_IS_OFFLINE", NT_STATUS_FILE_IS_OFFLINE}, + {"NT_STATUS_NO_MORE_ENTRIES", NT_STATUS_NO_MORE_ENTRIES}, + {"STATUS_MORE_ENTRIES", STATUS_MORE_ENTRIES}, + {"STATUS_SOME_UNMAPPED", STATUS_SOME_UNMAPPED}, + {NULL, 0} +}; diff --git a/release/src/linux/linux/fs/cifs/nterr.h b/release/src/linux/linux/fs/cifs/nterr.h new file mode 100644 index 00000000..d2fb06c9 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/nterr.h @@ -0,0 +1,556 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + NT error code constants + Copyright (C) Andrew Tridgell 1992-2000 + Copyright (C) John H Terpstra 1996-2000 + Copyright (C) Luke Kenneth Casson Leighton 1996-2000 + Copyright (C) Paul Ashton 1998-2000 + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + + +#ifndef _NTERR_H +#define _NTERR_H + +struct nt_err_code_struct { + char *nt_errstr; + __u32 nt_errcode; +}; + +extern const struct nt_err_code_struct nt_errs[]; + +/* Win32 Status codes. */ + +#define STATUS_BUFFER_OVERFLOW 0x80000005 +#define STATUS_MORE_ENTRIES 0x0105 +#define ERROR_INVALID_PARAMETER 0x0057 +#define ERROR_INSUFFICIENT_BUFFER 0x007a +#define STATUS_1804 0x070c +#define STATUS_NOTIFY_ENUM_DIR 0x010c + +/* Win32 Error codes extracted using a loop in smbclient then printing a + netmon sniff to a file. */ + +#define NT_STATUS_OK 0x0000 +#define STATUS_SOME_UNMAPPED 0x0107 +#define STATUS_BUFFER_OVERFLOW 0x80000005 +#define NT_STATUS_NO_MORE_ENTRIES 0x8000001a +#define NT_STATUS_UNSUCCESSFUL 0xC0000000 | 0x0001 +#define NT_STATUS_NOT_IMPLEMENTED 0xC0000000 | 0x0002 +#define NT_STATUS_INVALID_INFO_CLASS 0xC0000000 | 0x0003 +#define NT_STATUS_INFO_LENGTH_MISMATCH 0xC0000000 | 0x0004 +#define NT_STATUS_ACCESS_VIOLATION 0xC0000000 | 0x0005 +#define NT_STATUS_IN_PAGE_ERROR 0xC0000000 | 0x0006 +#define NT_STATUS_PAGEFILE_QUOTA 0xC0000000 | 0x0007 +#define NT_STATUS_INVALID_HANDLE 0xC0000000 | 0x0008 +#define NT_STATUS_BAD_INITIAL_STACK 0xC0000000 | 0x0009 +#define NT_STATUS_BAD_INITIAL_PC 0xC0000000 | 0x000a +#define NT_STATUS_INVALID_CID 0xC0000000 | 0x000b +#define NT_STATUS_TIMER_NOT_CANCELED 0xC0000000 | 0x000c +#define NT_STATUS_INVALID_PARAMETER 0xC0000000 | 0x000d +#define NT_STATUS_NO_SUCH_DEVICE 0xC0000000 | 0x000e +#define NT_STATUS_NO_SUCH_FILE 0xC0000000 | 0x000f +#define NT_STATUS_INVALID_DEVICE_REQUEST 0xC0000000 | 0x0010 +#define NT_STATUS_END_OF_FILE 0xC0000000 | 0x0011 +#define NT_STATUS_WRONG_VOLUME 0xC0000000 | 0x0012 +#define NT_STATUS_NO_MEDIA_IN_DEVICE 0xC0000000 | 0x0013 +#define NT_STATUS_UNRECOGNIZED_MEDIA 0xC0000000 | 0x0014 +#define NT_STATUS_NONEXISTENT_SECTOR 0xC0000000 | 0x0015 +#define NT_STATUS_MORE_PROCESSING_REQUIRED 0xC0000000 | 0x0016 +#define NT_STATUS_NO_MEMORY 0xC0000000 | 0x0017 +#define NT_STATUS_CONFLICTING_ADDRESSES 0xC0000000 | 0x0018 +#define NT_STATUS_NOT_MAPPED_VIEW 0xC0000000 | 0x0019 +#define NT_STATUS_UNABLE_TO_FREE_VM 0x80000000 | 0x001a +#define NT_STATUS_UNABLE_TO_DELETE_SECTION 0xC0000000 | 0x001b +#define NT_STATUS_INVALID_SYSTEM_SERVICE 0xC0000000 | 0x001c +#define NT_STATUS_ILLEGAL_INSTRUCTION 0xC0000000 | 0x001d +#define NT_STATUS_INVALID_LOCK_SEQUENCE 0xC0000000 | 0x001e +#define NT_STATUS_INVALID_VIEW_SIZE 0xC0000000 | 0x001f +#define NT_STATUS_INVALID_FILE_FOR_SECTION 0xC0000000 | 0x0020 +#define NT_STATUS_ALREADY_COMMITTED 0xC0000000 | 0x0021 +#define NT_STATUS_ACCESS_DENIED 0xC0000000 | 0x0022 +#define NT_STATUS_BUFFER_TOO_SMALL 0xC0000000 | 0x0023 +#define NT_STATUS_OBJECT_TYPE_MISMATCH 0xC0000000 | 0x0024 +#define NT_STATUS_NONCONTINUABLE_EXCEPTION 0xC0000000 | 0x0025 +#define NT_STATUS_INVALID_DISPOSITION 0xC0000000 | 0x0026 +#define NT_STATUS_UNWIND 0xC0000000 | 0x0027 +#define NT_STATUS_BAD_STACK 0xC0000000 | 0x0028 +#define NT_STATUS_INVALID_UNWIND_TARGET 0xC0000000 | 0x0029 +#define NT_STATUS_NOT_LOCKED 0xC0000000 | 0x002a +#define NT_STATUS_PARITY_ERROR 0xC0000000 | 0x002b +#define NT_STATUS_UNABLE_TO_DECOMMIT_VM 0xC0000000 | 0x002c +#define NT_STATUS_NOT_COMMITTED 0xC0000000 | 0x002d +#define NT_STATUS_INVALID_PORT_ATTRIBUTES 0xC0000000 | 0x002e +#define NT_STATUS_PORT_MESSAGE_TOO_LONG 0xC0000000 | 0x002f +#define NT_STATUS_INVALID_PARAMETER_MIX 0xC0000000 | 0x0030 +#define NT_STATUS_INVALID_QUOTA_LOWER 0xC0000000 | 0x0031 +#define NT_STATUS_DISK_CORRUPT_ERROR 0xC0000000 | 0x0032 +#define NT_STATUS_OBJECT_NAME_INVALID 0xC0000000 | 0x0033 +#define NT_STATUS_OBJECT_NAME_NOT_FOUND 0xC0000000 | 0x0034 +#define NT_STATUS_OBJECT_NAME_COLLISION 0xC0000000 | 0x0035 +#define NT_STATUS_HANDLE_NOT_WAITABLE 0xC0000000 | 0x0036 +#define NT_STATUS_PORT_DISCONNECTED 0xC0000000 | 0x0037 +#define NT_STATUS_DEVICE_ALREADY_ATTACHED 0xC0000000 | 0x0038 +#define NT_STATUS_OBJECT_PATH_INVALID 0xC0000000 | 0x0039 +#define NT_STATUS_OBJECT_PATH_NOT_FOUND 0xC0000000 | 0x003a +#define NT_STATUS_OBJECT_PATH_SYNTAX_BAD 0xC0000000 | 0x003b +#define NT_STATUS_DATA_OVERRUN 0xC0000000 | 0x003c +#define NT_STATUS_DATA_LATE_ERROR 0xC0000000 | 0x003d +#define NT_STATUS_DATA_ERROR 0xC0000000 | 0x003e +#define NT_STATUS_CRC_ERROR 0xC0000000 | 0x003f +#define NT_STATUS_SECTION_TOO_BIG 0xC0000000 | 0x0040 +#define NT_STATUS_PORT_CONNECTION_REFUSED 0xC0000000 | 0x0041 +#define NT_STATUS_INVALID_PORT_HANDLE 0xC0000000 | 0x0042 +#define NT_STATUS_SHARING_VIOLATION 0xC0000000 | 0x0043 +#define NT_STATUS_QUOTA_EXCEEDED 0xC0000000 | 0x0044 +#define NT_STATUS_INVALID_PAGE_PROTECTION 0xC0000000 | 0x0045 +#define NT_STATUS_MUTANT_NOT_OWNED 0xC0000000 | 0x0046 +#define NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED 0xC0000000 | 0x0047 +#define NT_STATUS_PORT_ALREADY_SET 0xC0000000 | 0x0048 +#define NT_STATUS_SECTION_NOT_IMAGE 0xC0000000 | 0x0049 +#define NT_STATUS_SUSPEND_COUNT_EXCEEDED 0xC0000000 | 0x004a +#define NT_STATUS_THREAD_IS_TERMINATING 0xC0000000 | 0x004b +#define NT_STATUS_BAD_WORKING_SET_LIMIT 0xC0000000 | 0x004c +#define NT_STATUS_INCOMPATIBLE_FILE_MAP 0xC0000000 | 0x004d +#define NT_STATUS_SECTION_PROTECTION 0xC0000000 | 0x004e +#define NT_STATUS_EAS_NOT_SUPPORTED 0xC0000000 | 0x004f +#define NT_STATUS_EA_TOO_LARGE 0xC0000000 | 0x0050 +#define NT_STATUS_NONEXISTENT_EA_ENTRY 0xC0000000 | 0x0051 +#define NT_STATUS_NO_EAS_ON_FILE 0xC0000000 | 0x0052 +#define NT_STATUS_EA_CORRUPT_ERROR 0xC0000000 | 0x0053 +#define NT_STATUS_FILE_LOCK_CONFLICT 0xC0000000 | 0x0054 +#define NT_STATUS_LOCK_NOT_GRANTED 0xC0000000 | 0x0055 +#define NT_STATUS_DELETE_PENDING 0xC0000000 | 0x0056 +#define NT_STATUS_CTL_FILE_NOT_SUPPORTED 0xC0000000 | 0x0057 +#define NT_STATUS_UNKNOWN_REVISION 0xC0000000 | 0x0058 +#define NT_STATUS_REVISION_MISMATCH 0xC0000000 | 0x0059 +#define NT_STATUS_INVALID_OWNER 0xC0000000 | 0x005a +#define NT_STATUS_INVALID_PRIMARY_GROUP 0xC0000000 | 0x005b +#define NT_STATUS_NO_IMPERSONATION_TOKEN 0xC0000000 | 0x005c +#define NT_STATUS_CANT_DISABLE_MANDATORY 0xC0000000 | 0x005d +#define NT_STATUS_NO_LOGON_SERVERS 0xC0000000 | 0x005e +#define NT_STATUS_NO_SUCH_LOGON_SESSION 0xC0000000 | 0x005f +#define NT_STATUS_NO_SUCH_PRIVILEGE 0xC0000000 | 0x0060 +#define NT_STATUS_PRIVILEGE_NOT_HELD 0xC0000000 | 0x0061 +#define NT_STATUS_INVALID_ACCOUNT_NAME 0xC0000000 | 0x0062 +#define NT_STATUS_USER_EXISTS 0xC0000000 | 0x0063 +#define NT_STATUS_NO_SUCH_USER 0xC0000000 | 0x0064 +#define NT_STATUS_GROUP_EXISTS 0xC0000000 | 0x0065 +#define NT_STATUS_NO_SUCH_GROUP 0xC0000000 | 0x0066 +#define NT_STATUS_MEMBER_IN_GROUP 0xC0000000 | 0x0067 +#define NT_STATUS_MEMBER_NOT_IN_GROUP 0xC0000000 | 0x0068 +#define NT_STATUS_LAST_ADMIN 0xC0000000 | 0x0069 +#define NT_STATUS_WRONG_PASSWORD 0xC0000000 | 0x006a +#define NT_STATUS_ILL_FORMED_PASSWORD 0xC0000000 | 0x006b +#define NT_STATUS_PASSWORD_RESTRICTION 0xC0000000 | 0x006c +#define NT_STATUS_LOGON_FAILURE 0xC0000000 | 0x006d +#define NT_STATUS_ACCOUNT_RESTRICTION 0xC0000000 | 0x006e +#define NT_STATUS_INVALID_LOGON_HOURS 0xC0000000 | 0x006f +#define NT_STATUS_INVALID_WORKSTATION 0xC0000000 | 0x0070 +#define NT_STATUS_PASSWORD_EXPIRED 0xC0000000 | 0x0071 +#define NT_STATUS_ACCOUNT_DISABLED 0xC0000000 | 0x0072 +#define NT_STATUS_NONE_MAPPED 0xC0000000 | 0x0073 +#define NT_STATUS_TOO_MANY_LUIDS_REQUESTED 0xC0000000 | 0x0074 +#define NT_STATUS_LUIDS_EXHAUSTED 0xC0000000 | 0x0075 +#define NT_STATUS_INVALID_SUB_AUTHORITY 0xC0000000 | 0x0076 +#define NT_STATUS_INVALID_ACL 0xC0000000 | 0x0077 +#define NT_STATUS_INVALID_SID 0xC0000000 | 0x0078 +#define NT_STATUS_INVALID_SECURITY_DESCR 0xC0000000 | 0x0079 +#define NT_STATUS_PROCEDURE_NOT_FOUND 0xC0000000 | 0x007a +#define NT_STATUS_INVALID_IMAGE_FORMAT 0xC0000000 | 0x007b +#define NT_STATUS_NO_TOKEN 0xC0000000 | 0x007c +#define NT_STATUS_BAD_INHERITANCE_ACL 0xC0000000 | 0x007d +#define NT_STATUS_RANGE_NOT_LOCKED 0xC0000000 | 0x007e +#define NT_STATUS_DISK_FULL 0xC0000000 | 0x007f +#define NT_STATUS_SERVER_DISABLED 0xC0000000 | 0x0080 +#define NT_STATUS_SERVER_NOT_DISABLED 0xC0000000 | 0x0081 +#define NT_STATUS_TOO_MANY_GUIDS_REQUESTED 0xC0000000 | 0x0082 +#define NT_STATUS_GUIDS_EXHAUSTED 0xC0000000 | 0x0083 +#define NT_STATUS_INVALID_ID_AUTHORITY 0xC0000000 | 0x0084 +#define NT_STATUS_AGENTS_EXHAUSTED 0xC0000000 | 0x0085 +#define NT_STATUS_INVALID_VOLUME_LABEL 0xC0000000 | 0x0086 +#define NT_STATUS_SECTION_NOT_EXTENDED 0xC0000000 | 0x0087 +#define NT_STATUS_NOT_MAPPED_DATA 0xC0000000 | 0x0088 +#define NT_STATUS_RESOURCE_DATA_NOT_FOUND 0xC0000000 | 0x0089 +#define NT_STATUS_RESOURCE_TYPE_NOT_FOUND 0xC0000000 | 0x008a +#define NT_STATUS_RESOURCE_NAME_NOT_FOUND 0xC0000000 | 0x008b +#define NT_STATUS_ARRAY_BOUNDS_EXCEEDED 0xC0000000 | 0x008c +#define NT_STATUS_FLOAT_DENORMAL_OPERAND 0xC0000000 | 0x008d +#define NT_STATUS_FLOAT_DIVIDE_BY_ZERO 0xC0000000 | 0x008e +#define NT_STATUS_FLOAT_INEXACT_RESULT 0xC0000000 | 0x008f +#define NT_STATUS_FLOAT_INVALID_OPERATION 0xC0000000 | 0x0090 +#define NT_STATUS_FLOAT_OVERFLOW 0xC0000000 | 0x0091 +#define NT_STATUS_FLOAT_STACK_CHECK 0xC0000000 | 0x0092 +#define NT_STATUS_FLOAT_UNDERFLOW 0xC0000000 | 0x0093 +#define NT_STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000000 | 0x0094 +#define NT_STATUS_INTEGER_OVERFLOW 0xC0000000 | 0x0095 +#define NT_STATUS_PRIVILEGED_INSTRUCTION 0xC0000000 | 0x0096 +#define NT_STATUS_TOO_MANY_PAGING_FILES 0xC0000000 | 0x0097 +#define NT_STATUS_FILE_INVALID 0xC0000000 | 0x0098 +#define NT_STATUS_ALLOTTED_SPACE_EXCEEDED 0xC0000000 | 0x0099 +#define NT_STATUS_INSUFFICIENT_RESOURCES 0xC0000000 | 0x009a +#define NT_STATUS_DFS_EXIT_PATH_FOUND 0xC0000000 | 0x009b +#define NT_STATUS_DEVICE_DATA_ERROR 0xC0000000 | 0x009c +#define NT_STATUS_DEVICE_NOT_CONNECTED 0xC0000000 | 0x009d +#define NT_STATUS_DEVICE_POWER_FAILURE 0xC0000000 | 0x009e +#define NT_STATUS_FREE_VM_NOT_AT_BASE 0xC0000000 | 0x009f +#define NT_STATUS_MEMORY_NOT_ALLOCATED 0xC0000000 | 0x00a0 +#define NT_STATUS_WORKING_SET_QUOTA 0xC0000000 | 0x00a1 +#define NT_STATUS_MEDIA_WRITE_PROTECTED 0xC0000000 | 0x00a2 +#define NT_STATUS_DEVICE_NOT_READY 0xC0000000 | 0x00a3 +#define NT_STATUS_INVALID_GROUP_ATTRIBUTES 0xC0000000 | 0x00a4 +#define NT_STATUS_BAD_IMPERSONATION_LEVEL 0xC0000000 | 0x00a5 +#define NT_STATUS_CANT_OPEN_ANONYMOUS 0xC0000000 | 0x00a6 +#define NT_STATUS_BAD_VALIDATION_CLASS 0xC0000000 | 0x00a7 +#define NT_STATUS_BAD_TOKEN_TYPE 0xC0000000 | 0x00a8 +#define NT_STATUS_BAD_MASTER_BOOT_RECORD 0xC0000000 | 0x00a9 +#define NT_STATUS_INSTRUCTION_MISALIGNMENT 0xC0000000 | 0x00aa +#define NT_STATUS_INSTANCE_NOT_AVAILABLE 0xC0000000 | 0x00ab +#define NT_STATUS_PIPE_NOT_AVAILABLE 0xC0000000 | 0x00ac +#define NT_STATUS_INVALID_PIPE_STATE 0xC0000000 | 0x00ad +#define NT_STATUS_PIPE_BUSY 0xC0000000 | 0x00ae +#define NT_STATUS_ILLEGAL_FUNCTION 0xC0000000 | 0x00af +#define NT_STATUS_PIPE_DISCONNECTED 0xC0000000 | 0x00b0 +#define NT_STATUS_PIPE_CLOSING 0xC0000000 | 0x00b1 +#define NT_STATUS_PIPE_CONNECTED 0xC0000000 | 0x00b2 +#define NT_STATUS_PIPE_LISTENING 0xC0000000 | 0x00b3 +#define NT_STATUS_INVALID_READ_MODE 0xC0000000 | 0x00b4 +#define NT_STATUS_IO_TIMEOUT 0xC0000000 | 0x00b5 +#define NT_STATUS_FILE_FORCED_CLOSED 0xC0000000 | 0x00b6 +#define NT_STATUS_PROFILING_NOT_STARTED 0xC0000000 | 0x00b7 +#define NT_STATUS_PROFILING_NOT_STOPPED 0xC0000000 | 0x00b8 +#define NT_STATUS_COULD_NOT_INTERPRET 0xC0000000 | 0x00b9 +#define NT_STATUS_FILE_IS_A_DIRECTORY 0xC0000000 | 0x00ba +#define NT_STATUS_NOT_SUPPORTED 0xC0000000 | 0x00bb +#define NT_STATUS_REMOTE_NOT_LISTENING 0xC0000000 | 0x00bc +#define NT_STATUS_DUPLICATE_NAME 0xC0000000 | 0x00bd +#define NT_STATUS_BAD_NETWORK_PATH 0xC0000000 | 0x00be +#define NT_STATUS_NETWORK_BUSY 0xC0000000 | 0x00bf +#define NT_STATUS_DEVICE_DOES_NOT_EXIST 0xC0000000 | 0x00c0 +#define NT_STATUS_TOO_MANY_COMMANDS 0xC0000000 | 0x00c1 +#define NT_STATUS_ADAPTER_HARDWARE_ERROR 0xC0000000 | 0x00c2 +#define NT_STATUS_INVALID_NETWORK_RESPONSE 0xC0000000 | 0x00c3 +#define NT_STATUS_UNEXPECTED_NETWORK_ERROR 0xC0000000 | 0x00c4 +#define NT_STATUS_BAD_REMOTE_ADAPTER 0xC0000000 | 0x00c5 +#define NT_STATUS_PRINT_QUEUE_FULL 0xC0000000 | 0x00c6 +#define NT_STATUS_NO_SPOOL_SPACE 0xC0000000 | 0x00c7 +#define NT_STATUS_PRINT_CANCELLED 0xC0000000 | 0x00c8 +#define NT_STATUS_NETWORK_NAME_DELETED 0xC0000000 | 0x00c9 +#define NT_STATUS_NETWORK_ACCESS_DENIED 0xC0000000 | 0x00ca +#define NT_STATUS_BAD_DEVICE_TYPE 0xC0000000 | 0x00cb +#define NT_STATUS_BAD_NETWORK_NAME 0xC0000000 | 0x00cc +#define NT_STATUS_TOO_MANY_NAMES 0xC0000000 | 0x00cd +#define NT_STATUS_TOO_MANY_SESSIONS 0xC0000000 | 0x00ce +#define NT_STATUS_SHARING_PAUSED 0xC0000000 | 0x00cf +#define NT_STATUS_REQUEST_NOT_ACCEPTED 0xC0000000 | 0x00d0 +#define NT_STATUS_REDIRECTOR_PAUSED 0xC0000000 | 0x00d1 +#define NT_STATUS_NET_WRITE_FAULT 0xC0000000 | 0x00d2 +#define NT_STATUS_PROFILING_AT_LIMIT 0xC0000000 | 0x00d3 +#define NT_STATUS_NOT_SAME_DEVICE 0xC0000000 | 0x00d4 +#define NT_STATUS_FILE_RENAMED 0xC0000000 | 0x00d5 +#define NT_STATUS_VIRTUAL_CIRCUIT_CLOSED 0xC0000000 | 0x00d6 +#define NT_STATUS_NO_SECURITY_ON_OBJECT 0xC0000000 | 0x00d7 +#define NT_STATUS_CANT_WAIT 0xC0000000 | 0x00d8 +#define NT_STATUS_PIPE_EMPTY 0xC0000000 | 0x00d9 +#define NT_STATUS_CANT_ACCESS_DOMAIN_INFO 0xC0000000 | 0x00da +#define NT_STATUS_CANT_TERMINATE_SELF 0xC0000000 | 0x00db +#define NT_STATUS_INVALID_SERVER_STATE 0xC0000000 | 0x00dc +#define NT_STATUS_INVALID_DOMAIN_STATE 0xC0000000 | 0x00dd +#define NT_STATUS_INVALID_DOMAIN_ROLE 0xC0000000 | 0x00de +#define NT_STATUS_NO_SUCH_DOMAIN 0xC0000000 | 0x00df +#define NT_STATUS_DOMAIN_EXISTS 0xC0000000 | 0x00e0 +#define NT_STATUS_DOMAIN_LIMIT_EXCEEDED 0xC0000000 | 0x00e1 +#define NT_STATUS_OPLOCK_NOT_GRANTED 0xC0000000 | 0x00e2 +#define NT_STATUS_INVALID_OPLOCK_PROTOCOL 0xC0000000 | 0x00e3 +#define NT_STATUS_INTERNAL_DB_CORRUPTION 0xC0000000 | 0x00e4 +#define NT_STATUS_INTERNAL_ERROR 0xC0000000 | 0x00e5 +#define NT_STATUS_GENERIC_NOT_MAPPED 0xC0000000 | 0x00e6 +#define NT_STATUS_BAD_DESCRIPTOR_FORMAT 0xC0000000 | 0x00e7 +#define NT_STATUS_INVALID_USER_BUFFER 0xC0000000 | 0x00e8 +#define NT_STATUS_UNEXPECTED_IO_ERROR 0xC0000000 | 0x00e9 +#define NT_STATUS_UNEXPECTED_MM_CREATE_ERR 0xC0000000 | 0x00ea +#define NT_STATUS_UNEXPECTED_MM_MAP_ERROR 0xC0000000 | 0x00eb +#define NT_STATUS_UNEXPECTED_MM_EXTEND_ERR 0xC0000000 | 0x00ec +#define NT_STATUS_NOT_LOGON_PROCESS 0xC0000000 | 0x00ed +#define NT_STATUS_LOGON_SESSION_EXISTS 0xC0000000 | 0x00ee +#define NT_STATUS_INVALID_PARAMETER_1 0xC0000000 | 0x00ef +#define NT_STATUS_INVALID_PARAMETER_2 0xC0000000 | 0x00f0 +#define NT_STATUS_INVALID_PARAMETER_3 0xC0000000 | 0x00f1 +#define NT_STATUS_INVALID_PARAMETER_4 0xC0000000 | 0x00f2 +#define NT_STATUS_INVALID_PARAMETER_5 0xC0000000 | 0x00f3 +#define NT_STATUS_INVALID_PARAMETER_6 0xC0000000 | 0x00f4 +#define NT_STATUS_INVALID_PARAMETER_7 0xC0000000 | 0x00f5 +#define NT_STATUS_INVALID_PARAMETER_8 0xC0000000 | 0x00f6 +#define NT_STATUS_INVALID_PARAMETER_9 0xC0000000 | 0x00f7 +#define NT_STATUS_INVALID_PARAMETER_10 0xC0000000 | 0x00f8 +#define NT_STATUS_INVALID_PARAMETER_11 0xC0000000 | 0x00f9 +#define NT_STATUS_INVALID_PARAMETER_12 0xC0000000 | 0x00fa +#define NT_STATUS_REDIRECTOR_NOT_STARTED 0xC0000000 | 0x00fb +#define NT_STATUS_REDIRECTOR_STARTED 0xC0000000 | 0x00fc +#define NT_STATUS_STACK_OVERFLOW 0xC0000000 | 0x00fd +#define NT_STATUS_NO_SUCH_PACKAGE 0xC0000000 | 0x00fe +#define NT_STATUS_BAD_FUNCTION_TABLE 0xC0000000 | 0x00ff +#define NT_STATUS_DIRECTORY_NOT_EMPTY 0xC0000000 | 0x0101 +#define NT_STATUS_FILE_CORRUPT_ERROR 0xC0000000 | 0x0102 +#define NT_STATUS_NOT_A_DIRECTORY 0xC0000000 | 0x0103 +#define NT_STATUS_BAD_LOGON_SESSION_STATE 0xC0000000 | 0x0104 +#define NT_STATUS_LOGON_SESSION_COLLISION 0xC0000000 | 0x0105 +#define NT_STATUS_NAME_TOO_LONG 0xC0000000 | 0x0106 +#define NT_STATUS_FILES_OPEN 0xC0000000 | 0x0107 +#define NT_STATUS_CONNECTION_IN_USE 0xC0000000 | 0x0108 +#define NT_STATUS_MESSAGE_NOT_FOUND 0xC0000000 | 0x0109 +#define NT_STATUS_PROCESS_IS_TERMINATING 0xC0000000 | 0x010a +#define NT_STATUS_INVALID_LOGON_TYPE 0xC0000000 | 0x010b +#define NT_STATUS_NO_GUID_TRANSLATION 0xC0000000 | 0x010c +#define NT_STATUS_CANNOT_IMPERSONATE 0xC0000000 | 0x010d +#define NT_STATUS_IMAGE_ALREADY_LOADED 0xC0000000 | 0x010e +#define NT_STATUS_ABIOS_NOT_PRESENT 0xC0000000 | 0x010f +#define NT_STATUS_ABIOS_LID_NOT_EXIST 0xC0000000 | 0x0110 +#define NT_STATUS_ABIOS_LID_ALREADY_OWNED 0xC0000000 | 0x0111 +#define NT_STATUS_ABIOS_NOT_LID_OWNER 0xC0000000 | 0x0112 +#define NT_STATUS_ABIOS_INVALID_COMMAND 0xC0000000 | 0x0113 +#define NT_STATUS_ABIOS_INVALID_LID 0xC0000000 | 0x0114 +#define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE 0xC0000000 | 0x0115 +#define NT_STATUS_ABIOS_INVALID_SELECTOR 0xC0000000 | 0x0116 +#define NT_STATUS_NO_LDT 0xC0000000 | 0x0117 +#define NT_STATUS_INVALID_LDT_SIZE 0xC0000000 | 0x0118 +#define NT_STATUS_INVALID_LDT_OFFSET 0xC0000000 | 0x0119 +#define NT_STATUS_INVALID_LDT_DESCRIPTOR 0xC0000000 | 0x011a +#define NT_STATUS_INVALID_IMAGE_NE_FORMAT 0xC0000000 | 0x011b +#define NT_STATUS_RXACT_INVALID_STATE 0xC0000000 | 0x011c +#define NT_STATUS_RXACT_COMMIT_FAILURE 0xC0000000 | 0x011d +#define NT_STATUS_MAPPED_FILE_SIZE_ZERO 0xC0000000 | 0x011e +#define NT_STATUS_TOO_MANY_OPENED_FILES 0xC0000000 | 0x011f +#define NT_STATUS_CANCELLED 0xC0000000 | 0x0120 +#define NT_STATUS_CANNOT_DELETE 0xC0000000 | 0x0121 +#define NT_STATUS_INVALID_COMPUTER_NAME 0xC0000000 | 0x0122 +#define NT_STATUS_FILE_DELETED 0xC0000000 | 0x0123 +#define NT_STATUS_SPECIAL_ACCOUNT 0xC0000000 | 0x0124 +#define NT_STATUS_SPECIAL_GROUP 0xC0000000 | 0x0125 +#define NT_STATUS_SPECIAL_USER 0xC0000000 | 0x0126 +#define NT_STATUS_MEMBERS_PRIMARY_GROUP 0xC0000000 | 0x0127 +#define NT_STATUS_FILE_CLOSED 0xC0000000 | 0x0128 +#define NT_STATUS_TOO_MANY_THREADS 0xC0000000 | 0x0129 +#define NT_STATUS_THREAD_NOT_IN_PROCESS 0xC0000000 | 0x012a +#define NT_STATUS_TOKEN_ALREADY_IN_USE 0xC0000000 | 0x012b +#define NT_STATUS_PAGEFILE_QUOTA_EXCEEDED 0xC0000000 | 0x012c +#define NT_STATUS_COMMITMENT_LIMIT 0xC0000000 | 0x012d +#define NT_STATUS_INVALID_IMAGE_LE_FORMAT 0xC0000000 | 0x012e +#define NT_STATUS_INVALID_IMAGE_NOT_MZ 0xC0000000 | 0x012f +#define NT_STATUS_INVALID_IMAGE_PROTECT 0xC0000000 | 0x0130 +#define NT_STATUS_INVALID_IMAGE_WIN_16 0xC0000000 | 0x0131 +#define NT_STATUS_LOGON_SERVER_CONFLICT 0xC0000000 | 0x0132 +#define NT_STATUS_TIME_DIFFERENCE_AT_DC 0xC0000000 | 0x0133 +#define NT_STATUS_SYNCHRONIZATION_REQUIRED 0xC0000000 | 0x0134 +#define NT_STATUS_DLL_NOT_FOUND 0xC0000000 | 0x0135 +#define NT_STATUS_OPEN_FAILED 0xC0000000 | 0x0136 +#define NT_STATUS_IO_PRIVILEGE_FAILED 0xC0000000 | 0x0137 +#define NT_STATUS_ORDINAL_NOT_FOUND 0xC0000000 | 0x0138 +#define NT_STATUS_ENTRYPOINT_NOT_FOUND 0xC0000000 | 0x0139 +#define NT_STATUS_CONTROL_C_EXIT 0xC0000000 | 0x013a +#define NT_STATUS_LOCAL_DISCONNECT 0xC0000000 | 0x013b +#define NT_STATUS_REMOTE_DISCONNECT 0xC0000000 | 0x013c +#define NT_STATUS_REMOTE_RESOURCES 0xC0000000 | 0x013d +#define NT_STATUS_LINK_FAILED 0xC0000000 | 0x013e +#define NT_STATUS_LINK_TIMEOUT 0xC0000000 | 0x013f +#define NT_STATUS_INVALID_CONNECTION 0xC0000000 | 0x0140 +#define NT_STATUS_INVALID_ADDRESS 0xC0000000 | 0x0141 +#define NT_STATUS_DLL_INIT_FAILED 0xC0000000 | 0x0142 +#define NT_STATUS_MISSING_SYSTEMFILE 0xC0000000 | 0x0143 +#define NT_STATUS_UNHANDLED_EXCEPTION 0xC0000000 | 0x0144 +#define NT_STATUS_APP_INIT_FAILURE 0xC0000000 | 0x0145 +#define NT_STATUS_PAGEFILE_CREATE_FAILED 0xC0000000 | 0x0146 +#define NT_STATUS_NO_PAGEFILE 0xC0000000 | 0x0147 +#define NT_STATUS_INVALID_LEVEL 0xC0000000 | 0x0148 +#define NT_STATUS_WRONG_PASSWORD_CORE 0xC0000000 | 0x0149 +#define NT_STATUS_ILLEGAL_FLOAT_CONTEXT 0xC0000000 | 0x014a +#define NT_STATUS_PIPE_BROKEN 0xC0000000 | 0x014b +#define NT_STATUS_REGISTRY_CORRUPT 0xC0000000 | 0x014c +#define NT_STATUS_REGISTRY_IO_FAILED 0xC0000000 | 0x014d +#define NT_STATUS_NO_EVENT_PAIR 0xC0000000 | 0x014e +#define NT_STATUS_UNRECOGNIZED_VOLUME 0xC0000000 | 0x014f +#define NT_STATUS_SERIAL_NO_DEVICE_INITED 0xC0000000 | 0x0150 +#define NT_STATUS_NO_SUCH_ALIAS 0xC0000000 | 0x0151 +#define NT_STATUS_MEMBER_NOT_IN_ALIAS 0xC0000000 | 0x0152 +#define NT_STATUS_MEMBER_IN_ALIAS 0xC0000000 | 0x0153 +#define NT_STATUS_ALIAS_EXISTS 0xC0000000 | 0x0154 +#define NT_STATUS_LOGON_NOT_GRANTED 0xC0000000 | 0x0155 +#define NT_STATUS_TOO_MANY_SECRETS 0xC0000000 | 0x0156 +#define NT_STATUS_SECRET_TOO_LONG 0xC0000000 | 0x0157 +#define NT_STATUS_INTERNAL_DB_ERROR 0xC0000000 | 0x0158 +#define NT_STATUS_FULLSCREEN_MODE 0xC0000000 | 0x0159 +#define NT_STATUS_TOO_MANY_CONTEXT_IDS 0xC0000000 | 0x015a +#define NT_STATUS_LOGON_TYPE_NOT_GRANTED 0xC0000000 | 0x015b +#define NT_STATUS_NOT_REGISTRY_FILE 0xC0000000 | 0x015c +#define NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED 0xC0000000 | 0x015d +#define NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR 0xC0000000 | 0x015e +#define NT_STATUS_FT_MISSING_MEMBER 0xC0000000 | 0x015f +#define NT_STATUS_ILL_FORMED_SERVICE_ENTRY 0xC0000000 | 0x0160 +#define NT_STATUS_ILLEGAL_CHARACTER 0xC0000000 | 0x0161 +#define NT_STATUS_UNMAPPABLE_CHARACTER 0xC0000000 | 0x0162 +#define NT_STATUS_UNDEFINED_CHARACTER 0xC0000000 | 0x0163 +#define NT_STATUS_FLOPPY_VOLUME 0xC0000000 | 0x0164 +#define NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND 0xC0000000 | 0x0165 +#define NT_STATUS_FLOPPY_WRONG_CYLINDER 0xC0000000 | 0x0166 +#define NT_STATUS_FLOPPY_UNKNOWN_ERROR 0xC0000000 | 0x0167 +#define NT_STATUS_FLOPPY_BAD_REGISTERS 0xC0000000 | 0x0168 +#define NT_STATUS_DISK_RECALIBRATE_FAILED 0xC0000000 | 0x0169 +#define NT_STATUS_DISK_OPERATION_FAILED 0xC0000000 | 0x016a +#define NT_STATUS_DISK_RESET_FAILED 0xC0000000 | 0x016b +#define NT_STATUS_SHARED_IRQ_BUSY 0xC0000000 | 0x016c +#define NT_STATUS_FT_ORPHANING 0xC0000000 | 0x016d +#define NT_STATUS_PARTITION_FAILURE 0xC0000000 | 0x0172 +#define NT_STATUS_INVALID_BLOCK_LENGTH 0xC0000000 | 0x0173 +#define NT_STATUS_DEVICE_NOT_PARTITIONED 0xC0000000 | 0x0174 +#define NT_STATUS_UNABLE_TO_LOCK_MEDIA 0xC0000000 | 0x0175 +#define NT_STATUS_UNABLE_TO_UNLOAD_MEDIA 0xC0000000 | 0x0176 +#define NT_STATUS_EOM_OVERFLOW 0xC0000000 | 0x0177 +#define NT_STATUS_NO_MEDIA 0xC0000000 | 0x0178 +#define NT_STATUS_NO_SUCH_MEMBER 0xC0000000 | 0x017a +#define NT_STATUS_INVALID_MEMBER 0xC0000000 | 0x017b +#define NT_STATUS_KEY_DELETED 0xC0000000 | 0x017c +#define NT_STATUS_NO_LOG_SPACE 0xC0000000 | 0x017d +#define NT_STATUS_TOO_MANY_SIDS 0xC0000000 | 0x017e +#define NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED 0xC0000000 | 0x017f +#define NT_STATUS_KEY_HAS_CHILDREN 0xC0000000 | 0x0180 +#define NT_STATUS_CHILD_MUST_BE_VOLATILE 0xC0000000 | 0x0181 +#define NT_STATUS_DEVICE_CONFIGURATION_ERROR 0xC0000000 | 0x0182 +#define NT_STATUS_DRIVER_INTERNAL_ERROR 0xC0000000 | 0x0183 +#define NT_STATUS_INVALID_DEVICE_STATE 0xC0000000 | 0x0184 +#define NT_STATUS_IO_DEVICE_ERROR 0xC0000000 | 0x0185 +#define NT_STATUS_DEVICE_PROTOCOL_ERROR 0xC0000000 | 0x0186 +#define NT_STATUS_BACKUP_CONTROLLER 0xC0000000 | 0x0187 +#define NT_STATUS_LOG_FILE_FULL 0xC0000000 | 0x0188 +#define NT_STATUS_TOO_LATE 0xC0000000 | 0x0189 +#define NT_STATUS_NO_TRUST_LSA_SECRET 0xC0000000 | 0x018a +#define NT_STATUS_NO_TRUST_SAM_ACCOUNT 0xC0000000 | 0x018b +#define NT_STATUS_TRUSTED_DOMAIN_FAILURE 0xC0000000 | 0x018c +#define NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE 0xC0000000 | 0x018d +#define NT_STATUS_EVENTLOG_FILE_CORRUPT 0xC0000000 | 0x018e +#define NT_STATUS_EVENTLOG_CANT_START 0xC0000000 | 0x018f +#define NT_STATUS_TRUST_FAILURE 0xC0000000 | 0x0190 +#define NT_STATUS_MUTANT_LIMIT_EXCEEDED 0xC0000000 | 0x0191 +#define NT_STATUS_NETLOGON_NOT_STARTED 0xC0000000 | 0x0192 +#define NT_STATUS_ACCOUNT_EXPIRED 0xC0000000 | 0x0193 +#define NT_STATUS_POSSIBLE_DEADLOCK 0xC0000000 | 0x0194 +#define NT_STATUS_NETWORK_CREDENTIAL_CONFLICT 0xC0000000 | 0x0195 +#define NT_STATUS_REMOTE_SESSION_LIMIT 0xC0000000 | 0x0196 +#define NT_STATUS_EVENTLOG_FILE_CHANGED 0xC0000000 | 0x0197 +#define NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 0xC0000000 | 0x0198 +#define NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT 0xC0000000 | 0x0199 +#define NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT 0xC0000000 | 0x019a +#define NT_STATUS_DOMAIN_TRUST_INCONSISTENT 0xC0000000 | 0x019b +#define NT_STATUS_FS_DRIVER_REQUIRED 0xC0000000 | 0x019c +#define NT_STATUS_NO_USER_SESSION_KEY 0xC0000000 | 0x0202 +#define NT_STATUS_USER_SESSION_DELETED 0xC0000000 | 0x0203 +#define NT_STATUS_RESOURCE_LANG_NOT_FOUND 0xC0000000 | 0x0204 +#define NT_STATUS_INSUFF_SERVER_RESOURCES 0xC0000000 | 0x0205 +#define NT_STATUS_INVALID_BUFFER_SIZE 0xC0000000 | 0x0206 +#define NT_STATUS_INVALID_ADDRESS_COMPONENT 0xC0000000 | 0x0207 +#define NT_STATUS_INVALID_ADDRESS_WILDCARD 0xC0000000 | 0x0208 +#define NT_STATUS_TOO_MANY_ADDRESSES 0xC0000000 | 0x0209 +#define NT_STATUS_ADDRESS_ALREADY_EXISTS 0xC0000000 | 0x020a +#define NT_STATUS_ADDRESS_CLOSED 0xC0000000 | 0x020b +#define NT_STATUS_CONNECTION_DISCONNECTED 0xC0000000 | 0x020c +#define NT_STATUS_CONNECTION_RESET 0xC0000000 | 0x020d +#define NT_STATUS_TOO_MANY_NODES 0xC0000000 | 0x020e +#define NT_STATUS_TRANSACTION_ABORTED 0xC0000000 | 0x020f +#define NT_STATUS_TRANSACTION_TIMED_OUT 0xC0000000 | 0x0210 +#define NT_STATUS_TRANSACTION_NO_RELEASE 0xC0000000 | 0x0211 +#define NT_STATUS_TRANSACTION_NO_MATCH 0xC0000000 | 0x0212 +#define NT_STATUS_TRANSACTION_RESPONDED 0xC0000000 | 0x0213 +#define NT_STATUS_TRANSACTION_INVALID_ID 0xC0000000 | 0x0214 +#define NT_STATUS_TRANSACTION_INVALID_TYPE 0xC0000000 | 0x0215 +#define NT_STATUS_NOT_SERVER_SESSION 0xC0000000 | 0x0216 +#define NT_STATUS_NOT_CLIENT_SESSION 0xC0000000 | 0x0217 +#define NT_STATUS_CANNOT_LOAD_REGISTRY_FILE 0xC0000000 | 0x0218 +#define NT_STATUS_DEBUG_ATTACH_FAILED 0xC0000000 | 0x0219 +#define NT_STATUS_SYSTEM_PROCESS_TERMINATED 0xC0000000 | 0x021a +#define NT_STATUS_DATA_NOT_ACCEPTED 0xC0000000 | 0x021b +#define NT_STATUS_NO_BROWSER_SERVERS_FOUND 0xC0000000 | 0x021c +#define NT_STATUS_VDM_HARD_ERROR 0xC0000000 | 0x021d +#define NT_STATUS_DRIVER_CANCEL_TIMEOUT 0xC0000000 | 0x021e +#define NT_STATUS_REPLY_MESSAGE_MISMATCH 0xC0000000 | 0x021f +#define NT_STATUS_MAPPED_ALIGNMENT 0xC0000000 | 0x0220 +#define NT_STATUS_IMAGE_CHECKSUM_MISMATCH 0xC0000000 | 0x0221 +#define NT_STATUS_LOST_WRITEBEHIND_DATA 0xC0000000 | 0x0222 +#define NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID 0xC0000000 | 0x0223 +#define NT_STATUS_PASSWORD_MUST_CHANGE 0xC0000000 | 0x0224 +#define NT_STATUS_NOT_FOUND 0xC0000000 | 0x0225 +#define NT_STATUS_NOT_TINY_STREAM 0xC0000000 | 0x0226 +#define NT_STATUS_RECOVERY_FAILURE 0xC0000000 | 0x0227 +#define NT_STATUS_STACK_OVERFLOW_READ 0xC0000000 | 0x0228 +#define NT_STATUS_FAIL_CHECK 0xC0000000 | 0x0229 +#define NT_STATUS_DUPLICATE_OBJECTID 0xC0000000 | 0x022a +#define NT_STATUS_OBJECTID_EXISTS 0xC0000000 | 0x022b +#define NT_STATUS_CONVERT_TO_LARGE 0xC0000000 | 0x022c +#define NT_STATUS_RETRY 0xC0000000 | 0x022d +#define NT_STATUS_FOUND_OUT_OF_SCOPE 0xC0000000 | 0x022e +#define NT_STATUS_ALLOCATE_BUCKET 0xC0000000 | 0x022f +#define NT_STATUS_PROPSET_NOT_FOUND 0xC0000000 | 0x0230 +#define NT_STATUS_MARSHALL_OVERFLOW 0xC0000000 | 0x0231 +#define NT_STATUS_INVALID_VARIANT 0xC0000000 | 0x0232 +#define NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND 0xC0000000 | 0x0233 +#define NT_STATUS_ACCOUNT_LOCKED_OUT 0xC0000000 | 0x0234 +#define NT_STATUS_HANDLE_NOT_CLOSABLE 0xC0000000 | 0x0235 +#define NT_STATUS_CONNECTION_REFUSED 0xC0000000 | 0x0236 +#define NT_STATUS_GRACEFUL_DISCONNECT 0xC0000000 | 0x0237 +#define NT_STATUS_ADDRESS_ALREADY_ASSOCIATED 0xC0000000 | 0x0238 +#define NT_STATUS_ADDRESS_NOT_ASSOCIATED 0xC0000000 | 0x0239 +#define NT_STATUS_CONNECTION_INVALID 0xC0000000 | 0x023a +#define NT_STATUS_CONNECTION_ACTIVE 0xC0000000 | 0x023b +#define NT_STATUS_NETWORK_UNREACHABLE 0xC0000000 | 0x023c +#define NT_STATUS_HOST_UNREACHABLE 0xC0000000 | 0x023d +#define NT_STATUS_PROTOCOL_UNREACHABLE 0xC0000000 | 0x023e +#define NT_STATUS_PORT_UNREACHABLE 0xC0000000 | 0x023f +#define NT_STATUS_REQUEST_ABORTED 0xC0000000 | 0x0240 +#define NT_STATUS_CONNECTION_ABORTED 0xC0000000 | 0x0241 +#define NT_STATUS_BAD_COMPRESSION_BUFFER 0xC0000000 | 0x0242 +#define NT_STATUS_USER_MAPPED_FILE 0xC0000000 | 0x0243 +#define NT_STATUS_AUDIT_FAILED 0xC0000000 | 0x0244 +#define NT_STATUS_TIMER_RESOLUTION_NOT_SET 0xC0000000 | 0x0245 +#define NT_STATUS_CONNECTION_COUNT_LIMIT 0xC0000000 | 0x0246 +#define NT_STATUS_LOGIN_TIME_RESTRICTION 0xC0000000 | 0x0247 +#define NT_STATUS_LOGIN_WKSTA_RESTRICTION 0xC0000000 | 0x0248 +#define NT_STATUS_IMAGE_MP_UP_MISMATCH 0xC0000000 | 0x0249 +#define NT_STATUS_INSUFFICIENT_LOGON_INFO 0xC0000000 | 0x0250 +#define NT_STATUS_BAD_DLL_ENTRYPOINT 0xC0000000 | 0x0251 +#define NT_STATUS_BAD_SERVICE_ENTRYPOINT 0xC0000000 | 0x0252 +#define NT_STATUS_LPC_REPLY_LOST 0xC0000000 | 0x0253 +#define NT_STATUS_IP_ADDRESS_CONFLICT1 0xC0000000 | 0x0254 +#define NT_STATUS_IP_ADDRESS_CONFLICT2 0xC0000000 | 0x0255 +#define NT_STATUS_REGISTRY_QUOTA_LIMIT 0xC0000000 | 0x0256 +#define NT_STATUS_PATH_NOT_COVERED 0xC0000000 | 0x0257 +#define NT_STATUS_NO_CALLBACK_ACTIVE 0xC0000000 | 0x0258 +#define NT_STATUS_LICENSE_QUOTA_EXCEEDED 0xC0000000 | 0x0259 +#define NT_STATUS_PWD_TOO_SHORT 0xC0000000 | 0x025a +#define NT_STATUS_PWD_TOO_RECENT 0xC0000000 | 0x025b +#define NT_STATUS_PWD_HISTORY_CONFLICT 0xC0000000 | 0x025c +#define NT_STATUS_PLUGPLAY_NO_DEVICE 0xC0000000 | 0x025e +#define NT_STATUS_UNSUPPORTED_COMPRESSION 0xC0000000 | 0x025f +#define NT_STATUS_INVALID_HW_PROFILE 0xC0000000 | 0x0260 +#define NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH 0xC0000000 | 0x0261 +#define NT_STATUS_DRIVER_ORDINAL_NOT_FOUND 0xC0000000 | 0x0262 +#define NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND 0xC0000000 | 0x0263 +#define NT_STATUS_RESOURCE_NOT_OWNED 0xC0000000 | 0x0264 +#define NT_STATUS_TOO_MANY_LINKS 0xC0000000 | 0x0265 +#define NT_STATUS_QUOTA_LIST_INCONSISTENT 0xC0000000 | 0x0266 +#define NT_STATUS_FILE_IS_OFFLINE 0xC0000000 | 0x0267 +#define NT_STATUS_NO_SUCH_JOB 0xC0000000 | 0xEDE /* scheduler */ + +#endif /* _NTERR_H */ diff --git a/release/src/linux/linux/fs/cifs/ntlmssp.h b/release/src/linux/linux/fs/cifs/ntlmssp.h new file mode 100644 index 00000000..f06edcbe --- /dev/null +++ b/release/src/linux/linux/fs/cifs/ntlmssp.h @@ -0,0 +1,101 @@ +/* + * fs/cifs/ntlmssp.h + * + * Copyright (c) International Business Machines Corp., 2002 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#pragma pack(1) + +#define NTLMSSP_SIGNATURE "NTLMSSP" +/* Message Types */ +#define NtLmNegotiate 1 +#define NtLmChallenge 2 +#define NtLmAuthenticate 3 +#define UnknownMessage 8 + +/* Negotiate Flags */ +#define NTLMSSP_NEGOTIATE_UNICODE 0x01 // Text strings are in unicode +#define NTLMSSP_NEGOTIATE_OEM 0x02 // Text strings are in OEM +#define NTLMSSP_REQUEST_TARGET 0x04 // Server return its auth realm +#define NTLMSSP_NEGOTIATE_SIGN 0x0010 // Request signature capability +#define NTLMSSP_NEGOTIATE_SEAL 0x0020 // Request confidentiality +#define NTLMSSP_NEGOTIATE_DGRAM 0x0040 +#define NTLMSSP_NEGOTIATE_LM_KEY 0x0080 // Use LM session key for sign/seal +#define NTLMSSP_NEGOTIATE_NTLM 0x0200 // NTLM authentication +#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000 +#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000 +#define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x4000 // client/server on same machine +#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 // Sign for all security levels +#define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000 +#define NTLMSSP_TARGET_TYPE_SERVER 0x20000 +#define NTLMSSP_TARGET_TYPE_SHARE 0x40000 +#define NTLMSSP_NEGOTIATE_NTLMV2 0x80000 +#define NTLMSSP_REQUEST_INIT_RESP 0x100000 +#define NTLMSSP_REQUEST_ACCEPT_RESP 0x200000 +#define NTLMSSP_REQUEST_NOT_NT_KEY 0x400000 +#define NTLMSSP_NEGOTIATE_TARGET_INFO 0x800000 +#define NTLMSSP_NEGOTIATE_128 0x20000000 +#define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000 +#define NTLMSSP_NEGOTIATE_56 0x80000000 + +/* Although typedefs are not commonly used for structure definitions */ +/* in the Linux kernel, in this particular case they are useful */ +/* to more closely match the standards document for NTLMSSP from */ +/* OpenGroup and to make the code more closely match the standard in */ +/* appearance */ + +typedef struct _SECURITY_BUFFER { + __u16 Length; + __u16 MaximumLength; + __u32 Buffer; /* offset to buffer */ +} SECURITY_BUFFER; + +typedef struct _NEGOTIATE_MESSAGE { + __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; + __u32 MessageType; /* 1 */ + __u32 NegotiateFlags; + SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */ + SECURITY_BUFFER WorkstationName; /* RFC 1001 and ASCII */ + char DomainString[0]; + /* followed by WorkstationString */ +} NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE; + +typedef struct _CHALLENGE_MESSAGE { + __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; + __u32 MessageType; /* 2 */ + SECURITY_BUFFER TargetName; + __u32 NegotiateFlags; + __u8 Challenge[CIFS_CRYPTO_KEY_SIZE]; + __u8 Reserved[8]; + SECURITY_BUFFER TargetInfoArray; +} CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE; + +typedef struct _AUTHENTICATE_MESSAGE { + __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; + __u32 MessageType; /* 3 */ + SECURITY_BUFFER LmChallengeResponse; + SECURITY_BUFFER NtChallengeResponse; + SECURITY_BUFFER DomainName; + SECURITY_BUFFER UserName; + SECURITY_BUFFER WorkstationName; + SECURITY_BUFFER SessionKey; + __u32 NegotiateFlags; + char UserString[0]; +} AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE; + +#pragma pack() /* resume default structure packing */ diff --git a/release/src/linux/linux/fs/cifs/rfc1002pdu.h b/release/src/linux/linux/fs/cifs/rfc1002pdu.h new file mode 100644 index 00000000..806c0ed0 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/rfc1002pdu.h @@ -0,0 +1,79 @@ +/* + * fs/cifs/rfc1002pdu.h + * + * Protocol Data Unit definitions for RFC 1001/1002 support + * + * Copyright (c) International Business Machines Corp., 2004 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#pragma pack(1) + +/* NB: unlike smb/cifs packets, the RFC1002 structures are big endian */ + + /* RFC 1002 session packet types */ +#define RFC1002_SESSION_MESASAGE 0x00 +#define RFC1002_SESSION_REQUEST 0x81 +#define RFC1002_POSITIVE_SESSION_RESPONSE 0x82 +#define RFC1002_NEGATIVE_SESSION_RESPONSE 0x83 +#define RFC1002_RETARGET_SESSION_RESPONSE 0x83 +#define RFC1002_SESSION_KEEP_ALIVE 0x85 + + /* RFC 1002 flags (only one defined */ +#define RFC1002_LENGTH_EXTEND 0x80 /* high order bit of length (ie +64K) */ + +struct rfc1002_session_packet { + __u8 type; + __u8 flags; + __u16 length; + union { + struct { + __u8 called_len; + __u8 called_name[32]; + __u8 scope1; /* null */ + __u8 calling_len; + __u8 calling_name[32]; + __u8 scope2; /* null */ + } session_req; + struct { + __u32 retarget_ip_addr; + __u16 port; + } retarget_resp; + __u8 neg_ses_resp_error_code; + /* POSITIVE_SESSION_RESPONSE packet does not include trailer. + SESSION_KEEP_ALIVE packet also does not include a trailer. + Trailer for the SESSION_MESSAGE packet is SMB/CIFS header */ + } trailer; +}; + +/* Negative Session Response error codes */ +#define RFC1002_NOT_LISTENING_CALLED 0x80 /* not listening on called name */ +#define RFC1002_NOT_LISTENING_CALLING 0x81 /* not listening on calling name */ +#define RFC1002_NOT_PRESENT 0x82 /* called name not present */ +#define RFC1002_INSUFFICIENT_RESOURCE 0x83 +#define RFC1002_UNSPECIFIED_ERROR 0x8F + +/* RFC 1002 Datagram service packets are not defined here as they +are not needed for the network filesystem client unless we plan on +implementing broadcast resolution of the server ip address (from +server netbios name). Currently server names are resolved only via DNS +(tcp name) or ip address or an /etc/hosts equivalent mapping to ip address.*/ + +#define DEFAULT_CIFS_CALLED_NAME "*SMBSERVER " + +#pragma pack() /* resume default structure packing */ + diff --git a/release/src/linux/linux/fs/cifs/smbdes.c b/release/src/linux/linux/fs/cifs/smbdes.c new file mode 100644 index 00000000..4d765f73 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/smbdes.c @@ -0,0 +1,408 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + + a partial implementation of DES designed for use in the + SMB authentication protocol + + Copyright (C) Andrew Tridgell 1998 + Modified by Steve French (sfrench@us.ibm.com) 2002,2004 + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* NOTES: + + This code makes no attempt to be fast! In fact, it is a very + slow implementation + + This code is NOT a complete DES implementation. It implements only + the minimum necessary for SMB authentication, as used by all SMB + products (including every copy of Microsoft Windows95 ever sold) + + In particular, it can only do a unchained forward DES pass. This + means it is not possible to use this code for encryption/decryption + of data, instead it is only useful as a "hash" algorithm. + + There is no entry point into this code that allows normal DES operation. + + I believe this means that this code does not come under ITAR + regulations but this is NOT a legal opinion. If you are concerned + about the applicability of ITAR regulations to this code then you + should confirm it for yourself (and maybe let me know if you come + up with a different answer to the one above) +*/ +#include <linux/slab.h> +#define uchar unsigned char + +static uchar perm1[56] = { 57, 49, 41, 33, 25, 17, 9, + 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, + 19, 11, 3, 60, 52, 44, 36, + 63, 55, 47, 39, 31, 23, 15, + 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, + 21, 13, 5, 28, 20, 12, 4 +}; + +static uchar perm2[48] = { 14, 17, 11, 24, 1, 5, + 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, + 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, + 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, + 46, 42, 50, 36, 29, 32 +}; + +static uchar perm3[64] = { 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, + 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7 +}; + +static uchar perm4[48] = { 32, 1, 2, 3, 4, 5, + 4, 5, 6, 7, 8, 9, + 8, 9, 10, 11, 12, 13, + 12, 13, 14, 15, 16, 17, + 16, 17, 18, 19, 20, 21, + 20, 21, 22, 23, 24, 25, + 24, 25, 26, 27, 28, 29, + 28, 29, 30, 31, 32, 1 +}; + +static uchar perm5[32] = { 16, 7, 20, 21, + 29, 12, 28, 17, + 1, 15, 23, 26, + 5, 18, 31, 10, + 2, 8, 24, 14, + 32, 27, 3, 9, + 19, 13, 30, 6, + 22, 11, 4, 25 +}; + +static uchar perm6[64] = { 40, 8, 48, 16, 56, 24, 64, 32, + 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25 +}; + +static uchar sc[16] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; + +static uchar sbox[8][4][16] = { + {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7}, + {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8}, + {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0}, + {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}}, + + {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10}, + {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5}, + {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15}, + {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}}, + + {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8}, + {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1}, + {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7}, + {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}}, + + {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15}, + {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9}, + {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4}, + {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}}, + + {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9}, + {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6}, + {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14}, + {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}}, + + {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11}, + {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8}, + {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6}, + {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}}, + + {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1}, + {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6}, + {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2}, + {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}}, + + {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7}, + {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2}, + {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8}, + {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}} +}; + +static void +permute(char *out, char *in, uchar * p, int n) +{ + int i; + for (i = 0; i < n; i++) + out[i] = in[p[i] - 1]; +} + +static void +lshift(char *d, int count, int n) +{ + char out[64]; + int i; + for (i = 0; i < n; i++) + out[i] = d[(i + count) % n]; + for (i = 0; i < n; i++) + d[i] = out[i]; +} + +static void +concat(char *out, char *in1, char *in2, int l1, int l2) +{ + while (l1--) + *out++ = *in1++; + while (l2--) + *out++ = *in2++; +} + +static void +xor(char *out, char *in1, char *in2, int n) +{ + int i; + for (i = 0; i < n; i++) + out[i] = in1[i] ^ in2[i]; +} + +static void +dohash(char *out, char *in, char *key, int forw) +{ + int i, j, k; + char *pk1; + char c[28]; + char d[28]; + char *cd; + char ki[16][48]; + char *pd1; + char l[32], r[32]; + char *rl; + + /* Have to reduce stack usage */ + pk1 = kmalloc(56+56+64+64,GFP_KERNEL); + if(pk1 == NULL) + return; + + cd = pk1 + 56; + pd1= cd + 56; + rl = pd1 + 64; + + permute(pk1, key, perm1, 56); + + for (i = 0; i < 28; i++) + c[i] = pk1[i]; + for (i = 0; i < 28; i++) + d[i] = pk1[i + 28]; + + for (i = 0; i < 16; i++) { + lshift(c, sc[i], 28); + lshift(d, sc[i], 28); + + concat(cd, c, d, 28, 28); + permute(ki[i], cd, perm2, 48); + } + + permute(pd1, in, perm3, 64); + + for (j = 0; j < 32; j++) { + l[j] = pd1[j]; + r[j] = pd1[j + 32]; + } + + for (i = 0; i < 16; i++) { + char *er; /* er[48] */ + char *erk; /* erk[48] */ + char b[8][6]; + char *cb; /* cb[32] */ + char *pcb; /* pcb[32] */ + char *r2; /* r2[32] */ + + er = kmalloc(48+48+32+32+32, GFP_KERNEL); + if(er == NULL) { + kfree(pk1); + return; + } + erk = er+48; + cb = erk+48; + pcb = cb+32; + r2 = pcb+32; + + permute(er, r, perm4, 48); + + xor(erk, er, ki[forw ? i : 15 - i], 48); + + for (j = 0; j < 8; j++) + for (k = 0; k < 6; k++) + b[j][k] = erk[j * 6 + k]; + + for (j = 0; j < 8; j++) { + int m, n; + m = (b[j][0] << 1) | b[j][5]; + + n = (b[j][1] << 3) | (b[j][2] << 2) | (b[j][3] << + 1) | b[j][4]; + + for (k = 0; k < 4; k++) + b[j][k] = + (sbox[j][m][n] & (1 << (3 - k))) ? 1 : 0; + } + + for (j = 0; j < 8; j++) + for (k = 0; k < 4; k++) + cb[j * 4 + k] = b[j][k]; + permute(pcb, cb, perm5, 32); + + xor(r2, l, pcb, 32); + + for (j = 0; j < 32; j++) + l[j] = r[j]; + + for (j = 0; j < 32; j++) + r[j] = r2[j]; + + kfree(er); + } + + concat(rl, r, l, 32, 32); + + permute(out, rl, perm6, 64); + kfree(pk1); +} + +static void +str_to_key(unsigned char *str, unsigned char *key) +{ + int i; + + key[0] = str[0] >> 1; + key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2); + key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3); + key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4); + key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5); + key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6); + key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7); + key[7] = str[6] & 0x7F; + for (i = 0; i < 8; i++) { + key[i] = (key[i] << 1); + } +} + +static void +smbhash(unsigned char *out, unsigned char *in, unsigned char *key, int forw) +{ + int i; + char *outb; /* outb[64] */ + char *inb; /* inb[64] */ + char *keyb; /* keyb[64] */ + unsigned char key2[8]; + + outb = kmalloc(64 * 3,GFP_KERNEL); + if(outb == NULL) + return; + + inb = outb + 64; + keyb = inb + 64; + + str_to_key(key, key2); + + for (i = 0; i < 64; i++) { + inb[i] = (in[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0; + keyb[i] = (key2[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0; + outb[i] = 0; + } + + dohash(outb, inb, keyb, forw); + + for (i = 0; i < 8; i++) { + out[i] = 0; + } + + for (i = 0; i < 64; i++) { + if (outb[i]) + out[i / 8] |= (1 << (7 - (i % 8))); + } + kfree(outb); +} + +void +E_P16(unsigned char *p14, unsigned char *p16) +{ + unsigned char sp8[8] = + { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; + smbhash(p16, sp8, p14, 1); + smbhash(p16 + 8, sp8, p14 + 7, 1); +} + +void +E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24) +{ + smbhash(p24, c8, p21, 1); + smbhash(p24 + 8, c8, p21 + 7, 1); + smbhash(p24 + 16, c8, p21 + 14, 1); +} + +void +D_P16(unsigned char *p14, unsigned char *in, unsigned char *out) +{ + smbhash(out, in, p14, 0); + smbhash(out + 8, in + 8, p14 + 7, 0); +} + +void +E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out) +{ + smbhash(out, in, p14, 1); + smbhash(out + 8, in + 8, p14 + 7, 1); +} + +void +cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key) +{ + unsigned char buf[8]; + + smbhash(buf, in, key, 1); + smbhash(out, buf, key + 9, 1); +} + +void +cred_hash2(unsigned char *out, unsigned char *in, unsigned char *key) +{ + unsigned char buf[8]; + static unsigned char key2[8]; + + smbhash(buf, in, key, 1); + key2[0] = key[7]; + smbhash(out, buf, key2, 1); +} + +void +cred_hash3(unsigned char *out, unsigned char *in, unsigned char *key, int forw) +{ + static unsigned char key2[8]; + + smbhash(out, in, key, forw); + key2[0] = key[7]; + smbhash(out + 8, in + 8, key2, forw); +} diff --git a/release/src/linux/linux/fs/cifs/smbencrypt.c b/release/src/linux/linux/fs/cifs/smbencrypt.c new file mode 100644 index 00000000..18329601 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/smbencrypt.c @@ -0,0 +1,295 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + SMB parameters and setup + Copyright (C) Andrew Tridgell 1992-2000 + Copyright (C) Luke Kenneth Casson Leighton 1996-2000 + Modified by Jeremy Allison 1995. + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003 + Modified by Steve French (sfrench@us.ibm.com) 2002-2003 + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/random.h> +#include "cifs_unicode.h" +#include "cifspdu.h" +#include "md5.h" +#include "cifs_debug.h" + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +/* following came from the other byteorder.h to avoid include conflicts */ +#define CVAL(buf,pos) (((unsigned char *)(buf))[pos]) +#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8) +#define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val))) + +/*The following definitions come from lib/md4.c */ + +void mdfour(unsigned char *out, unsigned char *in, int n); + +/*The following definitions come from libsmb/smbdes.c */ + +void E_P16(unsigned char *p14, unsigned char *p16); +void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24); +void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out); +void E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out); +void cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key); +void cred_hash2(unsigned char *out, unsigned char *in, unsigned char *key); +void cred_hash3(unsigned char *out, unsigned char *in, unsigned char *key, + int forw); + +/*The following definitions come from libsmb/smbencrypt.c */ + +void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); +void E_md4hash(const unsigned char *passwd, unsigned char *p16); +void nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]); +void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8, + unsigned char p24[24]); +void NTLMSSPOWFencrypt(unsigned char passwd[8], + unsigned char *ntlmchalresp, unsigned char p24[24]); +void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); +int decode_pw_buffer(char in_buffer[516], char *new_pwrd, + int new_pwrd_size, __u32 * new_pw_len); + +/* + This implements the X/Open SMB password encryption + It takes a password, a 8 byte "crypt key" and puts 24 bytes of + encrypted password into p24 */ +/* Note that password must be uppercased and null terminated */ +void +SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) +{ + unsigned char p14[15], p21[21]; + + memset(p21, '\0', 21); + memset(p14, '\0', 14); + strncpy((char *) p14, (char *) passwd, 14); + +/* strupper((char *)p14); *//* BB at least uppercase the easy range */ + E_P16(p14, p21); + + SMBOWFencrypt(p21, c8, p24); + + memset(p14,0,15); + memset(p21,0,21); +} + +/* Routines for Windows NT MD4 Hash functions. */ +static int +_my_wcslen(__u16 * str) +{ + int len = 0; + while (*str++ != 0) + len++; + return len; +} + +/* + * Convert a string into an NT UNICODE string. + * Note that regardless of processor type + * this must be in intel (little-endian) + * format. + */ + +static int +_my_mbstowcs(__u16 * dst, const unsigned char *src, int len) +{ /* not a very good conversion routine - change/fix */ + int i; + __u16 val; + + for (i = 0; i < len; i++) { + val = *src; + SSVAL(dst, 0, val); + dst++; + src++; + if (val == 0) + break; + } + return i; +} + +/* + * Creates the MD4 Hash of the users password in NT UNICODE. + */ + +void +E_md4hash(const unsigned char *passwd, unsigned char *p16) +{ + int len; + __u16 wpwd[129]; + + /* Password cannot be longer than 128 characters */ + if(passwd) { + len = strlen((char *) passwd); + if (len > 128) { + len = 128; + } + /* Password must be converted to NT unicode */ + _my_mbstowcs(wpwd, passwd, len); + } else + len = 0; + + wpwd[len] = 0; /* Ensure string is null terminated */ + /* Calculate length in bytes */ + len = _my_wcslen(wpwd) * sizeof (__u16); + + mdfour(p16, (unsigned char *) wpwd, len); + memset(wpwd,0,129 * 2); +} + +/* Does both the NT and LM owfs of a user's password */ +void +nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]) +{ + char passwd[514]; + + memset(passwd, '\0', 514); + if (strlen(pwd) < 513) + strcpy(passwd, pwd); + else + memcpy(passwd, pwd, 512); + /* Calculate the MD4 hash (NT compatible) of the password */ + memset(nt_p16, '\0', 16); + E_md4hash(passwd, nt_p16); + + /* Mangle the passwords into Lanman format */ + passwd[14] = '\0'; +/* strupper(passwd); */ + + /* Calculate the SMB (lanman) hash functions of the password */ + + memset(p16, '\0', 16); + E_P16((unsigned char *) passwd, (unsigned char *) p16); + + /* clear out local copy of user's password (just being paranoid). */ + memset(passwd, '\0', sizeof (passwd)); +} + +/* Does the NTLMv2 owfs of a user's password */ +void +ntv2_owf_gen(const unsigned char owf[16], const char *user_n, + const char *domain_n, unsigned char kr_buf[16], + const struct nls_table *nls_codepage) +{ + wchar_t * user_u; + wchar_t * dom_u; + int user_l, domain_l; + struct HMACMD5Context ctx; + + /* might as well do one alloc to hold both (user_u and dom_u) */ + user_u = kmalloc(2048 * sizeof(wchar_t),GFP_KERNEL); + if(user_u == NULL) + return; + dom_u = user_u + 1024; + + /* push_ucs2(NULL, user_u, user_n, (user_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); + push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); */ + + /* BB user and domain may need to be uppercased */ + user_l = cifs_strtoUCS(user_u, user_n, 511, nls_codepage); + domain_l = cifs_strtoUCS(dom_u, domain_n, 511, nls_codepage); + + user_l++; /* trailing null */ + domain_l++; + + hmac_md5_init_limK_to_64(owf, 16, &ctx); + hmac_md5_update((const unsigned char *) user_u, user_l * 2, &ctx); + hmac_md5_update((const unsigned char *) dom_u, domain_l * 2, &ctx); + hmac_md5_final(kr_buf, &ctx); + + kfree(user_u); +} + +/* Does the des encryption from the NT or LM MD4 hash. */ +void +SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8, + unsigned char p24[24]) +{ + unsigned char p21[21]; + + memset(p21, '\0', 21); + + memcpy(p21, passwd, 16); + E_P24(p21, c8, p24); +} + +/* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */ +void +NTLMSSPOWFencrypt(unsigned char passwd[8], + unsigned char *ntlmchalresp, unsigned char p24[24]) +{ + unsigned char p21[21]; + + memset(p21, '\0', 21); + memcpy(p21, passwd, 8); + memset(p21 + 8, 0xbd, 8); + + E_P24(p21, ntlmchalresp, p24); +} + +/* Does the NT MD4 hash then des encryption. */ + +void +SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) +{ + unsigned char p21[21]; + + memset(p21, '\0', 21); + + E_md4hash(passwd, p21); + SMBOWFencrypt(p21, c8, p24); +} + +/* Does the md5 encryption from the NT hash for NTLMv2. */ +void +SMBOWFencrypt_ntv2(const unsigned char kr[16], + const struct data_blob * srv_chal, + const struct data_blob * cli_chal, unsigned char resp_buf[16]) +{ + struct HMACMD5Context ctx; + + hmac_md5_init_limK_to_64(kr, 16, &ctx); + hmac_md5_update(srv_chal->data, srv_chal->length, &ctx); + hmac_md5_update(cli_chal->data, cli_chal->length, &ctx); + hmac_md5_final(resp_buf, &ctx); +} + +void +SMBsesskeygen_ntv2(const unsigned char kr[16], + const unsigned char *nt_resp, __u8 sess_key[16]) +{ + struct HMACMD5Context ctx; + + hmac_md5_init_limK_to_64(kr, 16, &ctx); + hmac_md5_update(nt_resp, 16, &ctx); + hmac_md5_final((unsigned char *) sess_key, &ctx); +} + +void +SMBsesskeygen_ntv1(const unsigned char kr[16], + const unsigned char *nt_resp, __u8 sess_key[16]) +{ + mdfour((unsigned char *) sess_key, (unsigned char *) kr, 16); +} diff --git a/release/src/linux/linux/fs/cifs/smberr.c b/release/src/linux/linux/fs/cifs/smberr.c new file mode 100644 index 00000000..f408b42b --- /dev/null +++ b/release/src/linux/linux/fs/cifs/smberr.c @@ -0,0 +1,240 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Steve French (sfrench@us.ibm.com) 2002 + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +include "smberr.h" +#define NO_SYSLOG +/* error code stuff - put together by Merik Karman + merik@blackadder.dsh.oz.au */ + typedef const struct { + char *name; + int code; + char *message; + int posix_code; +} err_code_struct; + +/* Dos Error Messages */ +err_code_struct dos_msgs[] = { + {"ERRbadfunc", ERRbadfunc, "Invalid function.", -EINVAL}, + {"ERRbadfile", ERRbadfile, "File not found.", -ENOENT}, + {"ERRbadpath", ERRbadpath, "Directory invalid.", -ENOENT}, + {"ERRnofids", ERRnofids, "No file descriptors available", -EMFILE}, + {"ERRnoaccess", ERRnoaccess, "Access denied.", -EACCES}, + {"ERRbadfid", ERRbadfid, "Invalid file handle.", -EBADF}, + {"ERRbadmcb", 7, "Memory control blocks destroyed.", -EIO}, + {"ERRnomem", ERRnomem, + "Insufficient server memory to perform the requested function.", + -ENOMEM}, + {"ERRbadmem", ERRbadmem, "Invalid memory block address.", -EFAULT}, + {"ERRbadenv", ERRbadenv, "Invalid environment.", -EFAULT}, + {"ERRbadformat", 11, "Invalid format.", -EINVAL}, + {"ERRbadaccess", ERRbadaccess, "Invalid open mode." - EACCES}, + {"ERRbaddata", ERRbaddata, "Invalid data.", -EIO}, + {"ERR", ERRres, "reserved.", -EIO}, + {"ERRbaddrive", ERRbaddrive, "Invalid drive specified.", -ENXIO}, + {"ERRremcd", ERRremcd, + "A Delete Directory request attempted to remove the server's current directory.", + -EIO}, + {"ERRdiffdevice", ERRdiffdevice, "Not same device.", -EXDEV}, + {"ERRnofiles", ERRnofiles, "A File Search command can find no more files matching the specified criteria.", -ENOENT}, /* Note: must map to zero manually in some places such as readdir */ + {"ERRbadshare", ERRbadshare, + "The sharing mode specified for an Open conflicts with existing FIDs on the file.", + -EXTBSY}, + {"ERRlock", ERRlock, + "A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process.", + -EACCES}, + {"ERRunsup", ERRunsup, "The operation is unsupported", -EINVAL}, + {"ERRnosuchshare", ERRnosuchshare, + "You specified an invalid share name", -ENXIO}, + {"ERRfilexists", ERRfilexists, + "The file named in a Create Directory, Make New File or Link request already exists.", + -EEXIST}, + {"ERRinvalidname", ERRinvalidname, "Invalid name", -ENOENT}, + {"ERRdiskfull", ERRdiskfull, "Disk full", -ENOSPC} + + {"ERRmoredata", ERRmoredata, + "There is more data to be returned.",}, + {"ERRinvgroup", 2455, "Invalid workgroup (try the -W option)"}, + {NULL, -1, NULL, -EIO} +}; + +/* Server Error Messages */ +err_code_struct server_msgs[] = { + {"ERRerror", 1, "Non-specific error code."}, + {"ERRbadpw", 2, + "Bad password - name/password pair in a Tree Connect or Session Setup are invalid."}, + {"ERRbadtype", 3, "reserved."}, + {"ERRaccess", 4, + "The requester does not have the necessary access rights within the specified context for the requested function. The context is defined by the TID or the UID."}, + {"ERRinvnid", 5, + "The tree ID (TID) specified in a command was invalid."}, + {"ERRinvnetname", 6, "Invalid network name in tree connect."}, + {"ERRinvdevice", 7, + "Invalid device - printer request made to non-printer connection or non-printer request made to printer connection."}, + {"ERRqfull", 49, + "Print queue full (files) -- returned by open print file."}, + {"ERRqtoobig", 50, "Print queue full -- no space."}, + {"ERRqeof", 51, "EOF on print queue dump."}, + {"ERRinvpfid", 52, "Invalid print file FID."}, + {"ERRsmbcmd", 64, + "The server did not recognize the command received."}, + {"ERRsrverror", 65, + "The server encountered an internal error, e.g., system file unavailable."}, + {"ERRfilespecs", 67, + "The file handle (FID) and pathname parameters contained an invalid combination of values."}, + {"ERRreserved", 68, "reserved."}, + {"ERRbadpermits", 69, + "The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute."}, + {"ERRreserved", 70, "reserved."}, + {"ERRsetattrmode", 71, + "The attribute mode in the Set File Attribute request is invalid."}, + {"ERRpaused", 81, "Server is paused."}, + {"ERRmsgoff", 82, "Not receiving messages."}, + {"ERRnoroom", 83, "No room to buffer message."}, + {"ERRrmuns", 87, "Too many remote user names."}, + {"ERRtimeout", 88, "Operation timed out."}, + {"ERRnoresource", 89, + "No resources currently available for request."}, + {"ERRtoomanyuids", 90, "Too many UIDs active on this session."}, + {"ERRbaduid", 91, + "The UID is not known as a valid ID on this session."}, + {"ERRusempx", 250, "Temp unable to support Raw, use MPX mode."}, + {"ERRusestd", 251, + "Temp unable to support Raw, use standard read/write."}, + {"ERRcontmpx", 252, "Continue in MPX mode."}, + {"ERRreserved", 253, "reserved."}, + {"ERRreserved", 254, "reserved."}, + {"ERRnosupport", 0xFFFF, "Function not supported."}, + {NULL, -1, NULL} +}; + +/* Hard Error Messages */ +err_code_struct hard_msgs[] = { + {"ERRnowrite", 19, + "Attempt to write on write-protected diskette."}, + {"ERRbadunit", 20, "Unknown unit."}, + {"ERRnotready", 21, "Drive not ready."}, + {"ERRbadcmd", 22, "Unknown command."}, + {"ERRdata", 23, "Data error (CRC)."}, + {"ERRbadreq", 24, "Bad request structure length."}, + {"ERRseek", 25, "Seek error."}, + {"ERRbadmedia", 26, "Unknown media type."}, + {"ERRbadsector", 27, "Sector not found."}, + {"ERRnopaper", 28, "Printer out of paper."}, + {"ERRwrite", 29, "Write fault."}, + {"ERRread", 30, "Read fault."}, + {"ERRgeneral", 31, "General failure."}, + {"ERRbadshare", 32, "An open conflicts with an existing open."}, + {"ERRlock", 33, + "A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."}, + {"ERRwrongdisk", 34, "The wrong disk was found in a drive."}, + {"ERRFCBUnavail", 35, "No FCBs are available to process request."}, + {"ERRsharebufexc", 36, "A sharing buffer has been exceeded."}, + {NULL, -1, NULL} +}; + + +const struct { + int code; + char *class; + err_code_struct *err_msgs; +} err_classes[] = { + { + 0, "SUCCESS", NULL}, { + 0x01, "ERRDOS", dos_msgs}, { + 0x02, "ERRSRV", server_msgs}, { + 0x03, "ERRHRD", hard_msgs}, { + 0x04, "ERRXOS", NULL}, { + 0xE1, "ERRRMX1", NULL}, { + 0xE2, "ERRRMX2", NULL}, { + 0xE3, "ERRRMX3", NULL}, { + 0xFF, "ERRCMD", NULL}, { +-1, NULL, NULL}}; + + +/**************************************************************************** +return a SMB error string from a SMB buffer +****************************************************************************/ +char *smb_dos_errstr(char *inbuf) +{ + static pstring ret; + int class = CVAL(inbuf, smb_rcls); + int num = SVAL(inbuf, smb_err); + int i, j; + + for (i = 0; err_classes[i].class; i++) + if (err_classes[i].code == class) { + if (err_classes[i].err_msgs) { + err_code_struct *err = + err_classes[i].err_msgs; + for (j = 0; err[j].name; j++) + if (num == err[j].code) { + if (DEBUGLEVEL > 0) + slprintf(ret, + sizeof + (ret) - 1, + "%s - %s (%s)", + err_classes + [i].class, + err[j]. + name, + err[j]. + message); + else + slprintf(ret, + sizeof + (ret) - 1, + "%s - %s", + err_classes + [i].class, + err[j]. + name); + return ret; + } + } + + slprintf(ret, sizeof(ret) - 1, "%s - %d", + err_classes[i].class, num); + return ret; + } + + slprintf(ret, sizeof(ret) - 1, "Error: Unknown error (%d,%d)", + class, num); + return (ret); +} + + +/***************************************************************************** + returns an WERROR error message. + *****************************************************************************/ +char *werror_str(WERROR status) +{ + static fstring msg; + slprintf(msg, sizeof(msg), "WIN32 code 0x%08x", W_ERROR_V(status)); + return msg; +} + + +/***************************************************************************** +map a unix errno to a win32 error + *****************************************************************************/ +WERROR map_werror_from_unix(int error) +{ + NTSTATUS status = map_nt_error_from_unix(error); + return ntstatus_to_werror(status); +} diff --git a/release/src/linux/linux/fs/cifs/smberr.h b/release/src/linux/linux/fs/cifs/smberr.h new file mode 100644 index 00000000..25a39bf3 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/smberr.h @@ -0,0 +1,113 @@ +/* + * fs/cifs/smberr.h + * + * Copyright (c) International Business Machines Corp., 2002 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * See Error Codes section of the SNIA CIFS Specification + * for more information + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define SUCCESS 0 /* The request was successful. */ +#define ERRDOS 0x01 /* Error is from the core DOS operating system set */ +#define ERRSRV 0x02 /* Error is generated by the file server daemon */ +#define ERRHRD 0x03 /* Error is a hardware error. */ +#define ERRCMD 0xFF /* Command was not in the "SMB" format. */ + +/* The following error codes may be generated with the SUCCESS error class.*/ + +#define SUCCESS 0 /* The request was successful. */ + +/* The following error codes may be generated with the ERRDOS error class.*/ + +#define ERRbadfunc 1 /* Invalid function. The server did not recognize or could not perform a system call generated by the server, e.g., set the DIRECTORY attribute on a data file, invalid seek mode. */ +#define ERRbadfile 2 /*File not found. The last component of a file's pathname could not be found. */ +#define ERRbadpath 3 /* Directory invalid. A directory component in a pathname could not be found. */ +#define ERRnofids 4 /* Too many open files. The server has no file handles available. */ +#define ERRnoaccess 5 /* Access denied, the client's context does not permit the requested function. This includes the following conditions: invalid rename command, write to Fid open for read only, read on Fid open for write only, attempt to delete a non-empty directory */ +#define ERRbadfid 6 /* Invalid file handle. The file handle specified was not recognized by the server. */ +#define ERRbadmcb 7 /* Memory control blocks destroyed. */ +#define ERRnomem 8 /* Insufficient server memory to perform the requested function. */ +#define ERRbadmem 9 /* Invalid memory block address. */ +#define ERRbadenv 10 /* Invalid environment. */ +#define ERRbadformat 11 /* Invalid format. */ +#define ERRbadaccess 12 /* Invalid open mode. */ +#define ERRbaddata 13 /* Invalid data (generated only by IOCTL calls within the server). */ +#define ERRbaddrive 15 /* Invalid drive specified. */ +#define ERRremcd 16 /* A Delete Directory request attempted to remove the server's current directory. */ +#define ERRdiffdevice 17 /* Not same device (e.g., a cross volume rename was attempted */ +#define ERRnofiles 18 /* A File Search command can find no more files matching the specified criteria. */ +#define ERRgeneral 31 +#define ERRbadshare 32 /* The sharing mode specified for an Open conflicts with existing FIDs on the file. */ +#define ERRlock 33 /* A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process. */ +#define ERRunsup 50 +#define ERRnosuchshare 67 +#define ERRfilexists 80 /* The file named in the request already exists. */ +#define ERRinvparm 87 +#define ERRdiskfull 112 +#define ERRinvname 123 +#define ERRdirnotempty 145 +#define ERRnotlocked 158 +#define ERRalreadyexists 183 +#define ERRbadpipe 230 +#define ERRpipebusy 231 +#define ERRpipeclosing 232 +#define ERRnotconnected 233 +#define ERRmoredata 234 +#define ErrQuota 0x200 /* The operation would cause a quota limit to be exceeded. */ +#define ErrNotALink 0x201 /* A link operation was performed on a pathname that + was not a link. */ + +/* Following error codes may be generated with the ERRSRV error +class.*/ + +#define ERRerror 1 /* Non-specific error code. It is returned under the following conditions: resource other than disk space exhausted (e.g. TIDs), first SMB command was not negotiate, multiple negotiates attempted, and internal server error. */ +#define ERRbadpw 2 /* Bad password - name/password pair in a TreeConnect or Session Setup are invalid. */ +#define ERRbadtype 3 /* used for indicating DFS referral needed */ +#define ERRaccess 4 /* The client does not have the necessary access rights within the specified context for requested function. */ +#define ERRinvtid 5 /* The Tid specified in a command was invalid. */ +#define ERRinvnetname 6 /* Invalid network name in tree connect. */ +#define ERRinvdevice 7 /* Invalid device - printer request made to non-printer connection or non-printer request made to printer connection. */ +#define ERRqfull 49 /* Print queue full (files) -- returned by open print file. */ +#define ERRqtoobig 50 /* Print queue full -- no space. */ +#define ERRqeof 51 /* EOF on print queue dump */ +#define ERRinvpfid 52 /* Invalid print file FID. */ +#define ERRsmbcmd 64 /* The server did not recognize the command received. */ +#define ERRsrverror 65 /* The server encountered an internal error, e.g., system file unavailable. */ +#define ERRbadBID 66 /* (obsolete) */ +#define ERRfilespecs 67 /* The Fid and pathname parameters contained an invalid combination of values. */ +#define ERRbadLink 68 /* (obsolete) */ +#define ERRbadpermits 69 /* The access permissions specified for a file or directory are not a valid combination. */ +#define ERRbadPID 70 +#define ERRsetattrmode 71 /* attribute (mode) is invalid */ +#define ERRpaused 81 /* Server is paused */ +#define ERRmsgoff 82 /* reserved - messaging off */ +#define ERRnoroom 83 /* reserved - no room for message */ +#define ERRrmuns 87 /* reserved - too many remote names */ +#define ERRtimeout 88 /* operation timed out */ +#define ERRnoresource 89 /* No resources available for request */ +#define ERRtoomanyuids 90 /* Too many UIDs active on this session */ +#define ERRbaduid 91 /* The UID is not known as a valid user */ +#define ERRusempx 250 /* temporarily unable to use raw */ +#define ERRusestd 251 /* temporarily unable to use either raw or mpx */ +#define ERR_NOTIFY_ENUM_DIR 1024 +#define ERRaccountexpired 2239 +#define ERRbadclient 2240 +#define ERRbadLogonTime 2241 +#define ERRpasswordExpired 2242 +#define ERRnetlogonNotStarted 2455 +#define ERRnosupport 0xFFFF diff --git a/release/src/linux/linux/fs/cifs/transport.c b/release/src/linux/linux/fs/cifs/transport.c new file mode 100644 index 00000000..4092aea7 --- /dev/null +++ b/release/src/linux/linux/fs/cifs/transport.c @@ -0,0 +1,434 @@ +/* + * fs/cifs/transport.c + * + * Copyright (C) International Business Machines Corp., 2002,2004 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/fs.h> +#include <linux/list.h> +#include <linux/wait.h> +#include <linux/net.h> +#include <linux/version.h> +#include <asm/uaccess.h> +#include <asm/processor.h> +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_debug.h" + +extern kmem_cache_t *cifs_mid_cachep; +extern kmem_cache_t *cifs_oplock_cachep; + +struct mid_q_entry * +AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) +{ + struct mid_q_entry *temp; + + if (ses == NULL) { + cERROR(1, ("Null session passed in to AllocMidQEntry ")); + return NULL; + } + if (ses->server == NULL) { + cERROR(1, ("Null TCP session in AllocMidQEntry")); + return NULL; + } + + temp = (struct mid_q_entry *) kmem_cache_alloc(cifs_mid_cachep, + SLAB_KERNEL); + if (temp == NULL) + return temp; + else { + memset(temp, 0, sizeof (struct mid_q_entry)); + temp->mid = smb_buffer->Mid; /* always LE */ + temp->pid = current->pid; + temp->command = smb_buffer->Command; + cFYI(1, ("For smb_command %d", temp->command)); + do_gettimeofday(&temp->when_sent); + temp->ses = ses; + temp->tsk = current; + } + + spin_lock(&GlobalMid_Lock); + list_add_tail(&temp->qhead, &ses->server->pending_mid_q); + atomic_inc(&midCount); + temp->midState = MID_REQUEST_ALLOCATED; + spin_unlock(&GlobalMid_Lock); + return temp; +} + +void +DeleteMidQEntry(struct mid_q_entry *midEntry) +{ + spin_lock(&GlobalMid_Lock); + midEntry->midState = MID_FREE; + list_del(&midEntry->qhead); + atomic_dec(&midCount); + spin_unlock(&GlobalMid_Lock); + cifs_buf_release(midEntry->resp_buf); + kmem_cache_free(cifs_mid_cachep, midEntry); +} + +struct oplock_q_entry * +AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon) +{ + struct oplock_q_entry *temp; + if ((pinode== NULL) || (tcon == NULL)) { + cERROR(1, ("Null parms passed to AllocOplockQEntry")); + return NULL; + } + temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep, + SLAB_KERNEL); + if (temp == NULL) + return temp; + else { + temp->pinode = pinode; + temp->tcon = tcon; + temp->netfid = fid; + spin_lock(&GlobalMid_Lock); + list_add_tail(&temp->qhead, &GlobalOplock_Q); + spin_unlock(&GlobalMid_Lock); + } + return temp; + +} + +void DeleteOplockQEntry(struct oplock_q_entry * oplockEntry) +{ + spin_lock(&GlobalMid_Lock); + /* should we check if list empty first? */ + list_del(&oplockEntry->qhead); + spin_unlock(&GlobalMid_Lock); + kmem_cache_free(cifs_oplock_cachep, oplockEntry); +} + +int +smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, + unsigned int smb_buf_length, struct sockaddr *sin) +{ + int rc = 0; + int i = 0; + struct msghdr smb_msg; + struct iovec iov; + mm_segment_t temp_fs; + + if(ssocket == NULL) + return -ENOTSOCK; /* BB eventually add reconnect code here */ + iov.iov_base = smb_buffer; + iov.iov_len = smb_buf_length + 4; + + smb_msg.msg_name = sin; + smb_msg.msg_namelen = sizeof (struct sockaddr); + smb_msg.msg_iov = &iov; + smb_msg.msg_iovlen = 1; + smb_msg.msg_control = NULL; + smb_msg.msg_controllen = 0; + smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/ + + /* smb header is converted in header_assemble. bcc and rest of SMB word + area, and byte area if necessary, is converted to littleendian in + cifssmb.c and RFC1001 len is converted to bigendian in smb_send + Flags2 is converted in SendReceive */ + + smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); + cFYI(1, ("Sending smb of length %d ", smb_buf_length)); + dump_smb(smb_buffer, smb_buf_length + 4); + + temp_fs = get_fs(); /* we must turn off socket api parm checking */ + set_fs(get_ds()); + while(iov.iov_len > 0) { + rc = sock_sendmsg(ssocket, &smb_msg, smb_buf_length + 4); + if ((rc == -ENOSPC) || (rc == -EAGAIN)) { + i++; + if(i > 60) { + cERROR(1, + ("sends on sock %p stuck for 30 seconds", + ssocket)); + rc = -EAGAIN; + break; + } + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/2); + continue; + } + if (rc < 0) + break; + iov.iov_base += rc; + iov.iov_len -= rc; + } + set_fs(temp_fs); + + if (rc < 0) { + cERROR(1,("Error %d sending data on socket to server.", rc)); + } else { + rc = 0; + } + + return rc; +} + +int +SendReceive(const unsigned int xid, struct cifsSesInfo *ses, + struct smb_hdr *in_buf, struct smb_hdr *out_buf, + int *pbytes_returned, const int long_op) +{ + int rc = 0; + unsigned int receive_len; + long timeout; + struct mid_q_entry *midQ; + + if (ses == NULL) { + cERROR(1,("Null smb session")); + return -EIO; + } + if(ses->server == NULL) { + cERROR(1,("Null tcp session")); + return -EIO; + } + + /* Ensure that we do not send more than 50 overlapping requests + to the same server. We may make this configurable later or + use ses->maxReq */ + if(long_op == -1) { + /* oplock breaks must not be held up */ + atomic_inc(&ses->server->inFlight); + } else { + spin_lock(&GlobalMid_Lock); + while(1) { + if(atomic_read(&ses->server->inFlight) >= CIFS_MAX_REQ){ + spin_unlock(&GlobalMid_Lock); + wait_event(ses->server->request_q, + atomic_read(&ses->server->inFlight) + < CIFS_MAX_REQ); + spin_lock(&GlobalMid_Lock); + } else { + if(ses->server->tcpStatus == CifsExiting) { + spin_unlock(&GlobalMid_Lock); + return -ENOENT; + } + + /* can not count locking commands against total since + they are allowed to block on server */ + + if(long_op < 3) { + /* update # of requests on the wire to server */ + atomic_inc(&ses->server->inFlight); + } + spin_unlock(&GlobalMid_Lock); + break; + } + } + } + /* make sure that we sign in the same order that we send on this socket + and avoid races inside tcp sendmsg code that could cause corruption + of smb data */ + + down(&ses->server->tcpSem); + + if (ses->server->tcpStatus == CifsExiting) { + rc = -ENOENT; + goto out_unlock; + } else if (ses->server->tcpStatus == CifsNeedReconnect) { + cFYI(1,("tcp session dead - return to caller to retry")); + rc = -EAGAIN; + goto out_unlock; + } else if (ses->status != CifsGood) { + /* check if SMB session is bad because we are setting it up */ + if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && + (in_buf->Command != SMB_COM_NEGOTIATE)) { + rc = -EAGAIN; + goto out_unlock; + } /* else ok - we are setting up session */ + } + midQ = AllocMidQEntry(in_buf, ses); + if (midQ == NULL) { + up(&ses->server->tcpSem); + /* If not lock req, update # of requests on wire to server */ + if(long_op < 3) { + atomic_dec(&ses->server->inFlight); + wake_up(&ses->server->request_q); + } + return -ENOMEM; + } + + if (in_buf->smb_buf_length > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4) { + up(&ses->server->tcpSem); + cERROR(1, + ("Illegal length, greater than maximum frame, %d ", + in_buf->smb_buf_length)); + DeleteMidQEntry(midQ); + /* If not lock req, update # of requests on wire to server */ + if(long_op < 3) { + atomic_dec(&ses->server->inFlight); + wake_up(&ses->server->request_q); + } + return -EIO; + } + + if (in_buf->smb_buf_length > 12) + in_buf->Flags2 = cpu_to_le16(in_buf->Flags2); + + rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number); + + midQ->midState = MID_REQUEST_SUBMITTED; + rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, + (struct sockaddr *) &(ses->server->addr.sockAddr)); + if(rc < 0) { + DeleteMidQEntry(midQ); + up(&ses->server->tcpSem); + /* If not lock req, update # of requests on wire to server */ + if(long_op < 3) { + atomic_dec(&ses->server->inFlight); + wake_up(&ses->server->request_q); + } + return rc; + } else + up(&ses->server->tcpSem); + if (long_op == -1) + goto cifs_no_response_exit; + else if (long_op == 2) /* writes past end of file can take looooong time */ + timeout = 300 * HZ; + else if (long_op == 1) + timeout = 45 * HZ; /* should be greater than + servers oplock break timeout (about 43 seconds) */ + else if (long_op > 2) { + timeout = MAX_SCHEDULE_TIMEOUT; + } else + timeout = 15 * HZ; + /* wait for 15 seconds or until woken up due to response arriving or + due to last connection to this server being unmounted */ + if (signal_pending(current)) { + /* if signal pending do not hold up user for full smb timeout + but we still give response a change to complete */ + if(midQ->midState & MID_REQUEST_SUBMITTED) { + set_current_state(TASK_UNINTERRUPTIBLE); + timeout = sleep_on_timeout(&ses->server->response_q,2 * HZ); + } + } else { /* using normal timeout */ + /* timeout = wait_event_interruptible_timeout(ses->server->response_q, + (midQ->midState & MID_RESPONSE_RECEIVED) || + ((ses->server->tcpStatus != CifsGood) && + (ses->server->tcpStatus != CifsNew)), + timeout); */ + /* Can not allow user interrupts- wreaks havoc with performance */ + if(midQ->midState & MID_REQUEST_SUBMITTED) { + set_current_state(TASK_UNINTERRUPTIBLE); + timeout = sleep_on_timeout(&ses->server->response_q,timeout); + } + } + + spin_lock(&GlobalMid_Lock); + if (midQ->resp_buf) { + spin_unlock(&GlobalMid_Lock); + receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length); + } else { + cERROR(1,("No response buffer")); + if(midQ->midState == MID_REQUEST_SUBMITTED) { + if(ses->server->tcpStatus == CifsExiting) + rc = -EHOSTDOWN; + else { + ses->server->tcpStatus = CifsNeedReconnect; + midQ->midState = MID_RETRY_NEEDED; + } + } + + if (rc != -EHOSTDOWN) { + if(midQ->midState == MID_RETRY_NEEDED) { + rc = -EAGAIN; + cFYI(1,("marking request for retry")); + } else { + rc = -EIO; + } + } + spin_unlock(&GlobalMid_Lock); + DeleteMidQEntry(midQ); + /* If not lock req, update # of requests on wire to server */ + if(long_op < 3) { + atomic_dec(&ses->server->inFlight); + wake_up(&ses->server->request_q); + } + return rc; + } + + if (receive_len > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) { + cERROR(1, + ("Frame too large received. Length: %d Xid: %d", + receive_len, xid)); + rc = -EIO; + } else { /* rcvd frame is ok */ + + if (midQ->resp_buf && out_buf + && (midQ->midState == MID_RESPONSE_RECEIVED)) { + memcpy(out_buf, midQ->resp_buf, + receive_len + + 4 /* include 4 byte RFC1001 header */ ); + + dump_smb(out_buf, 92); + /* convert the length into a more usable form */ + out_buf->smb_buf_length = + be32_to_cpu(out_buf->smb_buf_length); + if((out_buf->smb_buf_length > 24) && + (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { + rc = cifs_verify_signature(out_buf, ses->mac_signing_key,midQ->sequence_number); /* BB fix BB */ + if(rc) + cFYI(1,("Unexpected signature received from server")); + } + + if (out_buf->smb_buf_length > 12) + out_buf->Flags2 = le16_to_cpu(out_buf->Flags2); + if (out_buf->smb_buf_length > 28) + out_buf->Pid = le16_to_cpu(out_buf->Pid); + if (out_buf->smb_buf_length > 28) + out_buf->PidHigh = + le16_to_cpu(out_buf->PidHigh); + + *pbytes_returned = out_buf->smb_buf_length; + + /* BB special case reconnect tid and reconnect uid here? */ + rc = map_smb_to_linux_error(out_buf); + + /* convert ByteCount if necessary */ + if (receive_len >= + sizeof (struct smb_hdr) - + 4 /* do not count RFC1001 header */ + + (2 * out_buf->WordCount) + 2 /* bcc */ ) + BCC(out_buf) = le16_to_cpu(BCC(out_buf)); + } else { + rc = -EIO; + cFYI(1,("Bad MID state? ")); + } + } +cifs_no_response_exit: + DeleteMidQEntry(midQ); + + if(long_op < 3) { + atomic_dec(&ses->server->inFlight); + wake_up(&ses->server->request_q); + } + + return rc; + +out_unlock: + up(&ses->server->tcpSem); + /* If not lock req, update # of requests on wire to server */ + if(long_op < 3) { + atomic_dec(&ses->server->inFlight); + wake_up(&ses->server->request_q); + } + + return rc; +} diff --git a/release/src/linux/linux/fs/nls/Config.in b/release/src/linux/linux/fs/nls/Config.in index 0ac7ab5d..aff381db 100644 --- a/release/src/linux/linux/fs/nls/Config.in +++ b/release/src/linux/linux/fs/nls/Config.in @@ -11,6 +11,7 @@ fi # msdos and Joliet want NLS if [ "$CONFIG_JOLIET" = "y" -o "$CONFIG_FAT_FS" != "n" \ + -o "$CONFIG_CIFS" != "n" \ -o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" \ -o "$CONFIG_SMB_NLS" = "y" -o "$CONFIG_JFS_FS" != "n" \ -o "$CONFIG_BEFS_FS" != "n" ]; then diff --git a/release/src/linux/linux/fs/squashfs/LzmaDecode.c b/release/src/linux/linux/fs/squashfs/LzmaDecode.c new file mode 100644 index 00000000..951700bd --- /dev/null +++ b/release/src/linux/linux/fs/squashfs/LzmaDecode.c @@ -0,0 +1,663 @@ +/* + LzmaDecode.c + LZMA Decoder + + LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25) + http://www.7-zip.org/ + + LZMA SDK is licensed under two licenses: + 1) GNU Lesser General Public License (GNU LGPL) + 2) Common Public License (CPL) + It means that you can select one of these two licenses and + follow rules of that license. + + SPECIAL EXCEPTION: + Igor Pavlov, as the author of this code, expressly permits you to + statically or dynamically link your code (or bind by name) to the + interfaces of this file without subjecting your linked code to the + terms of the CPL or GNU LGPL. Any modifications or additions + to this file, however, are subject to the LGPL or CPL terms. +*/ + +#include "LzmaDecode.h" + +#ifndef Byte +#define Byte unsigned char +#endif + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +typedef struct _CRangeDecoder +{ + Byte *Buffer; + Byte *BufferLim; + UInt32 Range; + UInt32 Code; + #ifdef _LZMA_IN_CB + ILzmaInCallback *InCallback; + int Result; + #endif + int ExtraBytes; +} CRangeDecoder; + +Byte RangeDecoderReadByte(CRangeDecoder *rd) +{ + if (rd->Buffer == rd->BufferLim) + { + #ifdef _LZMA_IN_CB + UInt32 size; + rd->Result = rd->InCallback->Read(rd->InCallback, &rd->Buffer, &size); + rd->BufferLim = rd->Buffer + size; + if (size == 0) + #endif + { + rd->ExtraBytes = 1; + return 0xFF; + } + } + return (*rd->Buffer++); +} + +/* #define ReadByte (*rd->Buffer++) */ +#define ReadByte (RangeDecoderReadByte(rd)) + +void RangeDecoderInit(CRangeDecoder *rd, + #ifdef _LZMA_IN_CB + ILzmaInCallback *inCallback + #else + Byte *stream, UInt32 bufferSize + #endif + ) +{ + int i; + #ifdef _LZMA_IN_CB + rd->InCallback = inCallback; + rd->Buffer = rd->BufferLim = 0; + #else + rd->Buffer = stream; + rd->BufferLim = stream + bufferSize; + #endif + rd->ExtraBytes = 0; + rd->Code = 0; + rd->Range = (0xFFFFFFFF); + for(i = 0; i < 5; i++) + rd->Code = (rd->Code << 8) | ReadByte; +} + +#define RC_INIT_VAR UInt32 range = rd->Range; UInt32 code = rd->Code; +#define RC_FLUSH_VAR rd->Range = range; rd->Code = code; +#define RC_NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | ReadByte; } + +UInt32 RangeDecoderDecodeDirectBits(CRangeDecoder *rd, int numTotalBits) +{ + RC_INIT_VAR + UInt32 result = 0; + int i; + for (i = numTotalBits; i > 0; i--) + { + /* UInt32 t; */ + range >>= 1; + + result <<= 1; + if (code >= range) + { + code -= range; + result |= 1; + } + /* + t = (code - range) >> 31; + t &= 1; + code -= range & (t - 1); + result = (result + result) | (1 - t); + */ + RC_NORMALIZE + } + RC_FLUSH_VAR + return result; +} + +int RangeDecoderBitDecode(CProb *prob, CRangeDecoder *rd) +{ + UInt32 bound = (rd->Range >> kNumBitModelTotalBits) * *prob; + if (rd->Code < bound) + { + rd->Range = bound; + *prob += (kBitModelTotal - *prob) >> kNumMoveBits; + if (rd->Range < kTopValue) + { + rd->Code = (rd->Code << 8) | ReadByte; + rd->Range <<= 8; + } + return 0; + } + else + { + rd->Range -= bound; + rd->Code -= bound; + *prob -= (*prob) >> kNumMoveBits; + if (rd->Range < kTopValue) + { + rd->Code = (rd->Code << 8) | ReadByte; + rd->Range <<= 8; + } + return 1; + } +} + +#define RC_GET_BIT2(prob, mi, A0, A1) \ + UInt32 bound = (range >> kNumBitModelTotalBits) * *prob; \ + if (code < bound) \ + { A0; range = bound; *prob += (kBitModelTotal - *prob) >> kNumMoveBits; mi <<= 1; } \ + else \ + { A1; range -= bound; code -= bound; *prob -= (*prob) >> kNumMoveBits; mi = (mi + mi) + 1; } \ + RC_NORMALIZE + +#define RC_GET_BIT(prob, mi) RC_GET_BIT2(prob, mi, ; , ;) + +int RangeDecoderBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd) +{ + int mi = 1; + int i; + #ifdef _LZMA_LOC_OPT + RC_INIT_VAR + #endif + for(i = numLevels; i > 0; i--) + { + #ifdef _LZMA_LOC_OPT + CProb *prob = probs + mi; + RC_GET_BIT(prob, mi) + #else + mi = (mi + mi) + RangeDecoderBitDecode(probs + mi, rd); + #endif + } + #ifdef _LZMA_LOC_OPT + RC_FLUSH_VAR + #endif + return mi - (1 << numLevels); +} + +int RangeDecoderReverseBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd) +{ + int mi = 1; + int i; + int symbol = 0; + #ifdef _LZMA_LOC_OPT + RC_INIT_VAR + #endif + for(i = 0; i < numLevels; i++) + { + #ifdef _LZMA_LOC_OPT + CProb *prob = probs + mi; + RC_GET_BIT2(prob, mi, ; , symbol |= (1 << i)) + #else + int bit = RangeDecoderBitDecode(probs + mi, rd); + mi = mi + mi + bit; + symbol |= (bit << i); + #endif + } + #ifdef _LZMA_LOC_OPT + RC_FLUSH_VAR + #endif + return symbol; +} + +Byte LzmaLiteralDecode(CProb *probs, CRangeDecoder *rd) +{ + int symbol = 1; + #ifdef _LZMA_LOC_OPT + RC_INIT_VAR + #endif + do + { + #ifdef _LZMA_LOC_OPT + CProb *prob = probs + symbol; + RC_GET_BIT(prob, symbol) + #else + symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd); + #endif + } + while (symbol < 0x100); + #ifdef _LZMA_LOC_OPT + RC_FLUSH_VAR + #endif + return symbol; +} + +Byte LzmaLiteralDecodeMatch(CProb *probs, CRangeDecoder *rd, Byte matchByte) +{ + int symbol = 1; + #ifdef _LZMA_LOC_OPT + RC_INIT_VAR + #endif + do + { + int bit; + int matchBit = (matchByte >> 7) & 1; + matchByte <<= 1; + #ifdef _LZMA_LOC_OPT + { + CProb *prob = probs + ((1 + matchBit) << 8) + symbol; + RC_GET_BIT2(prob, symbol, bit = 0, bit = 1) + } + #else + bit = RangeDecoderBitDecode(probs + ((1 + matchBit) << 8) + symbol, rd); + symbol = (symbol << 1) | bit; + #endif + if (matchBit != bit) + { + while (symbol < 0x100) + { + #ifdef _LZMA_LOC_OPT + CProb *prob = probs + symbol; + RC_GET_BIT(prob, symbol) + #else + symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd); + #endif + } + break; + } + } + while (symbol < 0x100); + #ifdef _LZMA_LOC_OPT + RC_FLUSH_VAR + #endif + return symbol; +} + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenChoice 0 +#define LenChoice2 (LenChoice + 1) +#define LenLow (LenChoice2 + 1) +#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) +#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + +int LzmaLenDecode(CProb *p, CRangeDecoder *rd, int posState) +{ + if(RangeDecoderBitDecode(p + LenChoice, rd) == 0) + return RangeDecoderBitTreeDecode(p + LenLow + + (posState << kLenNumLowBits), kLenNumLowBits, rd); + if(RangeDecoderBitDecode(p + LenChoice2, rd) == 0) + return kLenNumLowSymbols + RangeDecoderBitTreeDecode(p + LenMid + + (posState << kLenNumMidBits), kLenNumMidBits, rd); + return kLenNumLowSymbols + kLenNumMidSymbols + + RangeDecoderBitTreeDecode(p + LenHigh, kLenNumHighBits, rd); +} + +#define kNumStates 12 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 + +#define IsMatch 0 +#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define IsRep0Long (IsRepG2 + kNumStates) +#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) +#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) +#define LenCoder (Align + kAlignTableSize) +#define RepLenCoder (LenCoder + kNumLenProbs) +#define Literal (RepLenCoder + kNumLenProbs) + +#if Literal != LZMA_BASE_SIZE +StopCompilingDueBUG +#endif + +#ifdef _LZMA_OUT_READ + +typedef struct _LzmaVarState +{ + CRangeDecoder RangeDecoder; + Byte *Dictionary; + UInt32 DictionarySize; + UInt32 DictionaryPos; + UInt32 GlobalPos; + UInt32 Reps[4]; + int lc; + int lp; + int pb; + int State; + int PreviousIsMatch; + int RemainLen; +} LzmaVarState; + +int LzmaDecoderInit( + unsigned char *buffer, UInt32 bufferSize, + int lc, int lp, int pb, + unsigned char *dictionary, UInt32 dictionarySize, + #ifdef _LZMA_IN_CB + ILzmaInCallback *inCallback + #else + unsigned char *inStream, UInt32 inSize + #endif + ) +{ + LzmaVarState *vs = (LzmaVarState *)buffer; + CProb *p = (CProb *)(buffer + sizeof(LzmaVarState)); + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp)); + UInt32 i; + if (bufferSize < numProbs * sizeof(CProb) + sizeof(LzmaVarState)) + return LZMA_RESULT_NOT_ENOUGH_MEM; + vs->Dictionary = dictionary; + vs->DictionarySize = dictionarySize; + vs->DictionaryPos = 0; + vs->GlobalPos = 0; + vs->Reps[0] = vs->Reps[1] = vs->Reps[2] = vs->Reps[3] = 1; + vs->lc = lc; + vs->lp = lp; + vs->pb = pb; + vs->State = 0; + vs->PreviousIsMatch = 0; + vs->RemainLen = 0; + dictionary[dictionarySize - 1] = 0; + for (i = 0; i < numProbs; i++) + p[i] = kBitModelTotal >> 1; + RangeDecoderInit(&vs->RangeDecoder, + #ifdef _LZMA_IN_CB + inCallback + #else + inStream, inSize + #endif + ); + return LZMA_RESULT_OK; +} + +int LzmaDecode(unsigned char *buffer, + unsigned char *outStream, UInt32 outSize, + UInt32 *outSizeProcessed) +{ + LzmaVarState *vs = (LzmaVarState *)buffer; + CProb *p = (CProb *)(buffer + sizeof(LzmaVarState)); + CRangeDecoder rd = vs->RangeDecoder; + int state = vs->State; + int previousIsMatch = vs->PreviousIsMatch; + Byte previousByte; + UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3]; + UInt32 nowPos = 0; + UInt32 posStateMask = (1 << (vs->pb)) - 1; + UInt32 literalPosMask = (1 << (vs->lp)) - 1; + int lc = vs->lc; + int len = vs->RemainLen; + UInt32 globalPos = vs->GlobalPos; + + Byte *dictionary = vs->Dictionary; + UInt32 dictionarySize = vs->DictionarySize; + UInt32 dictionaryPos = vs->DictionaryPos; + + if (len == -1) + { + *outSizeProcessed = 0; + return LZMA_RESULT_OK; + } + + while(len > 0 && nowPos < outSize) + { + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos]; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + len--; + } + if (dictionaryPos == 0) + previousByte = dictionary[dictionarySize - 1]; + else + previousByte = dictionary[dictionaryPos - 1]; +#else + +int LzmaDecode( + Byte *buffer, UInt32 bufferSize, + int lc, int lp, int pb, + #ifdef _LZMA_IN_CB + ILzmaInCallback *inCallback, + #else + unsigned char *inStream, UInt32 inSize, + #endif + unsigned char *outStream, UInt32 outSize, + UInt32 *outSizeProcessed) +{ + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp)); + CProb *p = (CProb *)buffer; + CRangeDecoder rd; + UInt32 i; + int state = 0; + int previousIsMatch = 0; + Byte previousByte = 0; + UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1; + UInt32 nowPos = 0; + UInt32 posStateMask = (1 << pb) - 1; + UInt32 literalPosMask = (1 << lp) - 1; + int len = 0; + if (bufferSize < numProbs * sizeof(CProb)) + return LZMA_RESULT_NOT_ENOUGH_MEM; + for (i = 0; i < numProbs; i++) + p[i] = kBitModelTotal >> 1; + RangeDecoderInit(&rd, + #ifdef _LZMA_IN_CB + inCallback + #else + inStream, inSize + #endif + ); +#endif + + *outSizeProcessed = 0; + while(nowPos < outSize) + { + int posState = (int)( + (nowPos + #ifdef _LZMA_OUT_READ + + globalPos + #endif + ) + & posStateMask); + #ifdef _LZMA_IN_CB + if (rd.Result != LZMA_RESULT_OK) + return rd.Result; + #endif + if (rd.ExtraBytes != 0) + return LZMA_RESULT_DATA_ERROR; + if (RangeDecoderBitDecode(p + IsMatch + (state << kNumPosBitsMax) + posState, &rd) == 0) + { + CProb *probs = p + Literal + (LZMA_LIT_SIZE * + ((( + (nowPos + #ifdef _LZMA_OUT_READ + + globalPos + #endif + ) + & literalPosMask) << lc) + (previousByte >> (8 - lc)))); + + if (state < 4) state = 0; + else if (state < 10) state -= 3; + else state -= 6; + if (previousIsMatch) + { + Byte matchByte; + #ifdef _LZMA_OUT_READ + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + matchByte = dictionary[pos]; + #else + matchByte = outStream[nowPos - rep0]; + #endif + previousByte = LzmaLiteralDecodeMatch(probs, &rd, matchByte); + previousIsMatch = 0; + } + else + previousByte = LzmaLiteralDecode(probs, &rd); + outStream[nowPos++] = previousByte; + #ifdef _LZMA_OUT_READ + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + #endif + } + else + { + previousIsMatch = 1; + if (RangeDecoderBitDecode(p + IsRep + state, &rd) == 1) + { + if (RangeDecoderBitDecode(p + IsRepG0 + state, &rd) == 0) + { + if (RangeDecoderBitDecode(p + IsRep0Long + (state << kNumPosBitsMax) + posState, &rd) == 0) + { + #ifdef _LZMA_OUT_READ + UInt32 pos; + #endif + if ( + (nowPos + #ifdef _LZMA_OUT_READ + + globalPos + #endif + ) + == 0) + return LZMA_RESULT_DATA_ERROR; + state = state < 7 ? 9 : 11; + #ifdef _LZMA_OUT_READ + pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + previousByte = dictionary[pos]; + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + #else + previousByte = outStream[nowPos - rep0]; + #endif + outStream[nowPos++] = previousByte; + continue; + } + } + else + { + UInt32 distance; + if(RangeDecoderBitDecode(p + IsRepG1 + state, &rd) == 0) + distance = rep1; + else + { + if(RangeDecoderBitDecode(p + IsRepG2 + state, &rd) == 0) + distance = rep2; + else + { + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + len = LzmaLenDecode(p + RepLenCoder, &rd, posState); + state = state < 7 ? 8 : 11; + } + else + { + int posSlot; + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + state = state < 7 ? 7 : 10; + len = LzmaLenDecode(p + LenCoder, &rd, posState); + posSlot = RangeDecoderBitTreeDecode(p + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits), kNumPosSlotBits, &rd); + if (posSlot >= kStartPosModelIndex) + { + int numDirectBits = ((posSlot >> 1) - 1); + rep0 = ((2 | ((UInt32)posSlot & 1)) << numDirectBits); + if (posSlot < kEndPosModelIndex) + { + rep0 += RangeDecoderReverseBitTreeDecode( + p + SpecPos + rep0 - posSlot - 1, numDirectBits, &rd); + } + else + { + rep0 += RangeDecoderDecodeDirectBits(&rd, + numDirectBits - kNumAlignBits) << kNumAlignBits; + rep0 += RangeDecoderReverseBitTreeDecode(p + Align, kNumAlignBits, &rd); + } + } + else + rep0 = posSlot; + rep0++; + } + if (rep0 == (UInt32)(0)) + { + /* it's for stream version */ + len = -1; + break; + } + if (rep0 > nowPos + #ifdef _LZMA_OUT_READ + + globalPos + #endif + ) + { + return LZMA_RESULT_DATA_ERROR; + } + len += kMatchMinLen; + do + { + #ifdef _LZMA_OUT_READ + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + previousByte = dictionary[pos]; + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + #else + previousByte = outStream[nowPos - rep0]; + #endif + outStream[nowPos++] = previousByte; + len--; + } + while(len > 0 && nowPos < outSize); + } + } + + #ifdef _LZMA_OUT_READ + vs->RangeDecoder = rd; + vs->DictionaryPos = dictionaryPos; + vs->GlobalPos = globalPos + nowPos; + vs->Reps[0] = rep0; + vs->Reps[1] = rep1; + vs->Reps[2] = rep2; + vs->Reps[3] = rep3; + vs->State = state; + vs->PreviousIsMatch = previousIsMatch; + vs->RemainLen = len; + #endif + + *outSizeProcessed = nowPos; + return LZMA_RESULT_OK; +} diff --git a/release/src/linux/linux/fs/squashfs/LzmaDecode.h b/release/src/linux/linux/fs/squashfs/LzmaDecode.h new file mode 100644 index 00000000..f58944e3 --- /dev/null +++ b/release/src/linux/linux/fs/squashfs/LzmaDecode.h @@ -0,0 +1,100 @@ +/* + LzmaDecode.h + LZMA Decoder interface + + LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25) + http://www.7-zip.org/ + + LZMA SDK is licensed under two licenses: + 1) GNU Lesser General Public License (GNU LGPL) + 2) Common Public License (CPL) + It means that you can select one of these two licenses and + follow rules of that license. + + SPECIAL EXCEPTION: + Igor Pavlov, as the author of this code, expressly permits you to + statically or dynamically link your code (or bind by name) to the + interfaces of this file without subjecting your linked code to the + terms of the CPL or GNU LGPL. Any modifications or additions + to this file, however, are subject to the LGPL or CPL terms. +*/ + +#ifndef __LZMADECODE_H +#define __LZMADECODE_H + +/* #define _LZMA_IN_CB */ +/* Use callback for input data */ + +/* #define _LZMA_OUT_READ */ +/* Use read function for output data */ + +/* #define _LZMA_PROB32 */ +/* It can increase speed on some 32-bit CPUs, + but memory usage will be doubled in that case */ + +/* #define _LZMA_LOC_OPT */ +/* Enable local speed optimizations inside code */ + +#ifndef UInt32 +#ifdef _LZMA_UINT32_IS_ULONG +#define UInt32 unsigned long +#else +#define UInt32 unsigned int +#endif +#endif + +#ifdef _LZMA_PROB32 +#define CProb UInt32 +#else +#define CProb unsigned short +#endif + +#define LZMA_RESULT_OK 0 +#define LZMA_RESULT_DATA_ERROR 1 +#define LZMA_RESULT_NOT_ENOUGH_MEM 2 + +#ifdef _LZMA_IN_CB +typedef struct _ILzmaInCallback +{ + int (*Read)(void *object, unsigned char **buffer, UInt32 *bufferSize); +} ILzmaInCallback; +#endif + +#define LZMA_BASE_SIZE 1846 +#define LZMA_LIT_SIZE 768 + +/* +bufferSize = (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)))* sizeof(CProb) +bufferSize += 100 in case of _LZMA_OUT_READ +by default CProb is unsigned short, +but if specify _LZMA_PROB_32, CProb will be UInt32(unsigned int) +*/ + +#ifdef _LZMA_OUT_READ +int LzmaDecoderInit( + unsigned char *buffer, UInt32 bufferSize, + int lc, int lp, int pb, + unsigned char *dictionary, UInt32 dictionarySize, + #ifdef _LZMA_IN_CB + ILzmaInCallback *inCallback + #else + unsigned char *inStream, UInt32 inSize + #endif +); +#endif + +int LzmaDecode( + unsigned char *buffer, + #ifndef _LZMA_OUT_READ + UInt32 bufferSize, + int lc, int lp, int pb, + #ifdef _LZMA_IN_CB + ILzmaInCallback *inCallback, + #else + unsigned char *inStream, UInt32 inSize, + #endif + #endif + unsigned char *outStream, UInt32 outSize, + UInt32 *outSizeProcessed); + +#endif diff --git a/release/src/linux/linux/fs/squashfs/Makefile b/release/src/linux/linux/fs/squashfs/Makefile index 0dcd8d17..367dbfc2 100644 --- a/release/src/linux/linux/fs/squashfs/Makefile +++ b/release/src/linux/linux/fs/squashfs/Makefile @@ -4,7 +4,11 @@ O_TARGET := squashfs.o -obj-y := inode.o +obj-y := inode.o squashfs2_0.o + +ifdef CONFIG_LZMA_FS_INFLATE +obj-y += LzmaDecode.o +endif obj-m := $(O_TARGET) diff --git a/release/src/linux/linux/fs/squashfs/inode.c b/release/src/linux/linux/fs/squashfs/inode.c index 08193482..5c17f070 100644 --- a/release/src/linux/linux/fs/squashfs/inode.c +++ b/release/src/linux/linux/fs/squashfs/inode.c @@ -1,7 +1,11 @@ /* * Squashfs - a compressed read only filesystem for Linux * - * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.net> + * Copyright (c) 2002, 2003, 2004, 2005, 2006 + * Phillip Lougher <phillip@lougher.org.uk> + * + * LZMA decompressor support added by Oleg I. Vdovikin + * Copyright (c) 2005 Oleg I.Vdovikin <oleg@cs.msu.su> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -16,39 +20,47 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * Squashfs - a compressed read only filesystem for Linux * * inode.c */ -#define SQUASHFS_1_0_COMPATIBILITY - #include <linux/types.h> #include <linux/squashfs_fs.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/slab.h> #include <linux/fs.h> +#include <linux/smp_lock.h> #include <linux/locks.h> #include <linux/init.h> #include <linux/dcache.h> -#include <asm/uaccess.h> #include <linux/wait.h> -#include <asm/semaphore.h> #include <linux/zlib.h> #include <linux/blkdev.h> #include <linux/vmalloc.h> +#include <asm/uaccess.h> +#include <asm/semaphore.h> +#include <linux/autoconf.h> -#ifdef SQUASHFS_TRACE -#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args) -#else -#define TRACE(s, args...) {} +#include "squashfs.h" + +#ifdef CONFIG_LZMA_FS_INFLATE + #define SQUASHFS_LZMA #endif -#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args) +#ifdef SQUASHFS_LZMA +#include "LzmaDecode.h" + +/* default LZMA settings, should be in sync with mksquashfs */ +#define LZMA_LC 3 +#define LZMA_LP 0 +#define LZMA_PB 2 + +#define LZMA_WORKSPACE_SIZE ((LZMA_BASE_SIZE + \ + (LZMA_LIT_SIZE << (LZMA_LC + LZMA_LP))) * sizeof(CProb)) + +#endif -#define SERROR(s, args...) if(!silent) printk(KERN_ERR "SQUASHFS error: "s, ## args) -#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args) static struct super_block *squashfs_read_super(struct super_block *, void *, int); static void squashfs_put_super(struct super_block *); @@ -58,26 +70,16 @@ static int squashfs_readpage(struct file *file, struct page *page); static int squashfs_readpage4K(struct file *file, struct page *page); static int squashfs_readdir(struct file *, void *, filldir_t); static struct dentry *squashfs_lookup(struct inode *, struct dentry *); -static unsigned int read_data(struct super_block *s, char *buffer, - unsigned int index, unsigned int length, int, unsigned int *next_index); -static int squashfs_get_cached_block(struct super_block *s, char *buffer, - unsigned int block, unsigned int offset, int length, - unsigned int *next_block, unsigned int *next_offset); -static struct inode *squashfs_iget(struct super_block *s, squashfs_inode inode); -static unsigned int read_blocklist(struct inode *inode, int index, int readahead_blks, - char *block_list, char **block_p, unsigned int *bsize); -static void squashfs_put_super(struct super_block *s); - -#ifdef SQUASHFS_1_0_COMPATIBILITY -static int squashfs_readpage_lessthan4K(struct file *file, struct page *page); -static struct inode *squashfs_iget_1(struct super_block *s, squashfs_inode inode); -static unsigned int read_blocklist_1(struct inode *inode, int index, int readahead_blks, - char *block_list, char **block_p, unsigned int *bsize); -#endif - -DECLARE_MUTEX(read_data_mutex); +static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode); +static long long read_blocklist(struct inode *inode, int index, + int readahead_blks, char *block_list, + unsigned short **block_p, unsigned int *bsize); +#ifdef SQUASHFS_LZMA +static unsigned char lzma_workspace[LZMA_WORKSPACE_SIZE]; +#else static z_stream stream; +#endif static DECLARE_FSTYPE_DEV(squashfs_fs_type, "squashfs", squashfs_read_super); @@ -86,140 +88,161 @@ static unsigned char squashfs_filetype_table[] = { }; static struct super_operations squashfs_ops = { - statfs: squashfs_statfs, - put_super: squashfs_put_super, + .statfs = squashfs_statfs, + .put_super = squashfs_put_super, }; -static struct address_space_operations squashfs_symlink_aops = { - readpage: squashfs_symlink_readpage +SQSH_EXTERN struct address_space_operations squashfs_symlink_aops = { + .readpage = squashfs_symlink_readpage }; -static struct address_space_operations squashfs_aops = { - readpage: squashfs_readpage +SQSH_EXTERN struct address_space_operations squashfs_aops = { + .readpage = squashfs_readpage }; -static struct address_space_operations squashfs_aops_4K = { - readpage: squashfs_readpage4K +SQSH_EXTERN struct address_space_operations squashfs_aops_4K = { + .readpage = squashfs_readpage4K }; -#ifdef SQUASHFS_1_0_COMPATIBILITY -static struct address_space_operations squashfs_aops_lessthan4K = { - readpage: squashfs_readpage_lessthan4K -}; -#endif - static struct file_operations squashfs_dir_ops = { - read: generic_read_dir, - readdir: squashfs_readdir + .read = generic_read_dir, + .readdir = squashfs_readdir }; static struct inode_operations squashfs_dir_inode_ops = { - lookup: squashfs_lookup + .lookup = squashfs_lookup }; +static struct buffer_head *get_block_length(struct super_block *s, + int *cur_index, int *offset, int *c_byte) +{ + struct squashfs_sb_info *msblk = &s->u.squashfs_sb; + unsigned short temp; + struct buffer_head *bh; + + if (!(bh = sb_bread(s, *cur_index))) + goto out; + + if (msblk->devblksize - *offset == 1) { + if (msblk->swap) + ((unsigned char *) &temp)[1] = *((unsigned char *) + (bh->b_data + *offset)); + else + ((unsigned char *) &temp)[0] = *((unsigned char *) + (bh->b_data + *offset)); + brelse(bh); + if (!(bh = sb_bread(s, ++(*cur_index)))) + goto out; + if (msblk->swap) + ((unsigned char *) &temp)[0] = *((unsigned char *) + bh->b_data); + else + ((unsigned char *) &temp)[1] = *((unsigned char *) + bh->b_data); + *c_byte = temp; + *offset = 1; + } else { + if (msblk->swap) { + ((unsigned char *) &temp)[1] = *((unsigned char *) + (bh->b_data + *offset)); + ((unsigned char *) &temp)[0] = *((unsigned char *) + (bh->b_data + *offset + 1)); + } else { + ((unsigned char *) &temp)[0] = *((unsigned char *) + (bh->b_data + *offset)); + ((unsigned char *) &temp)[1] = *((unsigned char *) + (bh->b_data + *offset + 1)); + } + *c_byte = temp; + *offset += 2; + } + + if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) { + if (*offset == msblk->devblksize) { + brelse(bh); + if (!(bh = sb_bread(s, ++(*cur_index)))) + goto out; + *offset = 0; + } + if (*((unsigned char *) (bh->b_data + *offset)) != + SQUASHFS_MARKER_BYTE) { + ERROR("Metadata block marker corrupt @ %x\n", + *cur_index); + brelse(bh); + goto out; + } + (*offset)++; + } + return bh; + +out: + return NULL; +} + -static unsigned int read_data(struct super_block *s, char *buffer, - unsigned int index, unsigned int length, int datablock, unsigned int *next_index) +SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer, + long long index, unsigned int length, + long long *next_index) { - squashfs_sb_info *msBlk = &s->u.squashfs_sb; - struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >> msBlk->devblksize_log2) + 2]; - unsigned int offset = index & ((1 << msBlk->devblksize_log2) - 1); - unsigned int cur_index = index >> msBlk->devblksize_log2; - int bytes, avail_bytes, b, k; + struct squashfs_sb_info *msblk = &s->u.squashfs_sb; + struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >> + msblk->devblksize_log2) + 2]; + unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1); + unsigned int cur_index = index >> msblk->devblksize_log2; + int bytes, avail_bytes, b = 0, k; char *c_buffer; unsigned int compressed; unsigned int c_byte = length; - if(c_byte) { - bytes = msBlk->devblksize - offset; - if(datablock) { - c_buffer = (compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte)) ? msBlk->read_data : buffer; - c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte); - } else { - c_buffer = (compressed = SQUASHFS_COMPRESSED(c_byte)) ? msBlk->read_data : buffer; - c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); - } + if (c_byte) { + bytes = msblk->devblksize - offset; + compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte); + c_buffer = compressed ? msblk->read_data : buffer; + c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte); - TRACE("Block @ 0x%x, %scompressed size %d\n", index, compressed ? "" : "un", (unsigned int) c_byte); + TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed + ? "" : "un", (unsigned int) c_byte); - if(!(bh[0] = sb_getblk(s, cur_index))) + if (!(bh[0] = sb_getblk(s, cur_index))) goto block_release; - for(b = 1; bytes < c_byte; b++) { - if(!(bh[b] = sb_getblk(s, ++cur_index))) + + for (b = 1; bytes < c_byte; b++) { + if (!(bh[b] = sb_getblk(s, ++cur_index))) goto block_release; - bytes += msBlk->devblksize; + bytes += msblk->devblksize; } ll_rw_block(READ, b, bh); } else { - unsigned short temp; - if(!(bh[0] = sb_bread(s, cur_index))) + if (!(bh[0] = get_block_length(s, &cur_index, &offset, + &c_byte))) goto read_failure; - if(msBlk->devblksize - offset == 1) { - if(msBlk->swap) - ((unsigned char *) &temp)[1] = *((unsigned char *) (bh[0]->b_data + offset)); - else - ((unsigned char *) &temp)[0] = *((unsigned char *) (bh[0]->b_data + offset)); - brelse(bh[0]); - if(!(bh[0] = sb_bread(s, ++cur_index))) - goto read_failure; - if(msBlk->swap) - ((unsigned char *) &temp)[0] = *((unsigned char *) bh[0]->b_data); - else - ((unsigned char *) &temp)[1] = *((unsigned char *) bh[0]->b_data); - c_byte = temp; - offset = 1; - } - else { - if(msBlk->swap) { - unsigned short temp; - ((unsigned char *) &temp)[1] = *((unsigned char *) (bh[0]->b_data + offset)); - ((unsigned char *) &temp)[0] = *((unsigned char *) (bh[0]->b_data + offset + 1)); - c_byte = temp; - } else - c_byte = *((unsigned short *) (bh[0]->b_data + offset)); - offset += 2; - } - if(SQUASHFS_CHECK_DATA(msBlk->sBlk.flags)) { - if(offset == msBlk->devblksize) { - brelse(bh[0]); - if(!(bh[0] = sb_bread(s, ++cur_index))) - goto read_failure; - offset = 0; - } - if(*((unsigned char *) (bh[0]->b_data + offset)) != SQUASHFS_MARKER_BYTE) { - ERROR("Metadata block marker corrupt @ %x\n", index); - brelse(bh[0]); - return 0; - } - offset ++; - } - - bytes = msBlk->devblksize - offset; - if(datablock) { - c_buffer = (compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte)) ? msBlk->read_data : buffer; - c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte); - } else { - c_buffer = (compressed = SQUASHFS_COMPRESSED(c_byte)) ? msBlk->read_data : buffer; - c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); - } + bytes = msblk->devblksize - offset; + compressed = SQUASHFS_COMPRESSED(c_byte); + c_buffer = compressed ? msblk->read_data : buffer; + c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); - TRACE("Block @ 0x%x, %scompressed size %d\n", index, compressed ? "" : "un", (unsigned int) c_byte); + TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed + ? "" : "un", (unsigned int) c_byte); - for(b = 1; bytes < c_byte; b++) { - if(!(bh[b] = sb_getblk(s, ++cur_index))) + for (b = 1; bytes < c_byte; b++) { + if (!(bh[b] = sb_getblk(s, ++cur_index))) goto block_release; - bytes += msBlk->devblksize; + bytes += msblk->devblksize; } ll_rw_block(READ, b - 1, bh + 1); } - if(compressed) - down(&read_data_mutex); + if (compressed) + down(&msblk->read_data_mutex); - for(bytes = 0, k = 0; k < b; k++) { - avail_bytes = (c_byte - bytes) > (msBlk->devblksize - offset) ? msBlk->devblksize - offset : c_byte - bytes; + for (bytes = 0, k = 0; k < b; k++) { + avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ? + msblk->devblksize - offset : + c_byte - bytes; wait_on_buffer(bh[k]); + if (!buffer_uptodate(bh[k])) + goto block_release; memcpy(c_buffer + bytes, bh[k]->b_data + offset, avail_bytes); bytes += avail_bytes; offset = 0; @@ -229,30 +252,46 @@ static unsigned int read_data(struct super_block *s, char *buffer, /* * uncompress block */ - if(compressed) { + if (compressed) { int zlib_err; +#ifdef SQUASHFS_LZMA + if ((zlib_err = LzmaDecode(lzma_workspace, + LZMA_WORKSPACE_SIZE, LZMA_LC, LZMA_LP, LZMA_PB, + c_buffer, c_byte, buffer, msblk->read_size, &bytes)) != LZMA_RESULT_OK) + { + ERROR("lzma returned unexpected result 0x%x\n", zlib_err); + bytes = 0; + } +#else stream.next_in = c_buffer; stream.avail_in = c_byte; stream.next_out = buffer; - stream.avail_out = msBlk->read_size; - if(((zlib_err = zlib_inflateInit(&stream)) != Z_OK) || - ((zlib_err = zlib_inflate(&stream, Z_FINISH)) != Z_STREAM_END) || - ((zlib_err = zlib_inflateEnd(&stream)) != Z_OK)) { - ERROR("zlib_fs returned unexpected result 0x%x\n", zlib_err); + stream.avail_out = msblk->read_size; + + if (((zlib_err = zlib_inflateInit(&stream)) != Z_OK) || + ((zlib_err = zlib_inflate(&stream, Z_FINISH)) + != Z_STREAM_END) || ((zlib_err = + zlib_inflateEnd(&stream)) != Z_OK)) { + ERROR("zlib_fs returned unexpected result 0x%x\n", + zlib_err); bytes = 0; } else bytes = stream.total_out; - up(&read_data_mutex); +#endif + + up(&msblk->read_data_mutex); } - if(next_index) - *next_index = index + c_byte + (length ? 0 : (SQUASHFS_CHECK_DATA(msBlk->sBlk.flags) ? 3 : 2)); - + if (next_index) + *next_index = index + c_byte + (length ? 0 : + (SQUASHFS_CHECK_DATA(msblk->sblk.flags) + ? 3 : 2)); return bytes; block_release: - while(--b >= 0) brelse(bh[b]); + while (--b >= 0) + brelse(bh[b]); read_failure: ERROR("sb_bread failed reading block 0x%x\n", cur_index); @@ -260,543 +299,668 @@ read_failure: } -static int squashfs_get_cached_block(struct super_block *s, char *buffer, - unsigned int block, unsigned int offset, int length, - unsigned int *next_block, unsigned int *next_offset) +SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer, + long long block, unsigned int offset, + int length, long long *next_block, + unsigned int *next_offset) { - squashfs_sb_info *msBlk = &s->u.squashfs_sb; + struct squashfs_sb_info *msblk = &s->u.squashfs_sb; int n, i, bytes, return_length = length; - unsigned int next_index; + long long next_index; - TRACE("Entered squashfs_get_cached_block [%x:%x]\n", block, offset); + TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset); - for(;;) { - for(i = 0; i < SQUASHFS_CACHED_BLKS; i++) - if(msBlk->block_cache[i].block == block) + while ( 1 ) { + for (i = 0; i < SQUASHFS_CACHED_BLKS; i++) + if (msblk->block_cache[i].block == block) break; - down(&msBlk->block_cache_mutex); - if(i == SQUASHFS_CACHED_BLKS) { + down(&msblk->block_cache_mutex); + + if (i == SQUASHFS_CACHED_BLKS) { /* read inode header block */ - for(i = msBlk->next_cache, n = SQUASHFS_CACHED_BLKS; n ; n --, i = (i + 1) % SQUASHFS_CACHED_BLKS) - if(msBlk->block_cache[i].block != SQUASHFS_USED_BLK) + for (i = msblk->next_cache, n = SQUASHFS_CACHED_BLKS; + n ; n --, i = (i + 1) % + SQUASHFS_CACHED_BLKS) + if (msblk->block_cache[i].block != + SQUASHFS_USED_BLK) break; - if(n == 0) { - up(&msBlk->block_cache_mutex); - sleep_on(&msBlk->waitq); + + if (n == 0) { + wait_queue_t wait; + + init_waitqueue_entry(&wait, current); + add_wait_queue(&msblk->waitq, &wait); + set_current_state(TASK_UNINTERRUPTIBLE); + up(&msblk->block_cache_mutex); + schedule(); + set_current_state(TASK_RUNNING); + remove_wait_queue(&msblk->waitq, &wait); continue; } - msBlk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS; - - if(msBlk->block_cache[i].block == SQUASHFS_INVALID_BLK) { - if(!(msBlk->block_cache[i].data = (unsigned char *) - kmalloc(SQUASHFS_METADATA_SIZE, GFP_KERNEL))) { - ERROR("Failed to allocate cache block\n"); - up(&msBlk->block_cache_mutex); - return 0; + msblk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS; + + if (msblk->block_cache[i].block == + SQUASHFS_INVALID_BLK) { + if (!(msblk->block_cache[i].data = + kmalloc(SQUASHFS_METADATA_SIZE, + GFP_KERNEL))) { + ERROR("Failed to allocate cache" + "block\n"); + up(&msblk->block_cache_mutex); + goto out; } } - msBlk->block_cache[i].block = SQUASHFS_USED_BLK; - up(&msBlk->block_cache_mutex); - if(!(msBlk->block_cache[i].length = read_data(s, msBlk->block_cache[i].data, block, 0, 0, - &next_index))) { - ERROR("Unable to read cache block [%x:%x]\n", block, offset); - return 0; + msblk->block_cache[i].block = SQUASHFS_USED_BLK; + up(&msblk->block_cache_mutex); + + if (!(msblk->block_cache[i].length = + squashfs_read_data(s, + msblk->block_cache[i].data, + block, 0, &next_index))) { + ERROR("Unable to read cache block [%llx:%x]\n", + block, offset); + goto out; } - down(&msBlk->block_cache_mutex); - wake_up(&msBlk->waitq); - msBlk->block_cache[i].block = block; - msBlk->block_cache[i].next_index = next_index; - TRACE("Read cache block [%x:%x]\n", block, offset); + + down(&msblk->block_cache_mutex); + wake_up(&msblk->waitq); + msblk->block_cache[i].block = block; + msblk->block_cache[i].next_index = next_index; + TRACE("Read cache block [%llx:%x]\n", block, offset); } - if(msBlk->block_cache[i].block != block) { - up(&msBlk->block_cache_mutex); + if (msblk->block_cache[i].block != block) { + up(&msblk->block_cache_mutex); continue; } - if((bytes = msBlk->block_cache[i].length - offset) >= length) { - if(buffer) - memcpy(buffer, msBlk->block_cache[i].data + offset, length); - if(msBlk->block_cache[i].length - offset == length) { - *next_block = msBlk->block_cache[i].next_index; + if ((bytes = msblk->block_cache[i].length - offset) >= length) { + if (buffer) + memcpy(buffer, msblk->block_cache[i].data + + offset, length); + if (msblk->block_cache[i].length - offset == length) { + *next_block = msblk->block_cache[i].next_index; *next_offset = 0; } else { *next_block = block; *next_offset = offset + length; } - - up(&msBlk->block_cache_mutex); - return return_length; + up(&msblk->block_cache_mutex); + goto finish; } else { - if(buffer) { - memcpy(buffer, msBlk->block_cache[i].data + offset, bytes); + if (buffer) { + memcpy(buffer, msblk->block_cache[i].data + + offset, bytes); buffer += bytes; } - block = msBlk->block_cache[i].next_index; - up(&msBlk->block_cache_mutex); + block = msblk->block_cache[i].next_index; + up(&msblk->block_cache_mutex); length -= bytes; offset = 0; } } + +finish: + return return_length; +out: + return 0; } -static int get_fragment_location(struct super_block *s, unsigned int fragment, unsigned int *fragment_start_block, unsigned int *fragment_size) +static int get_fragment_location(struct super_block *s, unsigned int fragment, + long long *fragment_start_block, + unsigned int *fragment_size) { - squashfs_sb_info *msBlk = &s->u.squashfs_sb; - unsigned int start_block = msBlk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)]; + struct squashfs_sb_info *msblk = &s->u.squashfs_sb; + long long start_block = + msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)]; int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment); - squashfs_fragment_entry fragment_entry; + struct squashfs_fragment_entry fragment_entry; - if(msBlk->swap) { - squashfs_fragment_entry sfragment_entry; + if (msblk->swap) { + struct squashfs_fragment_entry sfragment_entry; - if(!squashfs_get_cached_block(s, (char *) &sfragment_entry, start_block, offset, - sizeof(sfragment_entry), &start_block, &offset)) - return 0; + if (!squashfs_get_cached_block(s, (char *) &sfragment_entry, + start_block, offset, + sizeof(sfragment_entry), &start_block, + &offset)) + goto out; SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry); } else - if(!squashfs_get_cached_block(s, (char *) &fragment_entry, start_block, offset, - sizeof(fragment_entry), &start_block, &offset)) - return 0; + if (!squashfs_get_cached_block(s, (char *) &fragment_entry, + start_block, offset, + sizeof(fragment_entry), &start_block, + &offset)) + goto out; *fragment_start_block = fragment_entry.start_block; *fragment_size = fragment_entry.size; return 1; + +out: + return 0; } -void release_cached_fragment(squashfs_sb_info *msBlk, struct squashfs_fragment_cache *fragment) +SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, struct + squashfs_fragment_cache *fragment) { - down(&msBlk->fragment_mutex); + down(&msblk->fragment_mutex); fragment->locked --; - wake_up(&msBlk->fragment_wait_queue); - up(&msBlk->fragment_mutex); + wake_up(&msblk->fragment_wait_queue); + up(&msblk->fragment_mutex); } -struct squashfs_fragment_cache *get_cached_fragment(struct super_block *s, unsigned int start_block, int length) +SQSH_EXTERN struct squashfs_fragment_cache *get_cached_fragment(struct super_block + *s, long long start_block, + int length) { int i, n; - squashfs_sb_info *msBlk = &s->u.squashfs_sb; - - for(;;) { - down(&msBlk->fragment_mutex); - for(i = 0; i < SQUASHFS_CACHED_FRAGMENTS && msBlk->fragment[i].block != start_block; i++); - if(i == SQUASHFS_CACHED_FRAGMENTS) { - for(i = msBlk->next_fragment, n = SQUASHFS_CACHED_FRAGMENTS; - n && msBlk->fragment[i].locked; n--, i = (i + 1) % SQUASHFS_CACHED_FRAGMENTS); - - if(n == 0) { - up(&msBlk->fragment_mutex); - sleep_on(&msBlk->fragment_wait_queue); + struct squashfs_sb_info *msblk = &s->u.squashfs_sb; + + while ( 1 ) { + down(&msblk->fragment_mutex); + + for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS && + msblk->fragment[i].block != start_block; i++); + + if (i == SQUASHFS_CACHED_FRAGMENTS) { + for (i = msblk->next_fragment, n = + SQUASHFS_CACHED_FRAGMENTS; n && + msblk->fragment[i].locked; n--, i = (i + 1) % + SQUASHFS_CACHED_FRAGMENTS); + + if (n == 0) { + wait_queue_t wait; + + init_waitqueue_entry(&wait, current); + add_wait_queue(&msblk->fragment_wait_queue, + &wait); + set_current_state(TASK_UNINTERRUPTIBLE); + up(&msblk->fragment_mutex); + schedule(); + set_current_state(TASK_RUNNING); + remove_wait_queue(&msblk->fragment_wait_queue, + &wait); continue; } - msBlk->next_fragment = (msBlk->next_fragment + 1) % SQUASHFS_CACHED_FRAGMENTS; + msblk->next_fragment = (msblk->next_fragment + 1) % + SQUASHFS_CACHED_FRAGMENTS; - if(msBlk->fragment[i].data == NULL) - if(!(msBlk->fragment[i].data = (unsigned char *) - kmalloc(SQUASHFS_FILE_MAX_SIZE, GFP_KERNEL))) { - ERROR("Failed to allocate fragment cache block\n"); - up(&msBlk->fragment_mutex); - return NULL; + if (msblk->fragment[i].data == NULL) + if (!(msblk->fragment[i].data = SQUASHFS_ALLOC + (SQUASHFS_FILE_MAX_SIZE))) { + ERROR("Failed to allocate fragment " + "cache block\n"); + up(&msblk->fragment_mutex); + goto out; } - msBlk->fragment[i].block = SQUASHFS_INVALID_BLK; - msBlk->fragment[i].locked = 1; - up(&msBlk->fragment_mutex); - if(!(msBlk->fragment[i].length = read_data(s, msBlk->fragment[i].data, start_block, length, - 1, NULL))) { - ERROR("Unable to read fragment cache block [%x]\n", start_block); - msBlk->fragment[i].locked = 0; - return NULL; + msblk->fragment[i].block = SQUASHFS_INVALID_BLK; + msblk->fragment[i].locked = 1; + up(&msblk->fragment_mutex); + + if (!(msblk->fragment[i].length = squashfs_read_data(s, + msblk->fragment[i].data, + start_block, length, NULL))) { + ERROR("Unable to read fragment cache block " + "[%llx]\n", start_block); + msblk->fragment[i].locked = 0; + goto out; } - msBlk->fragment[i].block = start_block; - TRACE("New fragment %d, start block %d, locked %d\n", i, msBlk->fragment[i].block, msBlk->fragment[i].locked); - return &msBlk->fragment[i]; + + msblk->fragment[i].block = start_block; + TRACE("New fragment %d, start block %lld, locked %d\n", + i, msblk->fragment[i].block, + msblk->fragment[i].locked); + break; } - msBlk->fragment[i].locked ++; - up(&msBlk->fragment_mutex); - - TRACE("Got fragment %d, start block %d, locked %d\n", i, msBlk->fragment[i].block, msBlk->fragment[i].locked); - return &msBlk->fragment[i]; + msblk->fragment[i].locked++; + up(&msblk->fragment_mutex); + TRACE("Got fragment %d, start block %lld, locked %d\n", i, + msblk->fragment[i].block, + msblk->fragment[i].locked); + break; } + + return &msblk->fragment[i]; + +out: + return NULL; } -#ifdef SQUASHFS_1_0_COMPATIBILITY -static struct inode *squashfs_iget_1(struct super_block *s, squashfs_inode inode) +static struct inode *squashfs_new_inode(struct super_block *s, + struct squashfs_base_inode_header *inodeb) { + struct squashfs_sb_info *msblk = &s->u.squashfs_sb; struct inode *i = new_inode(s); - squashfs_sb_info *msBlk = &s->u.squashfs_sb; - squashfs_super_block *sBlk = &msBlk->sBlk; - unsigned int block = SQUASHFS_INODE_BLK(inode) + sBlk->inode_table_start; - unsigned int offset = SQUASHFS_INODE_OFFSET(inode); - unsigned int next_block, next_offset; - squashfs_base_inode_header_1 inodeb; - - TRACE("Entered squashfs_iget_1\n"); - if(msBlk->swap) { - squashfs_base_inode_header_1 sinodeb; + if (i) { + i->i_ino = inodeb->inode_number; + i->i_mtime = inodeb->mtime; + i->i_atime = inodeb->mtime; + i->i_ctime = inodeb->mtime; + i->i_uid = msblk->uid[inodeb->uid]; + i->i_mode = inodeb->mode; + i->i_size = 0; + if (inodeb->guid == SQUASHFS_GUIDS) + i->i_gid = i->i_uid; + else + i->i_gid = msblk->guid[inodeb->guid]; + } - if(!squashfs_get_cached_block(s, (char *) &sinodeb, block, offset, - sizeof(sinodeb), &next_block, &next_offset)) - goto failed_read; - SQUASHFS_SWAP_BASE_INODE_HEADER_1(&inodeb, &sinodeb, sizeof(sinodeb)); - } else - if(!squashfs_get_cached_block(s, (char *) &inodeb, block, offset, - sizeof(inodeb), &next_block, &next_offset)) - goto failed_read; + return i; +} - i->i_nlink = 1; - i->i_mtime = sBlk->mkfs_time; - i->i_atime = sBlk->mkfs_time; - i->i_ctime = sBlk->mkfs_time; +static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode) +{ + struct inode *i; + struct squashfs_sb_info *msblk = &s->u.squashfs_sb; + struct squashfs_super_block *sblk = &msblk->sblk; + long long block = SQUASHFS_INODE_BLK(inode) + + sblk->inode_table_start; + unsigned int offset = SQUASHFS_INODE_OFFSET(inode); + long long next_block; + unsigned int next_offset; + union squashfs_inode_header id, sid; + struct squashfs_base_inode_header *inodeb = &id.base, + *sinodeb = &sid.base; - if(inodeb.inode_type != SQUASHFS_IPC_TYPE) - i->i_uid = msBlk->uid[((inodeb.inode_type - 1) / SQUASHFS_TYPES) * 16 + inodeb.uid]; - i->i_ino = SQUASHFS_MK_VFS_INODE(block - sBlk->inode_table_start, offset); + TRACE("Entered squashfs_iget\n"); - i->i_mode = inodeb.mode; + if (msblk->swap) { + if (!squashfs_get_cached_block(s, (char *) sinodeb, block, + offset, sizeof(*sinodeb), &next_block, + &next_offset)) + goto failed_read; + SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb, + sizeof(*sinodeb)); + } else + if (!squashfs_get_cached_block(s, (char *) inodeb, block, + offset, sizeof(*inodeb), &next_block, + &next_offset)) + goto failed_read; - switch(inodeb.inode_type == SQUASHFS_IPC_TYPE ? SQUASHFS_IPC_TYPE : (inodeb.inode_type - 1) % SQUASHFS_TYPES + 1) { + switch(inodeb->inode_type) { case SQUASHFS_FILE_TYPE: { - squashfs_reg_inode_header_1 inodep; - - if(msBlk->swap) { - squashfs_reg_inode_header_1 sinodep; - - if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), - &next_block, &next_offset)) + unsigned int frag_size; + long long frag_blk; + struct squashfs_reg_inode_header *inodep = &id.reg; + struct squashfs_reg_inode_header *sinodep = &sid.reg; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, (char *) + sinodep, block, offset, + sizeof(*sinodep), &next_block, + &next_offset)) goto failed_read; - SQUASHFS_SWAP_REG_INODE_HEADER_1(&inodep, &sinodep); + SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep); } else - if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), - &next_block, &next_offset)) + if (!squashfs_get_cached_block(s, (char *) + inodep, block, offset, + sizeof(*inodep), &next_block, + &next_offset)) goto failed_read; - i->i_size = inodep.file_size; + frag_blk = SQUASHFS_INVALID_BLK; + if (inodep->fragment != SQUASHFS_INVALID_FRAG && + !get_fragment_location(s, + inodep->fragment, &frag_blk, &frag_size)) + goto failed_read; + + if((i = squashfs_new_inode(s, inodeb)) == NULL) + goto failed_read1; + + i->i_nlink = 1; + i->i_size = inodep->file_size; i->i_fop = &generic_ro_fops; - if(sBlk->block_size > 4096) + i->i_mode |= S_IFREG; + i->i_blocks = ((i->i_size - 1) >> 9) + 1; + i->i_blksize = PAGE_CACHE_SIZE; + SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; + SQUASHFS_I(i)->u.s1.fragment_size = frag_size; + SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; + SQUASHFS_I(i)->start_block = inodep->start_block; + SQUASHFS_I(i)->u.s1.block_list_start = next_block; + SQUASHFS_I(i)->offset = next_offset; + if (sblk->block_size > 4096) i->i_data.a_ops = &squashfs_aops; - else if(sBlk->block_size == 4096) - i->i_data.a_ops = &squashfs_aops_4K; else - i->i_data.a_ops = &squashfs_aops_lessthan4K; + i->i_data.a_ops = &squashfs_aops_4K; + + TRACE("File inode %x:%x, start_block %llx, " + "block_list_start %llx, offset %x\n", + SQUASHFS_INODE_BLK(inode), offset, + inodep->start_block, next_block, + next_offset); + break; + } + case SQUASHFS_LREG_TYPE: { + unsigned int frag_size; + long long frag_blk; + struct squashfs_lreg_inode_header *inodep = &id.lreg; + struct squashfs_lreg_inode_header *sinodep = &sid.lreg; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, (char *) + sinodep, block, offset, + sizeof(*sinodep), &next_block, + &next_offset)) + goto failed_read; + SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep); + } else + if (!squashfs_get_cached_block(s, (char *) + inodep, block, offset, + sizeof(*inodep), &next_block, + &next_offset)) + goto failed_read; + + frag_blk = SQUASHFS_INVALID_BLK; + if (inodep->fragment != SQUASHFS_INVALID_FRAG && + !get_fragment_location(s, + inodep->fragment, &frag_blk, &frag_size)) + goto failed_read; + + if((i = squashfs_new_inode(s, inodeb)) == NULL) + goto failed_read1; + + i->i_nlink = inodep->nlink; + i->i_size = inodep->file_size; + i->i_fop = &generic_ro_fops; i->i_mode |= S_IFREG; - i->i_mtime = inodep.mtime; - i->i_atime = inodep.mtime; - i->i_ctime = inodep.mtime; i->i_blocks = ((i->i_size - 1) >> 9) + 1; i->i_blksize = PAGE_CACHE_SIZE; - i->u.squashfs_i.fragment_start_block = SQUASHFS_INVALID_BLK; - i->u.squashfs_i.fragment_offset = 0; - i->u.squashfs_i.start_block = inodep.start_block; - i->u.squashfs_i.block_list_start = next_block; - i->u.squashfs_i.offset = next_offset; - TRACE("File inode %x:%x, start_block %x, block_list_start %x, offset %x\n", - SQUASHFS_INODE_BLK(inode), offset, inodep.start_block, next_block, next_offset); + SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; + SQUASHFS_I(i)->u.s1.fragment_size = frag_size; + SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; + SQUASHFS_I(i)->start_block = inodep->start_block; + SQUASHFS_I(i)->u.s1.block_list_start = next_block; + SQUASHFS_I(i)->offset = next_offset; + if (sblk->block_size > 4096) + i->i_data.a_ops = &squashfs_aops; + else + i->i_data.a_ops = &squashfs_aops_4K; + + TRACE("File inode %x:%x, start_block %llx, " + "block_list_start %llx, offset %x\n", + SQUASHFS_INODE_BLK(inode), offset, + inodep->start_block, next_block, + next_offset); break; } case SQUASHFS_DIR_TYPE: { - squashfs_dir_inode_header_1 inodep; + struct squashfs_dir_inode_header *inodep = &id.dir; + struct squashfs_dir_inode_header *sinodep = &sid.dir; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, (char *) + sinodep, block, offset, + sizeof(*sinodep), &next_block, + &next_offset)) + goto failed_read; + SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep); + } else + if (!squashfs_get_cached_block(s, (char *) + inodep, block, offset, + sizeof(*inodep), &next_block, + &next_offset)) + goto failed_read; - if(msBlk->swap) { - squashfs_dir_inode_header_1 sinodep; + if((i = squashfs_new_inode(s, inodeb)) == NULL) + goto failed_read1; - if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), - &next_block, &next_offset)) + i->i_nlink = inodep->nlink; + i->i_size = inodep->file_size; + i->i_op = &squashfs_dir_inode_ops; + i->i_fop = &squashfs_dir_ops; + i->i_mode |= S_IFDIR; + SQUASHFS_I(i)->start_block = inodep->start_block; + SQUASHFS_I(i)->offset = inodep->offset; + SQUASHFS_I(i)->u.s2.directory_index_count = 0; + SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode; + + TRACE("Directory inode %x:%x, start_block %x, offset " + "%x\n", SQUASHFS_INODE_BLK(inode), + offset, inodep->start_block, + inodep->offset); + break; + } + case SQUASHFS_LDIR_TYPE: { + struct squashfs_ldir_inode_header *inodep = &id.ldir; + struct squashfs_ldir_inode_header *sinodep = &sid.ldir; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, (char *) + sinodep, block, offset, + sizeof(*sinodep), &next_block, + &next_offset)) goto failed_read; - SQUASHFS_SWAP_DIR_INODE_HEADER_1(&inodep, &sinodep); + SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep, + sinodep); } else - if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), - &next_block, &next_offset)) + if (!squashfs_get_cached_block(s, (char *) + inodep, block, offset, + sizeof(*inodep), &next_block, + &next_offset)) goto failed_read; - i->i_size = inodep.file_size; + if((i = squashfs_new_inode(s, inodeb)) == NULL) + goto failed_read1; + + i->i_nlink = inodep->nlink; + i->i_size = inodep->file_size; i->i_op = &squashfs_dir_inode_ops; i->i_fop = &squashfs_dir_ops; i->i_mode |= S_IFDIR; - i->i_mtime = inodep.mtime; - i->i_atime = inodep.mtime; - i->i_ctime = inodep.mtime; - i->u.squashfs_i.start_block = inodep.start_block; - i->u.squashfs_i.offset = inodep.offset; - TRACE("Directory inode %x:%x, start_block %x, offset %x\n", SQUASHFS_INODE_BLK(inode), offset, - inodep.start_block, inodep.offset); + SQUASHFS_I(i)->start_block = inodep->start_block; + SQUASHFS_I(i)->offset = inodep->offset; + SQUASHFS_I(i)->u.s2.directory_index_start = next_block; + SQUASHFS_I(i)->u.s2.directory_index_offset = + next_offset; + SQUASHFS_I(i)->u.s2.directory_index_count = + inodep->i_count; + SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode; + + TRACE("Long directory inode %x:%x, start_block %x, " + "offset %x\n", + SQUASHFS_INODE_BLK(inode), offset, + inodep->start_block, inodep->offset); break; } case SQUASHFS_SYMLINK_TYPE: { - squashfs_symlink_inode_header_1 inodep; + struct squashfs_symlink_inode_header *inodep = + &id.symlink; + struct squashfs_symlink_inode_header *sinodep = + &sid.symlink; - if(msBlk->swap) { - squashfs_symlink_inode_header_1 sinodep; - - if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), - &next_block, &next_offset)) + if (msblk->swap) { + if (!squashfs_get_cached_block(s, (char *) + sinodep, block, offset, + sizeof(*sinodep), &next_block, + &next_offset)) goto failed_read; - SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(&inodep, &sinodep); + SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, + sinodep); } else - if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), - &next_block, &next_offset)) + if (!squashfs_get_cached_block(s, (char *) + inodep, block, offset, + sizeof(*inodep), &next_block, + &next_offset)) goto failed_read; - i->i_size = inodep.symlink_size; + if((i = squashfs_new_inode(s, inodeb)) == NULL) + goto failed_read1; + + i->i_nlink = inodep->nlink; + i->i_size = inodep->symlink_size; i->i_op = &page_symlink_inode_operations; i->i_data.a_ops = &squashfs_symlink_aops; i->i_mode |= S_IFLNK; - i->u.squashfs_i.start_block = next_block; - i->u.squashfs_i.offset = next_offset; - TRACE("Symbolic link inode %x:%x, start_block %x, offset %x\n", - SQUASHFS_INODE_BLK(inode), offset, next_block, next_offset); + SQUASHFS_I(i)->start_block = next_block; + SQUASHFS_I(i)->offset = next_offset; + + TRACE("Symbolic link inode %x:%x, start_block %llx, " + "offset %x\n", + SQUASHFS_INODE_BLK(inode), offset, + next_block, next_offset); break; } case SQUASHFS_BLKDEV_TYPE: case SQUASHFS_CHRDEV_TYPE: { - squashfs_dev_inode_header_1 inodep; - - if(msBlk->swap) { - squashfs_dev_inode_header_1 sinodep; - - if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), - &next_block, &next_offset)) + struct squashfs_dev_inode_header *inodep = &id.dev; + struct squashfs_dev_inode_header *sinodep = &sid.dev; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, (char *) + sinodep, block, offset, + sizeof(*sinodep), &next_block, + &next_offset)) goto failed_read; - SQUASHFS_SWAP_DEV_INODE_HEADER_1(&inodep, &sinodep); + SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep); } else - if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), - &next_block, &next_offset)) + if (!squashfs_get_cached_block(s, (char *) + inodep, block, offset, + sizeof(*inodep), &next_block, + &next_offset)) goto failed_read; - i->i_size = 0; - i->i_mode |= (inodeb.inode_type == SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : S_IFBLK; - init_special_inode(i, i->i_mode, inodep.rdev); - TRACE("Device inode %x:%x, rdev %x\n", SQUASHFS_INODE_BLK(inode), offset, inodep.rdev); - break; - } - case SQUASHFS_IPC_TYPE: { - squashfs_ipc_inode_header_1 inodep; + if ((i = squashfs_new_inode(s, inodeb)) == NULL) + goto failed_read1; - if(msBlk->swap) { - squashfs_ipc_inode_header_1 sinodep; + i->i_nlink = inodep->nlink; + i->i_mode |= (inodeb->inode_type == + SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : + S_IFBLK; + init_special_inode(i, i->i_mode, inodep->rdev); - if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), - &next_block, &next_offset)) + TRACE("Device inode %x:%x, rdev %x\n", + SQUASHFS_INODE_BLK(inode), offset, + inodep->rdev); + break; + } + case SQUASHFS_FIFO_TYPE: + case SQUASHFS_SOCKET_TYPE: { + struct squashfs_ipc_inode_header *inodep = &id.ipc; + struct squashfs_ipc_inode_header *sinodep = &sid.ipc; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, (char *) + sinodep, block, offset, + sizeof(*sinodep), &next_block, + &next_offset)) goto failed_read; - SQUASHFS_SWAP_IPC_INODE_HEADER_1(&inodep, &sinodep); + SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep); } else - if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), - &next_block, &next_offset)) + if (!squashfs_get_cached_block(s, (char *) + inodep, block, offset, + sizeof(*inodep), &next_block, + &next_offset)) goto failed_read; - i->i_size = 0; - i->i_mode |= (inodep.type == SQUASHFS_FIFO_TYPE) ? S_IFIFO : S_IFSOCK; - i->i_uid = msBlk->uid[inodep.offset * 16 + inodeb.uid]; + if ((i = squashfs_new_inode(s, inodeb)) == NULL) + goto failed_read1; + + i->i_nlink = inodep->nlink; + i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE) + ? S_IFIFO : S_IFSOCK; init_special_inode(i, i->i_mode, 0); break; } default: - ERROR("Unknown inode type %d in squashfs_iget!\n", inodeb.inode_type); - goto failed_read1; + ERROR("Unknown inode type %d in squashfs_iget!\n", + inodeb->inode_type); + goto failed_read1; } - if(inodeb.guid == 15) - i->i_gid = i->i_uid; - else - i->i_gid = msBlk->guid[inodeb.guid]; - + insert_inode_hash(i); return i; failed_read: - ERROR("Unable to read inode [%x:%x]\n", block, offset); + ERROR("Unable to read inode [%llx:%x]\n", block, offset); failed_read1: return NULL; } -#endif -static struct inode *squashfs_iget(struct super_block *s, squashfs_inode inode) +int read_fragment_index_table(struct super_block *s) { - struct inode *i = new_inode(s); - squashfs_sb_info *msBlk = &s->u.squashfs_sb; - squashfs_super_block *sBlk = &msBlk->sBlk; - unsigned int block = SQUASHFS_INODE_BLK(inode) + sBlk->inode_table_start; - unsigned int offset = SQUASHFS_INODE_OFFSET(inode); - unsigned int next_block, next_offset; - squashfs_base_inode_header inodeb; - - TRACE("Entered squashfs_iget\n"); - - if(msBlk->swap) { - squashfs_base_inode_header sinodeb; + struct squashfs_sb_info *msblk = &s->u.squashfs_sb; + struct squashfs_super_block *sblk = &msblk->sblk; - if(!squashfs_get_cached_block(s, (char *) &sinodeb, block, offset, - sizeof(sinodeb), &next_block, &next_offset)) - goto failed_read; - SQUASHFS_SWAP_BASE_INODE_HEADER(&inodeb, &sinodeb, sizeof(sinodeb)); - } else - if(!squashfs_get_cached_block(s, (char *) &inodeb, block, offset, - sizeof(inodeb), &next_block, &next_offset)) - goto failed_read; - - i->i_nlink = 1; - - i->i_mtime = sBlk->mkfs_time; - i->i_atime = sBlk->mkfs_time; - i->i_ctime = sBlk->mkfs_time; - - if(inodeb.inode_type != SQUASHFS_IPC_TYPE) - i->i_uid = msBlk->uid[((inodeb.inode_type - 1) / SQUASHFS_TYPES) * 16 + inodeb.uid]; - i->i_ino = SQUASHFS_MK_VFS_INODE(block - sBlk->inode_table_start, offset); - - i->i_mode = inodeb.mode; - - switch(inodeb.inode_type) { - case SQUASHFS_FILE_TYPE: { - squashfs_reg_inode_header inodep; - - if(msBlk->swap) { - squashfs_reg_inode_header sinodep; - - if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), - &next_block, &next_offset)) - goto failed_read; - SQUASHFS_SWAP_REG_INODE_HEADER(&inodep, &sinodep); - } else - if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), - &next_block, &next_offset)) - goto failed_read; + if (!(msblk->fragment_index = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES + (sblk->fragments), GFP_KERNEL))) { + ERROR("Failed to allocate uid/gid table\n"); + return 0; + } + + if (SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments) && + !squashfs_read_data(s, (char *) + msblk->fragment_index, + sblk->fragment_table_start, + SQUASHFS_FRAGMENT_INDEX_BYTES + (sblk->fragments) | + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { + ERROR("unable to read fragment index table\n"); + return 0; + } - i->u.squashfs_i.fragment_start_block = SQUASHFS_INVALID_BLK; - if(inodep.fragment != SQUASHFS_INVALID_BLK && !get_fragment_location(s, inodep.fragment, - &i->u.squashfs_i.fragment_start_block, &i->u.squashfs_i.fragment_size)) - goto failed_read; + if (msblk->swap) { + int i; + long long fragment; - i->u.squashfs_i.fragment_offset = inodep.offset; - i->i_size = inodep.file_size; - i->i_fop = &generic_ro_fops; - if(sBlk->block_size > 4096) - i->i_data.a_ops = &squashfs_aops; - else - i->i_data.a_ops = &squashfs_aops_4K; - i->i_mode |= S_IFREG; - i->i_mtime = inodep.mtime; - i->i_atime = inodep.mtime; - i->i_ctime = inodep.mtime; - i->i_blocks = ((i->i_size - 1) >> 9) + 1; - i->i_blksize = PAGE_CACHE_SIZE; - i->u.squashfs_i.start_block = inodep.start_block; - i->u.squashfs_i.block_list_start = next_block; - i->u.squashfs_i.offset = next_offset; - TRACE("File inode %x:%x, start_block %x, block_list_start %x, offset %x fragment_index %x fragment_offset %x\n", - SQUASHFS_INODE_BLK(inode), offset, inodep.start_block, next_block, next_offset, inodep.fragment, inodep.offset); - break; + for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments); + i++) { + SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment), + &msblk->fragment_index[i], 1); + msblk->fragment_index[i] = fragment; } - case SQUASHFS_DIR_TYPE: { - squashfs_dir_inode_header inodep; + } - if(msBlk->swap) { - squashfs_dir_inode_header sinodep; + return 1; +} - if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), - &next_block, &next_offset)) - goto failed_read; - SQUASHFS_SWAP_DIR_INODE_HEADER(&inodep, &sinodep); - } else - if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), - &next_block, &next_offset)) - goto failed_read; - i->i_size = inodep.file_size; - i->i_op = &squashfs_dir_inode_ops; - i->i_fop = &squashfs_dir_ops; - i->i_mode |= S_IFDIR; - i->i_mtime = inodep.mtime; - i->i_atime = inodep.mtime; - i->i_ctime = inodep.mtime; - i->u.squashfs_i.start_block = inodep.start_block; - i->u.squashfs_i.offset = inodep.offset; - TRACE("Directory inode %x:%x, start_block %x, offset %x\n", SQUASHFS_INODE_BLK(inode), offset, - inodep.start_block, inodep.offset); - break; +static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent) +{ + struct squashfs_super_block *sblk = &msblk->sblk; + + msblk->iget = squashfs_iget; + msblk->read_blocklist = read_blocklist; + msblk->read_fragment_index_table = read_fragment_index_table; + + if (sblk->s_major == 1) { + if (!squashfs_1_0_supported(msblk)) { + SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems " + "are unsupported\n"); + SERROR("Please recompile with " + "Squashfs 1.0 support enabled\n"); + return 0; } - case SQUASHFS_SYMLINK_TYPE: { - squashfs_symlink_inode_header inodep; - - if(msBlk->swap) { - squashfs_symlink_inode_header sinodep; - - if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), - &next_block, &next_offset)) - goto failed_read; - SQUASHFS_SWAP_SYMLINK_INODE_HEADER(&inodep, &sinodep); - } else - if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), - &next_block, &next_offset)) - goto failed_read; - - i->i_size = inodep.symlink_size; - i->i_op = &page_symlink_inode_operations; - i->i_data.a_ops = &squashfs_symlink_aops; - i->i_mode |= S_IFLNK; - i->u.squashfs_i.start_block = next_block; - i->u.squashfs_i.offset = next_offset; - TRACE("Symbolic link inode %x:%x, start_block %x, offset %x\n", - SQUASHFS_INODE_BLK(inode), offset, next_block, next_offset); - break; - } - case SQUASHFS_BLKDEV_TYPE: - case SQUASHFS_CHRDEV_TYPE: { - squashfs_dev_inode_header inodep; - - if(msBlk->swap) { - squashfs_dev_inode_header sinodep; - - if(!squashfs_get_cached_block(s, (char *) &sinodep, block, offset, sizeof(sinodep), - &next_block, &next_offset)) - goto failed_read; - SQUASHFS_SWAP_DEV_INODE_HEADER(&inodep, &sinodep); - } else - if(!squashfs_get_cached_block(s, (char *) &inodep, block, offset, sizeof(inodep), - &next_block, &next_offset)) - goto failed_read; - - i->i_size = 0; - i->i_mode |= (inodeb.inode_type == SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : S_IFBLK; - init_special_inode(i, i->i_mode, inodep.rdev); - TRACE("Device inode %x:%x, rdev %x\n", SQUASHFS_INODE_BLK(inode), offset, inodep.rdev); - break; - } - case SQUASHFS_FIFO_TYPE: - case SQUASHFS_SOCKET_TYPE: { - i->i_size = 0; - i->i_mode |= (inodeb.inode_type == SQUASHFS_FIFO_TYPE) ? S_IFIFO : S_IFSOCK; - init_special_inode(i, i->i_mode, 0); - break; - } - default: - ERROR("Unknown inode type %d in squashfs_iget!\n", inodeb.inode_type); - goto failed_read1; + } else if (sblk->s_major == 2) { + if (!squashfs_2_0_supported(msblk)) { + SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems " + "are unsupported\n"); + SERROR("Please recompile with " + "Squashfs 2.0 support enabled\n"); + return 0; + } + } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor > + SQUASHFS_MINOR) { + SERROR("Major/Minor mismatch, trying to mount newer %d.%d " + "filesystem\n", sblk->s_major, sblk->s_minor); + SERROR("Please update your kernel\n"); + return 0; } - - if(inodeb.guid == SQUASHFS_GUIDS) - i->i_gid = i->i_uid; - else - i->i_gid = msBlk->guid[inodeb.guid]; - - return i; -failed_read: - ERROR("Unable to read inode [%x:%x]\n", block, offset); - -failed_read1: - return NULL; + return 1; } @@ -804,221 +968,204 @@ static struct super_block *squashfs_read_super(struct super_block *s, void *data, int silent) { kdev_t dev = s->s_dev; - squashfs_sb_info *msBlk = &s->u.squashfs_sb; - squashfs_super_block *sBlk = &msBlk->sBlk; + struct squashfs_sb_info *msblk = &s->u.squashfs_sb; + struct squashfs_super_block *sblk = &msblk->sblk; int i; - - TRACE("Entered squashfs_read_superblock\n"); - - msBlk->devblksize = get_hardsect_size(dev); - if(msBlk->devblksize < BLOCK_SIZE) - msBlk->devblksize = BLOCK_SIZE; - msBlk->devblksize_log2 = ffz(~msBlk->devblksize); - set_blocksize(dev, msBlk->devblksize); - s->s_blocksize = msBlk->devblksize; - s->s_blocksize_bits = msBlk->devblksize_log2; - - init_MUTEX(&msBlk->read_page_mutex); - init_MUTEX(&msBlk->block_cache_mutex); - init_MUTEX(&msBlk->fragment_mutex); + struct inode *root; + + msblk->devblksize = get_hardsect_size(dev); + if(msblk->devblksize < BLOCK_SIZE) + msblk->devblksize = BLOCK_SIZE; + msblk->devblksize_log2 = ffz(~msblk->devblksize); + set_blocksize(dev, msblk->devblksize); + s->s_blocksize = msblk->devblksize; + s->s_blocksize_bits = msblk->devblksize_log2; + + init_MUTEX(&msblk->read_data_mutex); + init_MUTEX(&msblk->read_page_mutex); + init_MUTEX(&msblk->block_cache_mutex); + init_MUTEX(&msblk->fragment_mutex); - init_waitqueue_head(&msBlk->waitq); - init_waitqueue_head(&msBlk->fragment_wait_queue); + init_waitqueue_head(&msblk->waitq); + init_waitqueue_head(&msblk->fragment_wait_queue); - if(!read_data(s, (char *) sBlk, SQUASHFS_START, sizeof(squashfs_super_block) | SQUASHFS_COMPRESSED_BIT, 0, NULL)) { + if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START, + sizeof(struct squashfs_super_block) | + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { SERROR("unable to read superblock\n"); goto failed_mount; } /* Check it is a SQUASHFS superblock */ - msBlk->swap = 0; - if((s->s_magic = sBlk->s_magic) != SQUASHFS_MAGIC) { - if(sBlk->s_magic == SQUASHFS_MAGIC_SWAP) { - squashfs_super_block sblk; - WARNING("Mounting a different endian SQUASHFS filesystem on %s\n", bdevname(dev)); - SQUASHFS_SWAP_SUPER_BLOCK(&sblk, sBlk); - memcpy(sBlk, &sblk, sizeof(squashfs_super_block)); - msBlk->swap = 1; + msblk->swap = 0; + if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) { + if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) { + struct squashfs_super_block ssblk; + + WARNING("Mounting a different endian SQUASHFS " + "filesystem on %s\n", bdevname(dev)); + + SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk); + memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block)); + msblk->swap = 1; } else { - SERROR("Can't find a SQUASHFS superblock on %s\n", bdevname(dev)); + SERROR("Can't find a SQUASHFS superblock on %s\n", + bdevname(dev)); goto failed_mount; } } /* Check the MAJOR & MINOR versions */ -#ifdef SQUASHFS_1_0_COMPATIBILITY - if((sBlk->s_major != 1) && (sBlk->s_major != 2 || sBlk->s_minor > SQUASHFS_MINOR)) { - SERROR("Major/Minor mismatch, filesystem is (%d:%d), I support (1 : x) or (2 : <= %d)\n", - sBlk->s_major, sBlk->s_minor, SQUASHFS_MINOR); + if(!supported_squashfs_filesystem(msblk, silent)) goto failed_mount; - } - if(sBlk->s_major == 1) - sBlk->block_size = sBlk->block_size_1; -#else - if(sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) { - SERROR("Major/Minor mismatch, filesystem is (%d:%d), I support (%d: <= %d)\n", - sBlk->s_major, sBlk->s_minor, SQUASHFS_MAJOR, SQUASHFS_MINOR); - goto failed_mount; - } -#endif TRACE("Found valid superblock on %s\n", bdevname(dev)); - TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sBlk->flags) ? "un" : ""); - TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sBlk->flags) ? "un" : ""); - TRACE("Check data is %s present in the filesystem\n", SQUASHFS_CHECK_DATA(sBlk->flags) ? "" : "not"); - TRACE("Filesystem size %d bytes\n", sBlk->bytes_used); - TRACE("Block size %d\n", sBlk->block_size); - TRACE("Number of inodes %d\n", sBlk->inodes); - if(sBlk->s_major > 1) - TRACE("Number of fragments %d\n", sBlk->fragments); - TRACE("Number of uids %d\n", sBlk->no_uids); - TRACE("Number of gids %d\n", sBlk->no_guids); - TRACE("sBlk->inode_table_start %x\n", sBlk->inode_table_start); - TRACE("sBlk->directory_table_start %x\n", sBlk->directory_table_start); - if(sBlk->s_major > 1) - TRACE("sBlk->fragment_table_start %x\n", sBlk->fragment_table_start); - TRACE("sBlk->uid_start %x\n", sBlk->uid_start); + TRACE("Inodes are %scompressed\n", + SQUASHFS_UNCOMPRESSED_INODES + (sblk->flags) ? "un" : ""); + TRACE("Data is %scompressed\n", + SQUASHFS_UNCOMPRESSED_DATA(sblk->flags) + ? "un" : ""); + TRACE("Check data is %s present in the filesystem\n", + SQUASHFS_CHECK_DATA(sblk->flags) ? + "" : "not"); + TRACE("Filesystem size %lld bytes\n", sblk->bytes_used); + TRACE("Block size %d\n", sblk->block_size); + TRACE("Number of inodes %d\n", sblk->inodes); + if (sblk->s_major > 1) + TRACE("Number of fragments %d\n", sblk->fragments); + TRACE("Number of uids %d\n", sblk->no_uids); + TRACE("Number of gids %d\n", sblk->no_guids); + TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start); + TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start); + if (sblk->s_major > 1) + TRACE("sblk->fragment_table_start %llx\n", + sblk->fragment_table_start); + TRACE("sblk->uid_start %llx\n", sblk->uid_start); s->s_flags |= MS_RDONLY; s->s_op = &squashfs_ops; /* Init inode_table block pointer array */ - if(!(msBlk->block_cache = (squashfs_cache *) kmalloc(sizeof(squashfs_cache) * SQUASHFS_CACHED_BLKS, GFP_KERNEL))) { + if (!(msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) * + SQUASHFS_CACHED_BLKS, GFP_KERNEL))) { ERROR("Failed to allocate block cache\n"); goto failed_mount; } - for(i = 0; i < SQUASHFS_CACHED_BLKS; i++) - msBlk->block_cache[i].block = SQUASHFS_INVALID_BLK; + for (i = 0; i < SQUASHFS_CACHED_BLKS; i++) + msblk->block_cache[i].block = SQUASHFS_INVALID_BLK; - msBlk->next_cache = 0; + msblk->next_cache = 0; /* Allocate read_data block */ - msBlk->read_size = (sBlk->block_size < SQUASHFS_METADATA_SIZE) ? SQUASHFS_METADATA_SIZE : sBlk->block_size; - if(!(msBlk->read_data = (char *) kmalloc(msBlk->read_size, GFP_KERNEL))) { + msblk->read_size = (sblk->block_size < SQUASHFS_METADATA_SIZE) ? + SQUASHFS_METADATA_SIZE : + sblk->block_size; + + if (!(msblk->read_data = kmalloc(msblk->read_size, GFP_KERNEL))) { ERROR("Failed to allocate read_data block\n"); - goto failed_mount1; + goto failed_mount; } /* Allocate read_page block */ - if(sBlk->block_size > PAGE_CACHE_SIZE && - !(msBlk->read_page = (char *) kmalloc(sBlk->block_size, GFP_KERNEL))) { + if (!(msblk->read_page = kmalloc(sblk->block_size, GFP_KERNEL))) { ERROR("Failed to allocate read_page block\n"); - goto failed_mount2; + goto failed_mount; } /* Allocate uid and gid tables */ - if(!(msBlk->uid = (squashfs_uid *) kmalloc((sBlk->no_uids + - sBlk->no_guids) * sizeof(squashfs_uid), GFP_KERNEL))) { + if (!(msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) * + sizeof(unsigned int), GFP_KERNEL))) { ERROR("Failed to allocate uid/gid table\n"); - goto failed_mount3; + goto failed_mount; } - msBlk->guid = msBlk->uid + sBlk->no_uids; + msblk->guid = msblk->uid + sblk->no_uids; - if(msBlk->swap) { - squashfs_uid suid[sBlk->no_uids + sBlk->no_guids]; - - if(!read_data(s, (char *) &suid, sBlk->uid_start, ((sBlk->no_uids + sBlk->no_guids) * - sizeof(squashfs_uid)) | SQUASHFS_COMPRESSED_BIT, 0, NULL)) { - SERROR("unable to read uid/gid table\n"); - goto failed_mount4; + if (msblk->swap) { + unsigned int suid[sblk->no_uids + sblk->no_guids]; + + if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start, + ((sblk->no_uids + sblk->no_guids) * + sizeof(unsigned int)) | + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { + ERROR("unable to read uid/gid table\n"); + goto failed_mount; } - SQUASHFS_SWAP_DATA(msBlk->uid, suid, (sBlk->no_uids + sBlk->no_guids), (sizeof(squashfs_uid) * 8)); + + SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids + + sblk->no_guids), (sizeof(unsigned int) * 8)); } else - if(!read_data(s, (char *) msBlk->uid, sBlk->uid_start, ((sBlk->no_uids + sBlk->no_guids) * - sizeof(squashfs_uid)) | SQUASHFS_COMPRESSED_BIT, 0, NULL)) { - SERROR("unable to read uid/gid table\n"); - goto failed_mount4; + if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start, + ((sblk->no_uids + sblk->no_guids) * + sizeof(unsigned int)) | + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { + ERROR("unable to read uid/gid table\n"); + goto failed_mount; } -#ifdef SQUASHFS_1_0_COMPATIBILITY - if(sBlk->s_major == 1) { - msBlk->iget = squashfs_iget_1; - msBlk->read_blocklist = read_blocklist_1; - msBlk->fragment = (struct squashfs_fragment_cache *) msBlk->fragment_index = NULL; + if (sblk->s_major == 1 && squashfs_1_0_supported(msblk)) goto allocate_root; - } -#endif - msBlk->iget = squashfs_iget; - msBlk->read_blocklist = read_blocklist; - if(!(msBlk->fragment = (struct squashfs_fragment_cache *) kmalloc(sizeof(struct squashfs_fragment_cache) * SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) { + if (!(msblk->fragment = kmalloc(sizeof(struct squashfs_fragment_cache) * + SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) { ERROR("Failed to allocate fragment block cache\n"); - goto failed_mount4; + goto failed_mount; } - for(i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) { - msBlk->fragment[i].locked = 0; - msBlk->fragment[i].block = SQUASHFS_INVALID_BLK; - msBlk->fragment[i].data = NULL; + for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) { + msblk->fragment[i].locked = 0; + msblk->fragment[i].block = SQUASHFS_INVALID_BLK; + msblk->fragment[i].data = NULL; } - msBlk->next_fragment = 0; + msblk->next_fragment = 0; /* Allocate fragment index table */ - if(!(msBlk->fragment_index = (squashfs_fragment_index *) kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), GFP_KERNEL))) { - ERROR("Failed to allocate uid/gid table\n"); - goto failed_mount5; - } - - if(SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments) && - !read_data(s, (char *) msBlk->fragment_index, sBlk->fragment_table_start, - SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments) | SQUASHFS_COMPRESSED_BIT, 0, NULL)) { - SERROR("unable to read fragment index table\n"); - goto failed_mount6; - } - - if(msBlk->swap) { - int i; - squashfs_fragment_index fragment; - - for(i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sBlk->fragments); i++) { - SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment), &msBlk->fragment_index[i], 1); - msBlk->fragment_index[i] = fragment; - } - } + if(msblk->read_fragment_index_table(s) == 0) + goto failed_mount; -#ifdef SQUASHFS_1_0_COMPATIBILITY allocate_root: -#endif - if(!(s->s_root = d_alloc_root((msBlk->iget)(s, sBlk->root_inode)))) { + if ((root = (msblk->iget)(s, sblk->root_inode)) == NULL) + goto failed_mount; + + if ((s->s_root = d_alloc_root(root)) == NULL) { ERROR("Root inode create failed\n"); - goto failed_mount5; + iput(root); + goto failed_mount; } TRACE("Leaving squashfs_read_super\n"); return s; -failed_mount6: - kfree(msBlk->fragment_index); -failed_mount5: - kfree(msBlk->fragment); -failed_mount4: - kfree(msBlk->uid); -failed_mount3: - kfree(msBlk->read_page); -failed_mount2: - kfree(msBlk->read_data); -failed_mount1: - kfree(msBlk->block_cache); failed_mount: + kfree(msblk->fragment_index); + kfree(msblk->fragment); + kfree(msblk->uid); + kfree(msblk->read_page); + kfree(msblk->read_data); + kfree(msblk->block_cache); + kfree(msblk->fragment_index_2); return NULL; } static int squashfs_statfs(struct super_block *s, struct statfs *buf) { - squashfs_super_block *sBlk = &s->u.squashfs_sb.sBlk; + struct squashfs_sb_info *msblk = &s->u.squashfs_sb; + struct squashfs_super_block *sblk = &msblk->sblk; TRACE("Entered squashfs_statfs\n"); + buf->f_type = SQUASHFS_MAGIC; - buf->f_bsize = sBlk->block_size; - buf->f_blocks = ((sBlk->bytes_used - 1) >> sBlk->block_log) + 1; + buf->f_bsize = sblk->block_size; + buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1; buf->f_bfree = buf->f_bavail = 0; - buf->f_files = sBlk->inodes; + buf->f_files = sblk->inodes; buf->f_ffree = 0; buf->f_namelen = SQUASHFS_NAME_LEN; + return 0; } @@ -1027,35 +1174,41 @@ static int squashfs_symlink_readpage(struct file *file, struct page *page) { struct inode *inode = page->mapping->host; int index = page->index << PAGE_CACHE_SHIFT, length, bytes; - int block = inode->u.squashfs_i.start_block; - int offset = inode->u.squashfs_i.offset; - void *pageaddr = kmap(page); - - TRACE("Entered squashfs_symlink_readpage, page index %x, start block %x, offset %x\n", - (unsigned int) page->index, inode->u.squashfs_i.start_block, inode->u.squashfs_i.offset); - - for(length = 0; length < index; length += bytes) { - if(!(bytes = squashfs_get_cached_block(inode->i_sb, NULL, block, offset, - PAGE_CACHE_SIZE, &block, &offset))) { - ERROR("Unable to read symbolic link [%x:%x]\n", block, offset); + long long block = SQUASHFS_I(inode)->start_block; + int offset = SQUASHFS_I(inode)->offset; + void *pageaddr = kmap(page); + + TRACE("Entered squashfs_symlink_readpage, page index %ld, start block " + "%llx, offset %x\n", page->index, + SQUASHFS_I(inode)->start_block, + SQUASHFS_I(inode)->offset); + + for (length = 0; length < index; length += bytes) { + if (!(bytes = squashfs_get_cached_block(inode->i_sb, NULL, + block, offset, PAGE_CACHE_SIZE, &block, + &offset))) { + ERROR("Unable to read symbolic link [%llx:%x]\n", block, + offset); goto skip_read; } } - if(length != index) { + if (length != index) { ERROR("(squashfs_symlink_readpage) length != index\n"); bytes = 0; goto skip_read; } - bytes = (inode->i_size - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : inode->i_size - length; - if(!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, offset, bytes, &block, &offset))) - ERROR("Unable to read symbolic link [%x:%x]\n", block, offset); + bytes = (i_size_read(inode) - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : + i_size_read(inode) - length; + + if (!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, + offset, bytes, &block, &offset))) + ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset); skip_read: memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); kunmap(page); - flush_dcache_page(page); SetPageUptodate(page); UnlockPage(page); @@ -1063,155 +1216,358 @@ skip_read: } -#define SIZE 256 +struct meta_index *locate_meta_index(struct inode *inode, int index, int offset) +{ + struct meta_index *meta = NULL; + struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb; + int i; + + down(&msblk->meta_index_mutex); + + TRACE("locate_meta_index: index %d, offset %d\n", index, offset); + + if(msblk->meta_index == NULL) + goto not_allocated; + + for (i = 0; i < SQUASHFS_META_NUMBER; i ++) + if (msblk->meta_index[i].inode_number == inode->i_ino && + msblk->meta_index[i].offset >= offset && + msblk->meta_index[i].offset <= index && + msblk->meta_index[i].locked == 0) { + TRACE("locate_meta_index: entry %d, offset %d\n", i, + msblk->meta_index[i].offset); + meta = &msblk->meta_index[i]; + offset = meta->offset; + } -#ifdef SQUASHFS_1_0_COMPATIBILITY -static unsigned int read_blocklist_1(struct inode *inode, int index, int readahead_blks, - char *block_list, char **block_p, unsigned int *bsize) + if (meta) + meta->locked = 1; + +not_allocated: + up(&msblk->meta_index_mutex); + + return meta; +} + + +struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip) { - squashfs_sb_info *msBlk = &inode->i_sb->u.squashfs_sb; - unsigned short *block_listp; - int i = 0; - int block_ptr = inode->u.squashfs_i.block_list_start; - int offset = inode->u.squashfs_i.offset; - int block = inode->u.squashfs_i.start_block; - - for(;;) { - int blocks = (index + readahead_blks - i); - if(blocks > (SIZE >> 1)) { - if((index - i) <= (SIZE >> 1)) - blocks = index - i; - else - blocks = SIZE >> 1; + struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb; + struct meta_index *meta = NULL; + int i; + + down(&msblk->meta_index_mutex); + + TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip); + + if(msblk->meta_index == NULL) { + if (!(msblk->meta_index = kmalloc(sizeof(struct meta_index) * + SQUASHFS_META_NUMBER, GFP_KERNEL))) { + ERROR("Failed to allocate meta_index\n"); + goto failed; } + for(i = 0; i < SQUASHFS_META_NUMBER; i++) { + msblk->meta_index[i].inode_number = 0; + msblk->meta_index[i].locked = 0; + } + msblk->next_meta_index = 0; + } - if(msBlk->swap) { - unsigned char sblock_list[SIZE]; - if(!squashfs_get_cached_block(inode->i_sb, (char *) sblock_list, block_ptr, offset, blocks << 1, &block_ptr, &offset)) { - ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset); - return 0; - } - SQUASHFS_SWAP_SHORTS(((unsigned short *)block_list), ((unsigned short *)sblock_list), blocks); - } else - if(!squashfs_get_cached_block(inode->i_sb, (char *) block_list, block_ptr, offset, blocks << 1, &block_ptr, &offset)) { - ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset); - return 0; - } - for(block_listp = (unsigned short *) block_list; i < index && blocks; i ++, block_listp ++, blocks --) - block += SQUASHFS_COMPRESSED_SIZE(*block_listp); - if(blocks >= readahead_blks) - break; + for(i = SQUASHFS_META_NUMBER; i && + msblk->meta_index[msblk->next_meta_index].locked; i --) + msblk->next_meta_index = (msblk->next_meta_index + 1) % + SQUASHFS_META_NUMBER; + + if(i == 0) { + TRACE("empty_meta_index: failed!\n"); + goto failed; } - if(bsize) - *bsize = SQUASHFS_COMPRESSED_SIZE(*block_listp) | (!SQUASHFS_COMPRESSED(*block_listp) ? SQUASHFS_COMPRESSED_BIT_BLOCK : 0); - else - (unsigned short *) *block_p = block_listp; - return block; + TRACE("empty_meta_index: returned meta entry %d, %p\n", + msblk->next_meta_index, + &msblk->meta_index[msblk->next_meta_index]); + + meta = &msblk->meta_index[msblk->next_meta_index]; + msblk->next_meta_index = (msblk->next_meta_index + 1) % + SQUASHFS_META_NUMBER; + + meta->inode_number = inode->i_ino; + meta->offset = offset; + meta->skip = skip; + meta->entries = 0; + meta->locked = 1; + +failed: + up(&msblk->meta_index_mutex); + return meta; } -#endif +void release_meta_index(struct inode *inode, struct meta_index *meta) +{ + meta->locked = 0; +} + -static unsigned int read_blocklist(struct inode *inode, int index, int readahead_blks, - char *block_list, char **block_p, unsigned int *bsize) +static int read_block_index(struct super_block *s, int blocks, char *block_list, + long long *start_block, int *offset) { - squashfs_sb_info *msBlk = &inode->i_sb->u.squashfs_sb; + struct squashfs_sb_info *msblk = &s->u.squashfs_sb; unsigned int *block_listp; - int i = 0; - int block_ptr = inode->u.squashfs_i.block_list_start; - int offset = inode->u.squashfs_i.offset; - int block = inode->u.squashfs_i.start_block; - - for(;;) { - int blocks = (index + readahead_blks - i); - if(blocks > (SIZE >> 2)) { - if((index - i) <= (SIZE >> 2)) - blocks = index - i; - else - blocks = SIZE >> 2; + int block = 0; + + if (msblk->swap) { + char sblock_list[blocks << 2]; + + if (!squashfs_get_cached_block(s, sblock_list, *start_block, + *offset, blocks << 2, start_block, offset)) { + ERROR("Unable to read block list [%llx:%x]\n", + *start_block, *offset); + goto failure; + } + SQUASHFS_SWAP_INTS(((unsigned int *)block_list), + ((unsigned int *)sblock_list), blocks); + } else + if (!squashfs_get_cached_block(s, block_list, *start_block, + *offset, blocks << 2, start_block, offset)) { + ERROR("Unable to read block list [%llx:%x]\n", + *start_block, *offset); + goto failure; } - if(msBlk->swap) { - unsigned char sblock_list[SIZE]; - if(!squashfs_get_cached_block(inode->i_sb, (char *) sblock_list, block_ptr, offset, blocks << 2, &block_ptr, &offset)) { - ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset); - return 0; - } - SQUASHFS_SWAP_INTS(((unsigned int *)block_list), ((unsigned int *)sblock_list), blocks); - } else - if(!squashfs_get_cached_block(inode->i_sb, (char *) block_list, block_ptr, offset, blocks << 2, &block_ptr, &offset)) { - ERROR("Unable to read block list [%d:%x]\n", block_ptr, offset); - return 0; + for (block_listp = (unsigned int *) block_list; blocks; + block_listp++, blocks --) + block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp); + + return block; + +failure: + return -1; +} + + +#define SIZE 256 + +static inline int calculate_skip(int blocks) { + int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES); + return skip >= 7 ? 7 : skip + 1; +} + + +static int get_meta_index(struct inode *inode, int index, + long long *index_block, int *index_offset, + long long *data_block, char *block_list) +{ + struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb; + struct squashfs_super_block *sblk = &msblk->sblk; + int skip = calculate_skip(i_size_read(inode) >> sblk->block_log); + int offset = 0; + struct meta_index *meta; + struct meta_entry *meta_entry; + long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start; + int cur_offset = SQUASHFS_I(inode)->offset; + long long cur_data_block = SQUASHFS_I(inode)->start_block; + int i; + + index /= SQUASHFS_META_INDEXES * skip; + + while ( offset < index ) { + meta = locate_meta_index(inode, index, offset + 1); + + if (meta == NULL) { + if ((meta = empty_meta_index(inode, offset + 1, + skip)) == NULL) + goto all_done; + } else { + offset = index < meta->offset + meta->entries ? index : + meta->offset + meta->entries - 1; + meta_entry = &meta->meta_entry[offset - meta->offset]; + cur_index_block = meta_entry->index_block + sblk->inode_table_start; + cur_offset = meta_entry->offset; + cur_data_block = meta_entry->data_block; + TRACE("get_meta_index: offset %d, meta->offset %d, " + "meta->entries %d\n", offset, meta->offset, + meta->entries); + TRACE("get_meta_index: index_block 0x%llx, offset 0x%x" + " data_block 0x%llx\n", cur_index_block, + cur_offset, cur_data_block); + } + + for (i = meta->offset + meta->entries; i <= index && + i < meta->offset + SQUASHFS_META_ENTRIES; i++) { + int blocks = skip * SQUASHFS_META_INDEXES; + + while (blocks) { + int block = blocks > (SIZE >> 2) ? (SIZE >> 2) : + blocks; + int res = read_block_index(inode->i_sb, block, + block_list, &cur_index_block, + &cur_offset); + + if (res == -1) + goto failed; + + cur_data_block += res; + blocks -= block; } - for(block_listp = (unsigned int *) block_list; i < index && blocks; i ++, block_listp ++, blocks --) - block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp); - if(blocks >= readahead_blks) - break; + + meta_entry = &meta->meta_entry[i - meta->offset]; + meta_entry->index_block = cur_index_block - sblk->inode_table_start; + meta_entry->offset = cur_offset; + meta_entry->data_block = cur_data_block; + meta->entries ++; + offset ++; + } + + TRACE("get_meta_index: meta->offset %d, meta->entries %d\n", + meta->offset, meta->entries); + + release_meta_index(inode, meta); } - *bsize = *block_listp; +all_done: + *index_block = cur_index_block; + *index_offset = cur_offset; + *data_block = cur_data_block; + + return offset * SQUASHFS_META_INDEXES * skip; + +failed: + release_meta_index(inode, meta); + return -1; +} + + +static long long read_blocklist(struct inode *inode, int index, + int readahead_blks, char *block_list, + unsigned short **block_p, unsigned int *bsize) +{ + long long block_ptr; + int offset; + long long block; + int res = get_meta_index(inode, index, &block_ptr, &offset, &block, + block_list); + + TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset" + " 0x%x, block 0x%llx\n", res, index, block_ptr, offset, + block); + + if(res == -1) + goto failure; + + index -= res; + + while ( index ) { + int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index; + int res = read_block_index(inode->i_sb, blocks, block_list, + &block_ptr, &offset); + if (res == -1) + goto failure; + block += res; + index -= blocks; + } + + if (read_block_index(inode->i_sb, 1, block_list, + &block_ptr, &offset) == -1) + goto failure; + *bsize = *((unsigned int *) block_list); + return block; + +failure: + return 0; } static int squashfs_readpage(struct file *file, struct page *page) { struct inode *inode = page->mapping->host; - squashfs_sb_info *msBlk = &inode->i_sb->u.squashfs_sb; - squashfs_super_block *sBlk = &msBlk->sBlk; + struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb; + struct squashfs_super_block *sblk = &msblk->sblk; unsigned char block_list[SIZE]; - unsigned int bsize, block, i = 0, bytes = 0, byte_offset = 0; - int index = page->index >> (sBlk->block_log - PAGE_CACHE_SHIFT); - void *pageaddr = kmap(page); - struct squashfs_fragment_cache *fragment; - char *data_ptr = msBlk->read_page; + long long block; + unsigned int bsize, i = 0, bytes = 0, byte_offset = 0; + int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT); + void *pageaddr; + struct squashfs_fragment_cache *fragment = NULL; + char *data_ptr = msblk->read_page; - int mask = (1 << (sBlk->block_log - PAGE_CACHE_SHIFT)) - 1; + int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1; int start_index = page->index & ~mask; int end_index = start_index | mask; - TRACE("Entered squashfs_readpage, page index %x, start block %x\n", (unsigned int) page->index, - inode->u.squashfs_i.start_block); + TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n", + page->index, + SQUASHFS_I(inode)->start_block); - if(inode->u.squashfs_i.fragment_start_block == SQUASHFS_INVALID_BLK || index < (inode->i_size >> sBlk->block_log)) { - if((block = (msBlk->read_blocklist)(inode, index, 1, block_list, NULL, &bsize)) == 0) + if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> + PAGE_CACHE_SHIFT)) + goto skip_read; + + if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK + || index < (i_size_read(inode) >> + sblk->block_log)) { + if ((block = (msblk->read_blocklist)(inode, index, 1, + block_list, NULL, &bsize)) == 0) goto skip_read; - down(&msBlk->read_page_mutex); - if(!(bytes = read_data(inode->i_sb, msBlk->read_page, block, bsize, 1, NULL))) { - ERROR("Unable to read page, block %x, size %x\n", block, bsize); - up(&msBlk->read_page_mutex); + down(&msblk->read_page_mutex); + + if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page, + block, bsize, NULL))) { + ERROR("Unable to read page, block %llx, size %x\n", block, + bsize); + up(&msblk->read_page_mutex); goto skip_read; } } else { - if((fragment = get_cached_fragment(inode->i_sb, inode->u.squashfs_i.fragment_start_block, inode->u.squashfs_i.fragment_size)) == NULL) { - ERROR("Unable to read page, block %x, size %x\n", inode->u.squashfs_i.fragment_start_block, (int) inode->u.squashfs_i.fragment_size); + if ((fragment = get_cached_fragment(inode->i_sb, + SQUASHFS_I(inode)-> + u.s1.fragment_start_block, + SQUASHFS_I(inode)->u.s1.fragment_size)) + == NULL) { + ERROR("Unable to read page, block %llx, size %x\n", + SQUASHFS_I(inode)-> + u.s1.fragment_start_block, + (int) SQUASHFS_I(inode)-> + u.s1.fragment_size); goto skip_read; } - bytes = inode->u.squashfs_i.fragment_offset + (inode->i_size & (sBlk->block_size - 1)); - byte_offset = inode->u.squashfs_i.fragment_offset; + bytes = SQUASHFS_I(inode)->u.s1.fragment_offset + + (i_size_read(inode) & (sblk->block_size + - 1)); + byte_offset = SQUASHFS_I(inode)->u.s1.fragment_offset; data_ptr = fragment->data; } - for(i = start_index; i <= end_index && byte_offset < bytes; i++, byte_offset += PAGE_CACHE_SIZE) { + for (i = start_index; i <= end_index && byte_offset < bytes; + i++, byte_offset += PAGE_CACHE_SIZE) { struct page *push_page; - int available_bytes = (bytes - byte_offset) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : bytes - byte_offset; - - TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n", bytes, i, byte_offset, available_bytes); - - if(i == page->index) { - memcpy(pageaddr, data_ptr + byte_offset, available_bytes); - memset(pageaddr + available_bytes, 0, PAGE_CACHE_SIZE - available_bytes); - kunmap(page); + int available_bytes = (bytes - byte_offset) > PAGE_CACHE_SIZE ? + PAGE_CACHE_SIZE : bytes - byte_offset; + + TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n", + bytes, i, byte_offset, available_bytes); + + if (i == page->index) { + pageaddr = kmap_atomic(page, KM_USER0); + memcpy(pageaddr, data_ptr + byte_offset, + available_bytes); + memset(pageaddr + available_bytes, 0, + PAGE_CACHE_SIZE - available_bytes); + kunmap_atomic(pageaddr, KM_USER0); flush_dcache_page(page); SetPageUptodate(page); UnlockPage(page); - } else if((push_page = grab_cache_page_nowait(page->mapping, i))) { - void *pageaddr = kmap(push_page); - memcpy(pageaddr, data_ptr + byte_offset, available_bytes); - memset(pageaddr + available_bytes, 0, PAGE_CACHE_SIZE - available_bytes); - kunmap(push_page); + } else if ((push_page = + grab_cache_page_nowait(page->mapping, i))) { + pageaddr = kmap_atomic(push_page, KM_USER0); + + memcpy(pageaddr, data_ptr + byte_offset, + available_bytes); + memset(pageaddr + available_bytes, 0, + PAGE_CACHE_SIZE - available_bytes); + kunmap_atomic(pageaddr, KM_USER0); flush_dcache_page(push_page); SetPageUptodate(push_page); UnlockPage(push_page); @@ -1219,16 +1575,19 @@ static int squashfs_readpage(struct file *file, struct page *page) } } - if(inode->u.squashfs_i.fragment_start_block == SQUASHFS_INVALID_BLK || index < (inode->i_size >> sBlk->block_log)) - up(&msBlk->read_page_mutex); + if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK + || index < (i_size_read(inode) >> + sblk->block_log)) + up(&msblk->read_page_mutex); else - release_cached_fragment(msBlk, fragment); + release_cached_fragment(msblk, fragment); return 0; skip_read: + pageaddr = kmap_atomic(page, KM_USER0); memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); - kunmap(page); + kunmap_atomic(pageaddr, KM_USER0); flush_dcache_page(page); SetPageUptodate(page); UnlockPage(page); @@ -1240,34 +1599,61 @@ skip_read: static int squashfs_readpage4K(struct file *file, struct page *page) { struct inode *inode = page->mapping->host; - squashfs_sb_info *msBlk = &inode->i_sb->u.squashfs_sb; - squashfs_super_block *sBlk = &msBlk->sBlk; + struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb; + struct squashfs_super_block *sblk = &msblk->sblk; unsigned char block_list[SIZE]; - unsigned int bsize, block, bytes = 0; - void *pageaddr = kmap(page); + long long block; + unsigned int bsize, bytes = 0; + void *pageaddr; - TRACE("Entered squashfs_readpage4K, page index %x, start block %x\n", (unsigned int) page->index, - inode->u.squashfs_i.start_block); + TRACE("Entered squashfs_readpage4K, page index %lx, start block %llx\n", + page->index, + SQUASHFS_I(inode)->start_block); - if(page->index < (inode->i_size >> sBlk->block_log)) { - block = (msBlk->read_blocklist)(inode, page->index, 1, block_list, NULL, &bsize); + if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> + PAGE_CACHE_SHIFT)) { + pageaddr = kmap_atomic(page, KM_USER0); + goto skip_read; + } - if(!(bytes = read_data(inode->i_sb, pageaddr, block, bsize, 1, NULL))) - ERROR("Unable to read page, block %x, size %x\n", block, bsize); + if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK + || page->index < (i_size_read(inode) >> + sblk->block_log)) { + block = (msblk->read_blocklist)(inode, page->index, 1, + block_list, NULL, &bsize); + + down(&msblk->read_page_mutex); + bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block, + bsize, NULL); + pageaddr = kmap_atomic(page, KM_USER0); + if (bytes) + memcpy(pageaddr, msblk->read_page, bytes); + else + ERROR("Unable to read page, block %llx, size %x\n", + block, bsize); + up(&msblk->read_page_mutex); } else { - struct squashfs_fragment_cache *fragment; - - if((fragment = get_cached_fragment(inode->i_sb, inode->u.squashfs_i.fragment_start_block, inode->u.squashfs_i.fragment_size)) == NULL) - ERROR("Unable to read page, block %x, size %x\n", inode->u.squashfs_i.fragment_start_block, (int) inode->u.squashfs_i.fragment_size); - else { - bytes = inode->i_size & (sBlk->block_size - 1); - memcpy(pageaddr, fragment->data + inode->u.squashfs_i.fragment_offset, bytes); - release_cached_fragment(msBlk, fragment); - } + struct squashfs_fragment_cache *fragment = + get_cached_fragment(inode->i_sb, + SQUASHFS_I(inode)-> + u.s1.fragment_start_block, + SQUASHFS_I(inode)-> u.s1.fragment_size); + pageaddr = kmap_atomic(page, KM_USER0); + if (fragment) { + bytes = i_size_read(inode) & (sblk->block_size - 1); + memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)-> + u.s1.fragment_offset, bytes); + release_cached_fragment(msblk, fragment); + } else + ERROR("Unable to read page, block %llx, size %x\n", + SQUASHFS_I(inode)-> + u.s1.fragment_start_block, (int) + SQUASHFS_I(inode)-> u.s1.fragment_size); } +skip_read: memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); - kunmap(page); + kunmap_atomic(pageaddr, KM_USER0); flush_dcache_page(page); SetPageUptodate(page); UnlockPage(page); @@ -1276,191 +1662,331 @@ static int squashfs_readpage4K(struct file *file, struct page *page) } -#ifdef SQUASHFS_1_0_COMPATIBILITY -static int squashfs_readpage_lessthan4K(struct file *file, struct page *page) +static int get_dir_index_using_offset(struct super_block *s, long long + *next_block, unsigned int *next_offset, + long long index_start, + unsigned int index_offset, int i_count, + long long f_pos) { - struct inode *inode = page->mapping->host; - squashfs_sb_info *msBlk = &inode->i_sb->u.squashfs_sb; - squashfs_super_block *sBlk = &msBlk->sBlk; - unsigned char block_list[SIZE]; - unsigned short *block_listp, block, bytes = 0; - int index = page->index << (PAGE_CACHE_SHIFT - sBlk->block_log); - int file_blocks = ((inode->i_size - 1) >> sBlk->block_log) + 1; - int readahead_blks = 1 << (PAGE_CACHE_SHIFT - sBlk->block_log); - void *pageaddr = kmap(page); - - int i_end = index + (1 << (PAGE_CACHE_SHIFT - sBlk->block_log)); - int byte; - - TRACE("Entered squashfs_readpage_lessthan4K, page index %x, start block %x\n", (unsigned int) page->index, - inode->u.squashfs_i.start_block); + struct squashfs_sb_info *msblk = &s->u.squashfs_sb; + struct squashfs_super_block *sblk = &msblk->sblk; + int i, length = 0; + struct squashfs_dir_index index; + + TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n", + i_count, (unsigned int) f_pos); + + f_pos -= 3; + if (f_pos == 0) + goto finish; + + for (i = 0; i < i_count; i++) { + if (msblk->swap) { + struct squashfs_dir_index sindex; + squashfs_get_cached_block(s, (char *) &sindex, + index_start, index_offset, + sizeof(sindex), &index_start, + &index_offset); + SQUASHFS_SWAP_DIR_INDEX(&index, &sindex); + } else + squashfs_get_cached_block(s, (char *) &index, + index_start, index_offset, + sizeof(index), &index_start, + &index_offset); - block = read_blocklist_1(inode, index, readahead_blks, block_list, (char **) &block_listp, NULL); + if (index.index > f_pos) + break; - if(i_end > file_blocks) - i_end = file_blocks; + squashfs_get_cached_block(s, NULL, index_start, index_offset, + index.size + 1, &index_start, + &index_offset); - while(index < i_end) { - if(!(byte = read_data(inode->i_sb, pageaddr, block, *block_listp, 0, NULL))) { - ERROR("Unable to read page, block %x, size %x\n", block, *block_listp); - goto skip_read; - } - block += SQUASHFS_COMPRESSED_SIZE(*block_listp); - pageaddr += byte; - bytes += byte; - index ++; - block_listp ++; + length = index.index; + *next_block = index.start_block + sblk->directory_table_start; } -skip_read: - memset(pageaddr, 0, PAGE_CACHE_SIZE - bytes); - kunmap(page); - flush_dcache_page(page); - SetPageUptodate(page); - UnlockPage(page); + *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; - return 0; +finish: + return length + 3; } -#endif +static int get_dir_index_using_name(struct super_block *s, long long + *next_block, unsigned int *next_offset, + long long index_start, + unsigned int index_offset, int i_count, + const char *name, int size) +{ + struct squashfs_sb_info *msblk = &s->u.squashfs_sb; + struct squashfs_super_block *sblk = &msblk->sblk; + int i, length = 0; + char buffer[sizeof(struct squashfs_dir_index) + SQUASHFS_NAME_LEN + 1]; + struct squashfs_dir_index *index = (struct squashfs_dir_index *) buffer; + char str[SQUASHFS_NAME_LEN + 1]; + + TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count); + + strncpy(str, name, size); + str[size] = '\0'; + + for (i = 0; i < i_count; i++) { + if (msblk->swap) { + struct squashfs_dir_index sindex; + squashfs_get_cached_block(s, (char *) &sindex, + index_start, index_offset, + sizeof(sindex), &index_start, + &index_offset); + SQUASHFS_SWAP_DIR_INDEX(index, &sindex); + } else + squashfs_get_cached_block(s, (char *) index, + index_start, index_offset, + sizeof(struct squashfs_dir_index), + &index_start, &index_offset); + + squashfs_get_cached_block(s, index->name, index_start, + index_offset, index->size + 1, + &index_start, &index_offset); + + index->name[index->size + 1] = '\0'; + + if (strcmp(index->name, str) > 0) + break; + + length = index->index; + *next_block = index->start_block + sblk->directory_table_start; + } + + *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; + return length + 3; +} + + static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir) { struct inode *i = file->f_dentry->d_inode; - squashfs_sb_info *msBlk = &i->i_sb->u.squashfs_sb; - squashfs_super_block *sBlk = &msBlk->sBlk; - int next_block = i->u.squashfs_i.start_block + sBlk->directory_table_start, next_offset = - i->u.squashfs_i.offset, length = 0, dirs_read = 0, dir_count; - squashfs_dir_header dirh; - char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1]; - squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer; + struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb; + struct squashfs_super_block *sblk = &msblk->sblk; + long long next_block = SQUASHFS_I(i)->start_block + + sblk->directory_table_start; + int next_offset = SQUASHFS_I(i)->offset, length = 0, dirs_read = 0, + dir_count; + struct squashfs_dir_header dirh; + char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1]; + struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer; + + TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset); + + while(file->f_pos < 3) { + char *name; + int size, i_ino; + + if(file->f_pos == 0) { + name = "."; + size = 1; + i_ino = i->i_ino; + } else { + name = ".."; + size = 2; + i_ino = SQUASHFS_I(i)->u.s2.parent_inode; + } + TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n", + (unsigned int) dirent, name, size, (int) + file->f_pos, i_ino, + squashfs_filetype_table[1]); + + if (filldir(dirent, name, size, + file->f_pos, i_ino, + squashfs_filetype_table[1]) < 0) { + TRACE("Filldir returned less than 0\n"); + goto finish; + } + file->f_pos += size; + dirs_read++; + } - TRACE("Entered squashfs_readdir [%x:%x]\n", next_block, next_offset); + length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset, + SQUASHFS_I(i)->u.s2.directory_index_start, + SQUASHFS_I(i)->u.s2.directory_index_offset, + SQUASHFS_I(i)->u.s2.directory_index_count, + file->f_pos); - while(length < i->i_size) { + while (length < i_size_read(i)) { /* read directory header */ - if(msBlk->swap) { - squashfs_dir_header sdirh; - if(!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, next_block, - next_offset, sizeof(sdirh), &next_block, &next_offset)) + if (msblk->swap) { + struct squashfs_dir_header sdirh; + + if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, + next_block, next_offset, sizeof(sdirh), + &next_block, &next_offset)) goto failed_read; + length += sizeof(sdirh); SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); } else { - if(!squashfs_get_cached_block(i->i_sb, (char *) &dirh, next_block, - next_offset, sizeof(dirh), &next_block, &next_offset)) + if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, + next_block, next_offset, sizeof(dirh), + &next_block, &next_offset)) goto failed_read; + length += sizeof(dirh); } dir_count = dirh.count + 1; - while(dir_count--) { - if(msBlk->swap) { - squashfs_dir_entry sdire; - if(!squashfs_get_cached_block(i->i_sb, (char *) &sdire, next_block, - next_offset, sizeof(sdire), &next_block, &next_offset)) + while (dir_count--) { + if (msblk->swap) { + struct squashfs_dir_entry sdire; + if (!squashfs_get_cached_block(i->i_sb, (char *) + &sdire, next_block, next_offset, + sizeof(sdire), &next_block, + &next_offset)) goto failed_read; + length += sizeof(sdire); SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); } else { - if(!squashfs_get_cached_block(i->i_sb, (char *) dire, next_block, - next_offset, sizeof(*dire), &next_block, &next_offset)) + if (!squashfs_get_cached_block(i->i_sb, (char *) + dire, next_block, next_offset, + sizeof(*dire), &next_block, + &next_offset)) goto failed_read; + length += sizeof(*dire); } - if(!squashfs_get_cached_block(i->i_sb, dire->name, next_block, - next_offset, dire->size + 1, &next_block, &next_offset)) + if (!squashfs_get_cached_block(i->i_sb, dire->name, + next_block, next_offset, + dire->size + 1, &next_block, + &next_offset)) goto failed_read; + length += dire->size + 1; - if(file->f_pos >= length) + if (file->f_pos >= length) continue; dire->name[dire->size + 1] = '\0'; - TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n", (unsigned int) dirent, - dire->name, dire->size + 1, (int) file->f_pos, - dirh.start_block, dire->offset, squashfs_filetype_table[dire->type]); - - if(filldir(dirent, dire->name, dire->size + 1, file->f_pos, SQUASHFS_MK_VFS_INODE(dirh.start_block, - dire->offset), squashfs_filetype_table[dire->type]) < 0) { + TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n", + (unsigned int) dirent, dire->name, + dire->size + 1, (int) file->f_pos, + dirh.start_block, dire->offset, + dirh.inode_number + dire->inode_number, + squashfs_filetype_table[dire->type]); + + if (filldir(dirent, dire->name, dire->size + 1, + file->f_pos, + dirh.inode_number + dire->inode_number, + squashfs_filetype_table[dire->type]) + < 0) { TRACE("Filldir returned less than 0\n"); - return dirs_read; + goto finish; } - file->f_pos = length; - dirs_read ++; + dirs_read++; } } +finish: return dirs_read; failed_read: - ERROR("Unable to read directory block [%x:%x]\n", next_block, next_offset); + ERROR("Unable to read directory block [%llx:%x]\n", next_block, + next_offset); return 0; } static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry) { - const char *name =dentry->d_name.name; + const unsigned char *name = dentry->d_name.name; int len = dentry->d_name.len; struct inode *inode = NULL; - squashfs_sb_info *msBlk = &i->i_sb->u.squashfs_sb; - squashfs_super_block *sBlk = &msBlk->sBlk; - int next_block = i->u.squashfs_i.start_block + sBlk->directory_table_start, next_offset = - i->u.squashfs_i.offset, length = 0, dir_count; - squashfs_dir_header dirh; - char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN]; - squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer; - - TRACE("Entered squashfs_lookup [%x:%x]\n", next_block, next_offset); - - while(length < i->i_size) { + struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb; + struct squashfs_super_block *sblk = &msblk->sblk; + long long next_block = SQUASHFS_I(i)->start_block + + sblk->directory_table_start; + int next_offset = SQUASHFS_I(i)->offset, length = 0, + dir_count; + struct squashfs_dir_header dirh; + char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN]; + struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer; + + TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset); + + if (len > SQUASHFS_NAME_LEN) + goto exit_loop; + + length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset, + SQUASHFS_I(i)->u.s2.directory_index_start, + SQUASHFS_I(i)->u.s2.directory_index_offset, + SQUASHFS_I(i)->u.s2.directory_index_count, name, + len); + + while (length < i_size_read(i)) { /* read directory header */ - if(msBlk->swap) { - squashfs_dir_header sdirh; - if(!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, next_block, next_offset, - sizeof(sdirh), &next_block, &next_offset)) + if (msblk->swap) { + struct squashfs_dir_header sdirh; + if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, + next_block, next_offset, sizeof(sdirh), + &next_block, &next_offset)) goto failed_read; + length += sizeof(sdirh); SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); } else { - if(!squashfs_get_cached_block(i->i_sb, (char *) &dirh, next_block, next_offset, - sizeof(dirh), &next_block, &next_offset)) + if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, + next_block, next_offset, sizeof(dirh), + &next_block, &next_offset)) goto failed_read; + length += sizeof(dirh); } dir_count = dirh.count + 1; - while(dir_count--) { - if(msBlk->swap) { - squashfs_dir_entry sdire; - if(!squashfs_get_cached_block(i->i_sb, (char *) &sdire, - next_block,next_offset, sizeof(sdire), &next_block, &next_offset)) + while (dir_count--) { + if (msblk->swap) { + struct squashfs_dir_entry sdire; + if (!squashfs_get_cached_block(i->i_sb, (char *) + &sdire, next_block,next_offset, + sizeof(sdire), &next_block, + &next_offset)) goto failed_read; + length += sizeof(sdire); SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); } else { - if(!squashfs_get_cached_block(i->i_sb, (char *) dire, - next_block,next_offset, sizeof(*dire), &next_block, &next_offset)) + if (!squashfs_get_cached_block(i->i_sb, (char *) + dire, next_block,next_offset, + sizeof(*dire), &next_block, + &next_offset)) goto failed_read; + length += sizeof(*dire); } - if(!squashfs_get_cached_block(i->i_sb, dire->name, - next_block, next_offset, dire->size + 1, &next_block, &next_offset)) + if (!squashfs_get_cached_block(i->i_sb, dire->name, + next_block, next_offset, dire->size + 1, + &next_block, &next_offset)) goto failed_read; + length += dire->size + 1; - if((len == dire->size + 1) && !strncmp(name, dire->name, len)) { - squashfs_inode ino = SQUASHFS_MKINODE(dirh.start_block, dire->offset); + if (name[0] < dire->name[0]) + goto exit_loop; + + if ((len == dire->size + 1) && !strncmp(name, + dire->name, len)) { + squashfs_inode_t ino = + SQUASHFS_MKINODE(dirh.start_block, + dire->offset); - TRACE("calling squashfs_iget for directory entry %s, inode %x:%x\n", - name, dirh.start_block, dire->offset); + TRACE("calling squashfs_iget for directory " + "entry %s, inode %x:%x, %d\n", name, + dirh.start_block, dire->offset, + dirh.inode_number + dire->inode_number); - inode = (msBlk->iget)(i->i_sb, ino); + inode = (msblk->iget)(i->i_sb, ino); goto exit_loop; } @@ -1472,36 +1998,63 @@ exit_loop: return ERR_PTR(0); failed_read: - ERROR("Unable to read directory block [%x:%x]\n", next_block, next_offset); + ERROR("Unable to read directory block [%llx:%x]\n", next_block, + next_offset); goto exit_loop; } static void squashfs_put_super(struct super_block *s) { - if(s->u.squashfs_sb.block_cache) kfree(s->u.squashfs_sb.block_cache); - if(s->u.squashfs_sb.read_data) kfree(s->u.squashfs_sb.read_data); - if(s->u.squashfs_sb.read_page) kfree(s->u.squashfs_sb.read_page); - if(s->u.squashfs_sb.uid) kfree(s->u.squashfs_sb.uid); - s->u.squashfs_sb.block_cache = (void *) s->u.squashfs_sb.uid = - s->u.squashfs_sb.read_data = s->u.squashfs_sb.read_page = NULL; + int i; + + struct squashfs_sb_info *sbi = &s->u.squashfs_sb; + if (sbi->block_cache) + for (i = 0; i < SQUASHFS_CACHED_BLKS; i++) + if (sbi->block_cache[i].block != + SQUASHFS_INVALID_BLK) + kfree(sbi->block_cache[i].data); + if (sbi->fragment) + for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) + SQUASHFS_FREE(sbi->fragment[i].data); + kfree(sbi->fragment); + kfree(sbi->block_cache); + kfree(sbi->read_data); + kfree(sbi->read_page); + kfree(sbi->uid); + kfree(sbi->fragment_index); + kfree(sbi->fragment_index_2); + sbi->block_cache = NULL; + sbi->uid = NULL; + sbi->read_data = NULL; + sbi->read_page = NULL; + sbi->fragment = NULL; + sbi->fragment_index = NULL; + sbi->fragment_index_2 = NULL; } static int __init init_squashfs_fs(void) { - if(!(stream.workspace = (char *) vmalloc(zlib_inflate_workspacesize()))) { + printk(KERN_INFO "squashfs: version 3.0 (2006/03/15) " + "Phillip Lougher\n"); + +#ifndef SQUASHFS_LZMA + if (!(stream.workspace = vmalloc(zlib_inflate_workspacesize()))) { ERROR("Failed to allocate zlib workspace\n"); return -ENOMEM; } +#endif return register_filesystem(&squashfs_fs_type); } static void __exit exit_squashfs_fs(void) { +#ifndef SQUASHFS_LZMA vfree(stream.workspace); +#endif unregister_filesystem(&squashfs_fs_type); } @@ -1511,5 +2064,5 @@ EXPORT_NO_SYMBOLS; module_init(init_squashfs_fs); module_exit(exit_squashfs_fs); MODULE_DESCRIPTION("squashfs, a compressed read-only filesystem"); -MODULE_AUTHOR("Phillip Lougher <plougher@users.sourceforge.net>"); +MODULE_AUTHOR("Phillip Lougher <phillip@lougher.org.uk>"); MODULE_LICENSE("GPL"); diff --git a/release/src/linux/linux/fs/squashfs/squashfs.h b/release/src/linux/linux/fs/squashfs/squashfs.h new file mode 100644 index 00000000..e53ceeff --- /dev/null +++ b/release/src/linux/linux/fs/squashfs/squashfs.h @@ -0,0 +1,85 @@ +/* + * Squashfs - a compressed read only filesystem for Linux + * + * Copyright (c) 2002, 2003, 2004, 2005, 2006 + * Phillip Lougher <phillip@lougher.org.uk> + * + * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * squashfs.h + */ + +#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY +#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY +#endif +#ifdef SQUASHFS_TRACE +#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args) +#else +#define TRACE(s, args...) {} +#endif + +#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args) + +#define SERROR(s, args...) do { \ + if (!silent) \ + printk(KERN_ERR "SQUASHFS error: "s, ## args);\ + } while(0) + +#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args) + +#define SQUASHFS_I(INO) (&INO->u.squashfs_i) + +#define i_size_read(INO) (INO->i_size) + +#if defined(CONFIG_SQUASHFS_1_0_COMPATIBILITY ) || defined(CONFIG_SQUASHFS_2_0_COMPATIBILITY) +#define SQSH_EXTERN +extern unsigned int squashfs_read_data(struct super_block *s, char *buffer, + long long index, unsigned int length, + long long *next_index); +extern int squashfs_get_cached_block(struct super_block *s, char *buffer, + long long block, unsigned int offset, + int length, long long *next_block, + unsigned int *next_offset); +extern void release_cached_fragment(struct squashfs_sb_info *msblk, struct + squashfs_fragment_cache *fragment); +extern struct squashfs_fragment_cache *get_cached_fragment(struct super_block + *s, long long start_block, + int length); +extern struct address_space_operations squashfs_symlink_aops; +extern struct address_space_operations squashfs_aops; +extern struct address_space_operations squashfs_aops_4K; +extern struct file_operations squashfs_dir_ops; +extern struct inode_operations squashfs_dir_inode_ops; +#else +#define SQSH_EXTERN static +#endif + +#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY +extern int squashfs_1_0_supported(struct squashfs_sb_info *msblk); +#else +static inline int squashfs_1_0_supported(struct squashfs_sb_info *msblk) +{ + return 0; +} +#endif + +#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY +extern int squashfs_2_0_supported(struct squashfs_sb_info *msblk); +#else +static inline int squashfs_2_0_supported(struct squashfs_sb_info *msblk) +{ + return 0; +} +#endif diff --git a/release/src/linux/linux/fs/squashfs/squashfs2_0.c b/release/src/linux/linux/fs/squashfs/squashfs2_0.c new file mode 100644 index 00000000..d4efd8a9 --- /dev/null +++ b/release/src/linux/linux/fs/squashfs/squashfs2_0.c @@ -0,0 +1,751 @@ +/* + * Squashfs - a compressed read only filesystem for Linux + * + * Copyright (c) 2002, 2003, 2004, 2005, 2006 + * Phillip Lougher <phillip@lougher.org.uk> + * + * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * squashfs2_0.c + */ + +#include <linux/types.h> +#include <linux/squashfs_fs.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/fs.h> +#include <linux/smp_lock.h> +#include <linux/locks.h> +#include <linux/init.h> +#include <linux/dcache.h> +#include <linux/wait.h> +#include <linux/zlib.h> +#include <linux/blkdev.h> +#include <linux/vmalloc.h> +#include <asm/uaccess.h> +#include <asm/semaphore.h> +#include "squashfs.h" + +static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir); +static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry); + +static struct file_operations squashfs_dir_ops_2 = { + .read = generic_read_dir, + .readdir = squashfs_readdir_2 +}; + +static struct inode_operations squashfs_dir_inode_ops_2 = { + .lookup = squashfs_lookup_2 +}; + +static unsigned char squashfs_filetype_table[] = { + DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK +}; + +static int read_fragment_index_table_2(struct super_block *s) +{ + struct squashfs_sb_info *msblk = &s->u.squashfs_sb; + struct squashfs_super_block *sblk = &msblk->sblk; + + if (!(msblk->fragment_index_2 = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES_2 + (sblk->fragments), GFP_KERNEL))) { + ERROR("Failed to allocate uid/gid table\n"); + return 0; + } + + if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) && + !squashfs_read_data(s, (char *) + msblk->fragment_index_2, + sblk->fragment_table_start, + SQUASHFS_FRAGMENT_INDEX_BYTES_2 + (sblk->fragments) | + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { + ERROR("unable to read fragment index table\n"); + return 0; + } + + if (msblk->swap) { + int i; + unsigned int fragment; + + for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES_2(sblk->fragments); + i++) { + SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment), + &msblk->fragment_index_2[i], 1); + msblk->fragment_index_2[i] = fragment; + } + } + + return 1; +} + + +static int get_fragment_location_2(struct super_block *s, unsigned int fragment, + long long *fragment_start_block, + unsigned int *fragment_size) +{ + struct squashfs_sb_info *msblk = &s->u.squashfs_sb; + long long start_block = + msblk->fragment_index_2[SQUASHFS_FRAGMENT_INDEX_2(fragment)]; + int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET_2(fragment); + struct squashfs_fragment_entry_2 fragment_entry; + + if (msblk->swap) { + struct squashfs_fragment_entry_2 sfragment_entry; + + if (!squashfs_get_cached_block(s, (char *) &sfragment_entry, + start_block, offset, + sizeof(sfragment_entry), &start_block, + &offset)) + goto out; + SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry, &sfragment_entry); + } else + if (!squashfs_get_cached_block(s, (char *) &fragment_entry, + start_block, offset, + sizeof(fragment_entry), &start_block, + &offset)) + goto out; + + *fragment_start_block = fragment_entry.start_block; + *fragment_size = fragment_entry.size; + + return 1; + +out: + return 0; +} + + +static struct inode *squashfs_new_inode(struct super_block *s, + struct squashfs_base_inode_header_2 *inodeb, unsigned int ino) +{ + struct squashfs_sb_info *msblk = &s->u.squashfs_sb; + struct squashfs_super_block *sblk = &msblk->sblk; + struct inode *i = new_inode(s); + + if (i) { + i->i_ino = ino; + i->i_mtime = sblk->mkfs_time; + i->i_atime = sblk->mkfs_time; + i->i_ctime = sblk->mkfs_time; + i->i_uid = msblk->uid[inodeb->uid]; + i->i_mode = inodeb->mode; + i->i_nlink = 1; + i->i_size = 0; + if (inodeb->guid == SQUASHFS_GUIDS) + i->i_gid = i->i_uid; + else + i->i_gid = msblk->guid[inodeb->guid]; + } + + return i; +} + + +static struct inode *squashfs_iget_2(struct super_block *s, squashfs_inode_t inode) +{ + struct inode *i; + struct squashfs_sb_info *msblk = &s->u.squashfs_sb; + struct squashfs_super_block *sblk = &msblk->sblk; + unsigned int block = SQUASHFS_INODE_BLK(inode) + + sblk->inode_table_start; + unsigned int offset = SQUASHFS_INODE_OFFSET(inode); + unsigned int ino = SQUASHFS_MK_VFS_INODE(block + - sblk->inode_table_start, offset); + long long next_block; + unsigned int next_offset; + union squashfs_inode_header_2 id, sid; + struct squashfs_base_inode_header_2 *inodeb = &id.base, + *sinodeb = &sid.base; + + TRACE("Entered squashfs_iget\n"); + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, (char *) sinodeb, block, + offset, sizeof(*sinodeb), &next_block, + &next_offset)) + goto failed_read; + SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb, + sizeof(*sinodeb)); + } else + if (!squashfs_get_cached_block(s, (char *) inodeb, block, + offset, sizeof(*inodeb), &next_block, + &next_offset)) + goto failed_read; + + switch(inodeb->inode_type) { + case SQUASHFS_FILE_TYPE: { + struct squashfs_reg_inode_header_2 *inodep = &id.reg; + struct squashfs_reg_inode_header_2 *sinodep = &sid.reg; + long long frag_blk; + unsigned int frag_size; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, (char *) + sinodep, block, offset, + sizeof(*sinodep), &next_block, + &next_offset)) + goto failed_read; + SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep); + } else + if (!squashfs_get_cached_block(s, (char *) + inodep, block, offset, + sizeof(*inodep), &next_block, + &next_offset)) + goto failed_read; + + frag_blk = SQUASHFS_INVALID_BLK; + if (inodep->fragment != SQUASHFS_INVALID_FRAG && + !get_fragment_location_2(s, + inodep->fragment, &frag_blk, &frag_size)) + goto failed_read; + + if((i = squashfs_new_inode(s, inodeb, ino)) == NULL) + goto failed_read1; + + i->i_size = inodep->file_size; + i->i_fop = &generic_ro_fops; + i->i_mode |= S_IFREG; + i->i_mtime = inodep->mtime; + i->i_atime = inodep->mtime; + i->i_ctime = inodep->mtime; + i->i_blocks = ((i->i_size - 1) >> 9) + 1; + i->i_blksize = PAGE_CACHE_SIZE; + SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; + SQUASHFS_I(i)->u.s1.fragment_size = frag_size; + SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; + SQUASHFS_I(i)->start_block = inodep->start_block; + SQUASHFS_I(i)->u.s1.block_list_start = next_block; + SQUASHFS_I(i)->offset = next_offset; + if (sblk->block_size > 4096) + i->i_data.a_ops = &squashfs_aops; + else + i->i_data.a_ops = &squashfs_aops_4K; + + TRACE("File inode %x:%x, start_block %x, " + "block_list_start %llx, offset %x\n", + SQUASHFS_INODE_BLK(inode), offset, + inodep->start_block, next_block, + next_offset); + break; + } + case SQUASHFS_DIR_TYPE: { + struct squashfs_dir_inode_header_2 *inodep = &id.dir; + struct squashfs_dir_inode_header_2 *sinodep = &sid.dir; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, (char *) + sinodep, block, offset, + sizeof(*sinodep), &next_block, + &next_offset)) + goto failed_read; + SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep); + } else + if (!squashfs_get_cached_block(s, (char *) + inodep, block, offset, + sizeof(*inodep), &next_block, + &next_offset)) + goto failed_read; + + if((i = squashfs_new_inode(s, inodeb, ino)) == NULL) + goto failed_read1; + + i->i_size = inodep->file_size; + i->i_op = &squashfs_dir_inode_ops_2; + i->i_fop = &squashfs_dir_ops_2; + i->i_mode |= S_IFDIR; + i->i_mtime = inodep->mtime; + i->i_atime = inodep->mtime; + i->i_ctime = inodep->mtime; + SQUASHFS_I(i)->start_block = inodep->start_block; + SQUASHFS_I(i)->offset = inodep->offset; + SQUASHFS_I(i)->u.s2.directory_index_count = 0; + SQUASHFS_I(i)->u.s2.parent_inode = 0; + + TRACE("Directory inode %x:%x, start_block %x, offset " + "%x\n", SQUASHFS_INODE_BLK(inode), + offset, inodep->start_block, + inodep->offset); + break; + } + case SQUASHFS_LDIR_TYPE: { + struct squashfs_ldir_inode_header_2 *inodep = &id.ldir; + struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, (char *) + sinodep, block, offset, + sizeof(*sinodep), &next_block, + &next_offset)) + goto failed_read; + SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep, + sinodep); + } else + if (!squashfs_get_cached_block(s, (char *) + inodep, block, offset, + sizeof(*inodep), &next_block, + &next_offset)) + goto failed_read; + + if((i = squashfs_new_inode(s, inodeb, ino)) == NULL) + goto failed_read1; + + i->i_size = inodep->file_size; + i->i_op = &squashfs_dir_inode_ops_2; + i->i_fop = &squashfs_dir_ops_2; + i->i_mode |= S_IFDIR; + i->i_mtime = inodep->mtime; + i->i_atime = inodep->mtime; + i->i_ctime = inodep->mtime; + SQUASHFS_I(i)->start_block = inodep->start_block; + SQUASHFS_I(i)->offset = inodep->offset; + SQUASHFS_I(i)->u.s2.directory_index_start = next_block; + SQUASHFS_I(i)->u.s2.directory_index_offset = + next_offset; + SQUASHFS_I(i)->u.s2.directory_index_count = + inodep->i_count; + SQUASHFS_I(i)->u.s2.parent_inode = 0; + + TRACE("Long directory inode %x:%x, start_block %x, " + "offset %x\n", + SQUASHFS_INODE_BLK(inode), offset, + inodep->start_block, inodep->offset); + break; + } + case SQUASHFS_SYMLINK_TYPE: { + struct squashfs_symlink_inode_header_2 *inodep = + &id.symlink; + struct squashfs_symlink_inode_header_2 *sinodep = + &sid.symlink; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, (char *) + sinodep, block, offset, + sizeof(*sinodep), &next_block, + &next_offset)) + goto failed_read; + SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep, + sinodep); + } else + if (!squashfs_get_cached_block(s, (char *) + inodep, block, offset, + sizeof(*inodep), &next_block, + &next_offset)) + goto failed_read; + + if((i = squashfs_new_inode(s, inodeb, ino)) == NULL) + goto failed_read1; + + i->i_size = inodep->symlink_size; + i->i_op = &page_symlink_inode_operations; + i->i_data.a_ops = &squashfs_symlink_aops; + i->i_mode |= S_IFLNK; + SQUASHFS_I(i)->start_block = next_block; + SQUASHFS_I(i)->offset = next_offset; + + TRACE("Symbolic link inode %x:%x, start_block %llx, " + "offset %x\n", + SQUASHFS_INODE_BLK(inode), offset, + next_block, next_offset); + break; + } + case SQUASHFS_BLKDEV_TYPE: + case SQUASHFS_CHRDEV_TYPE: { + struct squashfs_dev_inode_header_2 *inodep = &id.dev; + struct squashfs_dev_inode_header_2 *sinodep = &sid.dev; + + if (msblk->swap) { + if (!squashfs_get_cached_block(s, (char *) + sinodep, block, offset, + sizeof(*sinodep), &next_block, + &next_offset)) + goto failed_read; + SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep); + } else + if (!squashfs_get_cached_block(s, (char *) + inodep, block, offset, + sizeof(*inodep), &next_block, + &next_offset)) + goto failed_read; + + if ((i = squashfs_new_inode(s, inodeb, ino)) == NULL) + goto failed_read1; + + i->i_mode |= (inodeb->inode_type == + SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : + S_IFBLK; + init_special_inode(i, i->i_mode, inodep->rdev); + + TRACE("Device inode %x:%x, rdev %x\n", + SQUASHFS_INODE_BLK(inode), offset, + inodep->rdev); + break; + } + case SQUASHFS_FIFO_TYPE: + case SQUASHFS_SOCKET_TYPE: { + if ((i = squashfs_new_inode(s, inodeb, ino)) == NULL) + goto failed_read1; + + i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE) + ? S_IFIFO : S_IFSOCK; + init_special_inode(i, i->i_mode, 0); + break; + } + default: + ERROR("Unknown inode type %d in squashfs_iget!\n", + inodeb->inode_type); + goto failed_read1; + } + + insert_inode_hash(i); + return i; + +failed_read: + ERROR("Unable to read inode [%x:%x]\n", block, offset); + +failed_read1: + return NULL; +} + + +static int get_dir_index_using_offset(struct super_block *s, long long + *next_block, unsigned int *next_offset, + long long index_start, + unsigned int index_offset, int i_count, + long long f_pos) +{ + struct squashfs_sb_info *msblk = &s->u.squashfs_sb; + struct squashfs_super_block *sblk = &msblk->sblk; + int i, length = 0; + struct squashfs_dir_index_2 index; + + TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n", + i_count, (unsigned int) f_pos); + + if (f_pos == 0) + goto finish; + + for (i = 0; i < i_count; i++) { + if (msblk->swap) { + struct squashfs_dir_index_2 sindex; + squashfs_get_cached_block(s, (char *) &sindex, + index_start, index_offset, + sizeof(sindex), &index_start, + &index_offset); + SQUASHFS_SWAP_DIR_INDEX_2(&index, &sindex); + } else + squashfs_get_cached_block(s, (char *) &index, + index_start, index_offset, + sizeof(index), &index_start, + &index_offset); + + if (index.index > f_pos) + break; + + squashfs_get_cached_block(s, NULL, index_start, index_offset, + index.size + 1, &index_start, + &index_offset); + + length = index.index; + *next_block = index.start_block + sblk->directory_table_start; + } + + *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; + +finish: + return length; +} + + +static int get_dir_index_using_name(struct super_block *s, long long + *next_block, unsigned int *next_offset, + long long index_start, + unsigned int index_offset, int i_count, + const char *name, int size) +{ + struct squashfs_sb_info *msblk = &s->u.squashfs_sb; + struct squashfs_super_block *sblk = &msblk->sblk; + int i, length = 0; + char buffer[sizeof(struct squashfs_dir_index_2) + SQUASHFS_NAME_LEN + 1]; + struct squashfs_dir_index_2 *index = (struct squashfs_dir_index_2 *) buffer; + char str[SQUASHFS_NAME_LEN + 1]; + + TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count); + + strncpy(str, name, size); + str[size] = '\0'; + + for (i = 0; i < i_count; i++) { + if (msblk->swap) { + struct squashfs_dir_index_2 sindex; + squashfs_get_cached_block(s, (char *) &sindex, + index_start, index_offset, + sizeof(sindex), &index_start, + &index_offset); + SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex); + } else + squashfs_get_cached_block(s, (char *) index, + index_start, index_offset, + sizeof(struct squashfs_dir_index_2), + &index_start, &index_offset); + + squashfs_get_cached_block(s, index->name, index_start, + index_offset, index->size + 1, + &index_start, &index_offset); + + index->name[index->size + 1] = '\0'; + + if (strcmp(index->name, str) > 0) + break; + + length = index->index; + *next_block = index->start_block + sblk->directory_table_start; + } + + *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; + return length; +} + + +static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir) +{ + struct inode *i = file->f_dentry->d_inode; + struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb; + struct squashfs_super_block *sblk = &msblk->sblk; + long long next_block = SQUASHFS_I(i)->start_block + + sblk->directory_table_start; + int next_offset = SQUASHFS_I(i)->offset, length = 0, dirs_read = 0, + dir_count; + struct squashfs_dir_header_2 dirh; + char buffer[sizeof(struct squashfs_dir_entry_2) + SQUASHFS_NAME_LEN + 1]; + struct squashfs_dir_entry_2 *dire = (struct squashfs_dir_entry_2 *) buffer; + + TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset); + + length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset, + SQUASHFS_I(i)->u.s2.directory_index_start, + SQUASHFS_I(i)->u.s2.directory_index_offset, + SQUASHFS_I(i)->u.s2.directory_index_count, + file->f_pos); + + while (length < i_size_read(i)) { + /* read directory header */ + if (msblk->swap) { + struct squashfs_dir_header_2 sdirh; + + if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, + next_block, next_offset, sizeof(sdirh), + &next_block, &next_offset)) + goto failed_read; + + length += sizeof(sdirh); + SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh); + } else { + if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, + next_block, next_offset, sizeof(dirh), + &next_block, &next_offset)) + goto failed_read; + + length += sizeof(dirh); + } + + dir_count = dirh.count + 1; + while (dir_count--) { + if (msblk->swap) { + struct squashfs_dir_entry_2 sdire; + if (!squashfs_get_cached_block(i->i_sb, (char *) + &sdire, next_block, next_offset, + sizeof(sdire), &next_block, + &next_offset)) + goto failed_read; + + length += sizeof(sdire); + SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire); + } else { + if (!squashfs_get_cached_block(i->i_sb, (char *) + dire, next_block, next_offset, + sizeof(*dire), &next_block, + &next_offset)) + goto failed_read; + + length += sizeof(*dire); + } + + if (!squashfs_get_cached_block(i->i_sb, dire->name, + next_block, next_offset, + dire->size + 1, &next_block, + &next_offset)) + goto failed_read; + + length += dire->size + 1; + + if (file->f_pos >= length) + continue; + + dire->name[dire->size + 1] = '\0'; + + TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n", + (unsigned int) dirent, dire->name, + dire->size + 1, (int) file->f_pos, + dirh.start_block, dire->offset, + squashfs_filetype_table[dire->type]); + + if (filldir(dirent, dire->name, dire->size + 1, + file->f_pos, SQUASHFS_MK_VFS_INODE( + dirh.start_block, dire->offset), + squashfs_filetype_table[dire->type]) + < 0) { + TRACE("Filldir returned less than 0\n"); + goto finish; + } + file->f_pos = length; + dirs_read++; + } + } + +finish: + return dirs_read; + +failed_read: + ERROR("Unable to read directory block [%llx:%x]\n", next_block, + next_offset); + return 0; +} + + +static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry) +{ + const unsigned char *name = dentry->d_name.name; + int len = dentry->d_name.len; + struct inode *inode = NULL; + struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb; + struct squashfs_super_block *sblk = &msblk->sblk; + long long next_block = SQUASHFS_I(i)->start_block + + sblk->directory_table_start; + int next_offset = SQUASHFS_I(i)->offset, length = 0, + dir_count; + struct squashfs_dir_header_2 dirh; + char buffer[sizeof(struct squashfs_dir_entry_2) + SQUASHFS_NAME_LEN]; + struct squashfs_dir_entry_2 *dire = (struct squashfs_dir_entry_2 *) buffer; + int sorted = sblk->s_major == 2 && sblk->s_minor >= 1; + + TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset); + + if (len > SQUASHFS_NAME_LEN) + goto exit_loop; + + length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset, + SQUASHFS_I(i)->u.s2.directory_index_start, + SQUASHFS_I(i)->u.s2.directory_index_offset, + SQUASHFS_I(i)->u.s2.directory_index_count, name, + len); + + while (length < i_size_read(i)) { + /* read directory header */ + if (msblk->swap) { + struct squashfs_dir_header_2 sdirh; + if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, + next_block, next_offset, sizeof(sdirh), + &next_block, &next_offset)) + goto failed_read; + + length += sizeof(sdirh); + SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh); + } else { + if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, + next_block, next_offset, sizeof(dirh), + &next_block, &next_offset)) + goto failed_read; + + length += sizeof(dirh); + } + + dir_count = dirh.count + 1; + while (dir_count--) { + if (msblk->swap) { + struct squashfs_dir_entry_2 sdire; + if (!squashfs_get_cached_block(i->i_sb, (char *) + &sdire, next_block,next_offset, + sizeof(sdire), &next_block, + &next_offset)) + goto failed_read; + + length += sizeof(sdire); + SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire); + } else { + if (!squashfs_get_cached_block(i->i_sb, (char *) + dire, next_block,next_offset, + sizeof(*dire), &next_block, + &next_offset)) + goto failed_read; + + length += sizeof(*dire); + } + + if (!squashfs_get_cached_block(i->i_sb, dire->name, + next_block, next_offset, dire->size + 1, + &next_block, &next_offset)) + goto failed_read; + + length += dire->size + 1; + + if (sorted && name[0] < dire->name[0]) + goto exit_loop; + + if ((len == dire->size + 1) && !strncmp(name, + dire->name, len)) { + squashfs_inode_t ino = + SQUASHFS_MKINODE(dirh.start_block, + dire->offset); + + TRACE("calling squashfs_iget for directory " + "entry %s, inode %x:%x, %d\n", name, + dirh.start_block, dire->offset, ino); + + inode = (msblk->iget)(i->i_sb, ino); + + goto exit_loop; + } + } + } + +exit_loop: + d_add(dentry, inode); + return ERR_PTR(0); + +failed_read: + ERROR("Unable to read directory block [%llx:%x]\n", next_block, + next_offset); + goto exit_loop; +} + + +int squashfs_2_0_supported(struct squashfs_sb_info *msblk) +{ + struct squashfs_super_block *sblk = &msblk->sblk; + + msblk->iget = squashfs_iget_2; + msblk->read_fragment_index_table = read_fragment_index_table_2; + + sblk->bytes_used = sblk->bytes_used_2; + sblk->uid_start = sblk->uid_start_2; + sblk->guid_start = sblk->guid_start_2; + sblk->inode_table_start = sblk->inode_table_start_2; + sblk->directory_table_start = sblk->directory_table_start_2; + sblk->fragment_table_start = sblk->fragment_table_start_2; + + return 1; +} diff --git a/release/src/linux/linux/include/linux/fs.h b/release/src/linux/linux/include/linux/fs.h index 0b85bf9e..db1a1572 100644 --- a/release/src/linux/linux/include/linux/fs.h +++ b/release/src/linux/linux/include/linux/fs.h @@ -1421,7 +1421,7 @@ extern int block_write_full_page(struct page*, get_block_t*); extern int block_read_full_page(struct page*, get_block_t*); extern int block_prepare_write(struct page*, unsigned, unsigned, get_block_t*); extern int cont_prepare_write(struct page*, unsigned, unsigned, get_block_t*, - unsigned long *); + loff_t *); extern int generic_cont_expand(struct inode *inode, loff_t size) ; extern int block_commit_write(struct page *page, unsigned from, unsigned to); extern int block_sync_page(struct page *); diff --git a/release/src/linux/linux/include/linux/imq.h b/release/src/linux/linux/include/linux/imq.h new file mode 100644 index 00000000..8bf3f959 --- /dev/null +++ b/release/src/linux/linux/include/linux/imq.h @@ -0,0 +1,9 @@ +#ifndef _IMQ_H +#define _IMQ_H + +#define IMQ_MAX_DEVS 16 + +#define IMQ_F_IFMASK 0x7f +#define IMQ_F_ENQUEUE 0x80 + +#endif /* _IMQ_H */ diff --git a/release/src/linux/linux/include/linux/jhash.h b/release/src/linux/linux/include/linux/jhash.h new file mode 100644 index 00000000..82c7ae41 --- /dev/null +++ b/release/src/linux/linux/include/linux/jhash.h @@ -0,0 +1,143 @@ +#ifndef _LINUX_JHASH_H +#define _LINUX_JHASH_H + +/* jhash.h: Jenkins hash support. + * + * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net) + * + * http://burtleburtle.net/bob/hash/ + * + * These are the credits from Bob's sources: + * + * lookup2.c, by Bob Jenkins, December 1996, Public Domain. + * hash(), hash2(), hash3, and mix() are externally useful functions. + * Routines to test the hash are included if SELF_TEST is defined. + * You can use this free for any purpose. It has no warranty. + * + * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * + * I've modified Bob's hash to be useful in the Linux kernel, and + * any bugs present are surely my fault. -DaveM + */ + +/* NOTE: Arguments are modified. */ +#define __jhash_mix(a, b, c) \ +{ \ + a -= b; a -= c; a ^= (c>>13); \ + b -= c; b -= a; b ^= (a<<8); \ + c -= a; c -= b; c ^= (b>>13); \ + a -= b; a -= c; a ^= (c>>12); \ + b -= c; b -= a; b ^= (a<<16); \ + c -= a; c -= b; c ^= (b>>5); \ + a -= b; a -= c; a ^= (c>>3); \ + b -= c; b -= a; b ^= (a<<10); \ + c -= a; c -= b; c ^= (b>>15); \ +} + +/* The golden ration: an arbitrary value */ +#define JHASH_GOLDEN_RATIO 0x9e3779b9 + +/* The most generic version, hashes an arbitrary sequence + * of bytes. No alignment or length assumptions are made about + * the input key. + */ +static inline u32 jhash(const void *key, u32 length, u32 initval) +{ + u32 a, b, c, len; + const u8 *k = key; + + len = length; + a = b = JHASH_GOLDEN_RATIO; + c = initval; + + while (len >= 12) { + a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24)); + b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24)); + c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24)); + + __jhash_mix(a,b,c); + + k += 12; + len -= 12; + } + + c += length; + switch (len) { + case 11: c += ((u32)k[10]<<24); + case 10: c += ((u32)k[9]<<16); + case 9 : c += ((u32)k[8]<<8); + case 8 : b += ((u32)k[7]<<24); + case 7 : b += ((u32)k[6]<<16); + case 6 : b += ((u32)k[5]<<8); + case 5 : b += k[4]; + case 4 : a += ((u32)k[3]<<24); + case 3 : a += ((u32)k[2]<<16); + case 2 : a += ((u32)k[1]<<8); + case 1 : a += k[0]; + }; + + __jhash_mix(a,b,c); + + return c; +} + +/* A special optimized version that handles 1 or more of u32s. + * The length parameter here is the number of u32s in the key. + */ +static inline u32 jhash2(u32 *k, u32 length, u32 initval) +{ + u32 a, b, c, len; + + a = b = JHASH_GOLDEN_RATIO; + c = initval; + len = length; + + while (len >= 3) { + a += k[0]; + b += k[1]; + c += k[2]; + __jhash_mix(a, b, c); + k += 3; len -= 3; + } + + c += length * 4; + + switch (len) { + case 2 : b += k[1]; + case 1 : a += k[0]; + }; + + __jhash_mix(a,b,c); + + return c; +} + + +/* A special ultra-optimized versions that knows they are hashing exactly + * 3, 2 or 1 word(s). + * + * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally + * done at the end is not done here. + */ +static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval) +{ + a += JHASH_GOLDEN_RATIO; + b += JHASH_GOLDEN_RATIO; + c += initval; + + __jhash_mix(a, b, c); + + return c; +} + +static inline u32 jhash_2words(u32 a, u32 b, u32 initval) +{ + return jhash_3words(a, b, 0, initval); +} + +static inline u32 jhash_1word(u32 a, u32 initval) +{ + return jhash_3words(a, 0, 0, initval); +} + +#endif /* _LINUX_JHASH_H */ diff --git a/release/src/linux/linux/include/linux/list.h b/release/src/linux/linux/include/linux/list.h index 9d98ba31..dafdfc87 100644 --- a/release/src/linux/linux/include/linux/list.h +++ b/release/src/linux/linux/include/linux/list.h @@ -227,6 +227,33 @@ static inline void list_splice_init(struct list_head *list, pos = list_entry(pos->member.next, typeof(*pos), member), \ prefetch(pos->member.next)) +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_continue - iterate over list of given type + * continuing after existing point + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + #endif /* __KERNEL__ || _LVM_H_INCLUDE */ #endif diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack.h index 314f6cc3..2e75b782 100644 --- a/release/src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack.h +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack.h @@ -6,6 +6,7 @@ #include <linux/config.h> #include <linux/netfilter_ipv4/ip_conntrack_tuple.h> +#include <linux/bitops.h> #include <asm/atomic.h> enum ip_conntrack_info @@ -41,6 +42,10 @@ enum ip_conntrack_status { /* Conntrack should never be early-expired. */ IPS_ASSURED_BIT = 2, IPS_ASSURED = (1 << IPS_ASSURED_BIT), + + /* Connection is confirmed: originating packet has left box */ + IPS_CONFIRMED_BIT = 3, + IPS_CONFIRMED = (1 << IPS_CONFIRMED_BIT), }; #include <linux/netfilter_ipv4/ip_conntrack_tcp.h> @@ -62,31 +67,27 @@ union ip_conntrack_expect_proto { }; /* Add protocol helper include file here */ +#include <linux/netfilter_ipv4/ip_conntrack_h323.h> #include <linux/netfilter_ipv4/ip_conntrack_pptp.h> #include <linux/netfilter_ipv4/ip_conntrack_sip.h> #include <linux/netfilter_ipv4/ip_conntrack_mms.h> -#include <linux/netfilter_ipv4/ip_conntrack_h323.h> - #include <linux/netfilter_ipv4/ip_conntrack_ftp.h> #include <linux/netfilter_ipv4/ip_conntrack_irc.h> -#ifdef CONFIG_IP_NF_NAT_RTSP -#include <linux/netfilter_ipv4/ip_conntrack_rtsp.h> -#endif #include <linux/netfilter_ipv4/ip_autofw.h> +#include <linux/netfilter_ipv4/ip_conntrack_rtsp.h> /* per expectation: application helper private data */ union ip_conntrack_expect_help { /* insert conntrack helper private data (expect) here */ + struct ip_ct_h225_expect exp_h225_info; struct ip_ct_pptp_expect exp_pptp_info; struct ip_ct_sip_expect exp_sip_info; struct ip_ct_mms_expect exp_mms_info; - struct ip_ct_h225_expect exp_h225_info; struct ip_ct_ftp_expect exp_ftp_info; struct ip_ct_irc_expect exp_irc_info; struct ip_autofw_expect exp_autofw_info; -#ifdef CONFIG_IP_NF_NAT_RTSP - struct ip_ct_rtsp_expect exp_rtsp_info; -#endif + struct ip_ct_rtsp_expect exp_rtsp_info; + #ifdef CONFIG_IP_NF_NAT_NEEDED union { /* insert nat helper private data (expect) here */ @@ -97,15 +98,13 @@ union ip_conntrack_expect_help { /* per conntrack: application helper private data */ union ip_conntrack_help { /* insert conntrack helper private data (master) here */ + struct ip_ct_h225_master ct_h225_info; struct ip_ct_pptp_master ct_pptp_info; struct ip_ct_sip_master ct_sip_info; struct ip_ct_mms_master ct_mms_info; - struct ip_ct_h225_master ct_h225_info; struct ip_ct_ftp_master ct_ftp_info; struct ip_ct_irc_master ct_irc_info; -#ifdef CONFIG_IP_NF_NAT_RTSP - struct ip_ct_rtsp_master ct_rtsp_info; -#endif + struct ip_ct_rtsp_master ct_rtsp_info; }; #ifdef CONFIG_IP_NF_NAT_NEEDED @@ -188,7 +187,7 @@ struct ip_conntrack struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX]; /* Have we seen traffic both ways yet? (bitset) */ - volatile unsigned long status; + unsigned long status; /* Timer function; drops refcnt when it goes off. */ struct timer_list timeout; @@ -227,6 +226,29 @@ struct ip_conntrack } nat; #endif /* CONFIG_IP_NF_NAT_NEEDED */ +#if defined(CONFIG_IP_NF_CONNTRACK_MARK) + unsigned long mark; +#endif + +#if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE) + struct { + unsigned int numpackets; /* surely this is kept track of somewhere else, right? I can't find it... */ + char * app_proto; /* "http", "ftp", etc. NULL if unclassifed */ + + /* the application layer data so far. NULL if ->numpackets > numpackets */ + char * app_data; + + unsigned int app_data_len; + } layer7; +#endif + +#if defined(CONFIG_IP_NF_TARGET_BCOUNT) || defined(CONFIG_IP_NF_TARGET_BCOUNT_MODULE) + u_int32_t bcount; +#endif + +#if defined(CONFIG_IP_NF_TARGET_MACSAVE) || defined(CONFIG_IP_NF_TARGET_MACSAVE_MODULE) + unsigned char macsave[6]; +#endif }; /* get master conntrack via master expectation */ @@ -283,7 +305,7 @@ ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data), /* It's confirmed if it is, or has been in the hash table. */ static inline int is_confirmed(struct ip_conntrack *ct) { - return ct->tuplehash[IP_CT_DIR_ORIGINAL].list.next != NULL; + return test_bit(IPS_CONFIRMED_BIT, &ct->status); } extern unsigned int ip_conntrack_htable_size; diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_h323.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_h323.h index 10221fe9..3803c126 100644 --- a/release/src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_h323.h +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_h323.h @@ -4,6 +4,7 @@ #ifdef __KERNEL__ /* Protects H.323 related data */ +#include <linux/netfilter_ipv4/lockhelp.h> DECLARE_LOCK_EXTERN(ip_h323_lock); #endif diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_proto_esp.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_proto_esp.h index acb4d9ec..acb4d9ec 100755..100644 --- a/release/src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_proto_esp.h +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_proto_esp.h diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h index 738e99a2..07646857 100644 --- a/release/src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h @@ -77,13 +77,13 @@ struct ip_ct_gre_expect { }; #ifdef __KERNEL__ +struct ip_conntrack_expect; /* structure for original <-> reply keymap */ struct ip_ct_gre_keymap { struct list_head list; struct ip_conntrack_tuple tuple; - struct ip_conntrack_expect *master; }; @@ -96,6 +96,8 @@ int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp, void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km, struct ip_conntrack_tuple *t); +/* delete keymap entries */ +void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp); /* get pointer to gre key, if present */ diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h index 770935d3..0f103d35 100644 --- a/release/src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h @@ -57,7 +57,6 @@ struct ip_conntrack_tuple } tcp; struct { u_int16_t port; - unsigned int init_cookie;//xiaoqin add for multi-ipsec passthrough,2005.12.19 } udp; struct { u_int8_t type, code; diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ip_tables.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ip_tables.h index d2a7f4b4..11e0cfcf 100644 --- a/release/src/linux/linux/include/linux/netfilter_ipv4/ip_tables.h +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ip_tables.h @@ -104,7 +104,8 @@ struct ipt_counters /* Values for "flag" field in struct ipt_ip (general ip structure). */ #define IPT_F_FRAG 0x01 /* Set if rule is a fragment rule */ -#define IPT_F_MASK 0x01 /* All possible flag bits mask. */ +#define IPT_F_GOTO 0x02 /* Set if jump is a goto */ +#define IPT_F_MASK 0x03 /* All possible flag bits mask. */ /* Values for "inv" field in struct ipt_ip. */ #define IPT_INV_VIA_IN 0x01 /* Invert the sense of IN IFACE. */ diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_BCOUNT.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_BCOUNT.h new file mode 100644 index 00000000..34b56aef --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_BCOUNT.h @@ -0,0 +1,16 @@ +/* + + BCOUNT target + Copyright (C) 2006 Jonathan Zarate + + Licensed under GNU GPL v2 or later. + +*/ +#ifndef _IPT_BCOUNT_TARGET_H +#define _IPT_BCOUNT_TARGET_H + +struct ipt_BCOUNT_target { +// int debug; +}; + +#endif diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_CLASSIFY.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_CLASSIFY.h new file mode 100644 index 00000000..7596e3dd --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_CLASSIFY.h @@ -0,0 +1,8 @@ +#ifndef _IPT_CLASSIFY_H +#define _IPT_CLASSIFY_H + +struct ipt_classify_target_info { + u_int32_t priority; +}; + +#endif /*_IPT_CLASSIFY_H */ diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_CONNMARK.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_CONNMARK.h new file mode 100644 index 00000000..f9099f92 --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_CONNMARK.h @@ -0,0 +1,26 @@ +#ifndef _IPT_CONNMARK_H_target +#define _IPT_CONNMARK_H_target + +/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com> + * by Henrik Nordstrom <hno@marasystems.com> + * + * 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. + */ + +enum { + IPT_CONNMARK_SET = 0, + IPT_CONNMARK_SAVE, + IPT_CONNMARK_RESTORE, + IPT_CONNMARK_SET_RETURN +}; + +struct ipt_connmark_target_info { + unsigned long mark; + unsigned long mask; + u_int8_t mode; +}; + +#endif /*_IPT_CONNMARK_H_target*/ diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_IMQ.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_IMQ.h new file mode 100644 index 00000000..45d57713 --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_IMQ.h @@ -0,0 +1,8 @@ +#ifndef _IPT_IMQ_H +#define _IPT_IMQ_H + +struct ipt_imq_info { + unsigned int todev; /* target imq device */ +}; + +#endif /* _IPT_IMQ_H */ diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_MACSAVE.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_MACSAVE.h new file mode 100644 index 00000000..dc426893 --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_MACSAVE.h @@ -0,0 +1,16 @@ +/* + + MACSAVE target + Copyright (C) 2006 Jonathan Zarate + + Licensed under GNU GPL v2 or later. + +*/ +#ifndef _IPT_MACSAVE_TARGET_H +#define _IPT_MACSAVE_TARGET_H + +struct ipt_MACSAVE_target_info { +// int debug; +}; + +#endif diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_ROUTE.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_ROUTE.h new file mode 100644 index 00000000..41b1a9c8 --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_ROUTE.h @@ -0,0 +1,23 @@ +/* Header file for iptables ipt_ROUTE target + * + * (C) 2002 by Cédric de Launois <delaunois@info.ucl.ac.be> + * + * This software is distributed under GNU GPL v2, 1991 + */ +#ifndef _IPT_ROUTE_H_target +#define _IPT_ROUTE_H_target + +#define IPT_ROUTE_IFNAMSIZ 16 + +struct ipt_route_target_info { + char oif[IPT_ROUTE_IFNAMSIZ]; /* Output Interface Name */ + char iif[IPT_ROUTE_IFNAMSIZ]; /* Input Interface Name */ + u_int32_t gw; /* IP address of gateway */ + u_int8_t flags; +}; + +/* Values for "flags" field */ +#define IPT_ROUTE_CONTINUE 0x01 +#define IPT_ROUTE_TEE 0x02 + +#endif /*_IPT_ROUTE_H_target*/ diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_TTL.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_TTL.h new file mode 100644 index 00000000..edf49e80 --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_TTL.h @@ -0,0 +1,21 @@ +/* TTL modification module for IP tables + * (C) 2000 by Harald Welte <laforge@gnumonks.org> */ + +#ifndef _IPT_TTL_H +#define _IPT_TTL_H + +enum { + IPT_TTL_SET = 0, + IPT_TTL_INC, + IPT_TTL_DEC +}; + +#define IPT_TTL_MAXMODE IPT_TTL_DEC + +struct ipt_TTL_info { + u_int8_t mode; + u_int8_t ttl; +}; + + +#endif diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_account.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_account.h new file mode 100644 index 00000000..6068d86d --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_account.h @@ -0,0 +1,26 @@ +/* + * accounting match (ipt_account.c) + * (C) 2003,2004 by Piotr Gasidlo (quaker@barbara.eu.org) + * + * Version: 0.1.7 + * + * This software is distributed under the terms of GNU GPL + */ + +#ifndef _IPT_ACCOUNT_H_ +#define _IPT_ACCOUNT_H_ + +#define IPT_ACCOUNT_NAME_LEN 64 + +#define IPT_ACCOUNT_NAME "ipt_account" +#define IPT_ACCOUNT_VERSION "0.1.7" + +struct t_ipt_account_info { + char name[IPT_ACCOUNT_NAME_LEN]; + u_int32_t network; + u_int32_t netmask; + int shortlisting:1; +}; + +#endif + diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_bcount.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_bcount.h new file mode 100644 index 00000000..66f5ed9c --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_bcount.h @@ -0,0 +1,18 @@ +/* + + bcount match (experimental) + Copyright (C) 2006 Jonathan Zarate + + Licensed under GNU GPL v2 or later. + +*/ +#ifndef _IPT_BCOUNT_H +#define _IPT_BCOUNT_H + +struct ipt_bcount_match { + u_int32_t min; + u_int32_t max; + int invert; +}; + +#endif diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_condition.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_condition.h new file mode 100644 index 00000000..2bc5b0c8 --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_condition.h @@ -0,0 +1,11 @@ +#ifndef __IPT_CONDITION_MATCH__ +#define __IPT_CONDITION_MATCH__ + +#define CONDITION_NAME_LEN 32 + +struct condition_info { + char name[CONDITION_NAME_LEN]; + int invert; +}; + +#endif diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_connlimit.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_connlimit.h new file mode 100644 index 00000000..d99193b7 --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_connlimit.h @@ -0,0 +1,12 @@ +#ifndef _IPT_CONNLIMIT_H +#define _IPT_CONNLIMIT_H + +struct ipt_connlimit_data; + +struct ipt_connlimit_info { + int limit; + int inverse; + u_int32_t mask; + struct ipt_connlimit_data *data; +}; +#endif /* _IPT_CONNLIMIT_H */ diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_connmark.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_connmark.h new file mode 100644 index 00000000..46573270 --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_connmark.h @@ -0,0 +1,18 @@ +#ifndef _IPT_CONNMARK_H +#define _IPT_CONNMARK_H + +/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com> + * by Henrik Nordstrom <hno@marasystems.com> + * + * 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. + */ + +struct ipt_connmark_info { + unsigned long mark, mask; + u_int8_t invert; +}; + +#endif /*_IPT_CONNMARK_H*/ diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_exp.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_exp.h new file mode 100644 index 00000000..51319cb2 --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_exp.h @@ -0,0 +1,15 @@ +/* + + Experimental Netfilter Crap + Copyright (C) 2006 Jonathan Zarate + +*/ + +#ifndef _IPT_EXP_H +#define _IPT_EXP_H + +struct ipt_exp_info { + char dummy; +}; + +#endif diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_geoip.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_geoip.h new file mode 100644 index 00000000..15764e8b --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_geoip.h @@ -0,0 +1,51 @@ +/* ipt_geoip.h header file for libipt_geoip.c and ipt_geoip.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. + * + * Copyright (c) 2004 Cookinglinux + */ +#ifndef _IPT_GEOIP_H +#define _IPT_GEOIP_H + +#define IPT_GEOIP_SRC 0x01 /* Perform check on Source IP */ +#define IPT_GEOIP_DST 0x02 /* Perform check on Destination IP */ +#define IPT_GEOIP_INV 0x04 /* Negate the condition */ + +#define IPT_GEOIP_MAX 15 /* Maximum of countries */ + +struct geoip_subnet { + u_int32_t begin; + u_int32_t end; +}; + +struct geoip_info { + struct geoip_subnet *subnets; + u_int32_t count; + u_int32_t ref; + u_int16_t cc; + struct geoip_info *next; + struct geoip_info *prev; +}; + +struct ipt_geoip_info { + u_int8_t flags; + u_int8_t count; + u_int16_t cc[IPT_GEOIP_MAX]; + + /* Used internally by the kernel */ + struct geoip_info *mem[IPT_GEOIP_MAX]; + u_int8_t *refcount; + + /* not implemented yet: + void *fini; + */ +}; + +#define COUNTRY(cc) (cc >> 8), (cc & 0x00FF) + +#endif + +/* End of ipt_geoip.h */ diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_ipp2p.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_ipp2p.h new file mode 100644 index 00000000..1bd3f649 --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_ipp2p.h @@ -0,0 +1,31 @@ +#ifndef __IPT_IPP2P_H +#define __IPT_IPP2P_H +#define IPP2P_VERSION "0.8.1_rc1" + +struct ipt_p2p_info { + int cmd; + int debug; +}; + +#endif //__IPT_IPP2P_H + +#define SHORT_HAND_IPP2P 1 /* --ipp2p switch*/ +//#define SHORT_HAND_DATA 4 /* --ipp2p-data switch*/ +#define SHORT_HAND_NONE 5 /* no short hand*/ + +#define IPP2P_EDK (1 << 1) +#define IPP2P_DATA_KAZAA (1 << 2) +#define IPP2P_DATA_EDK (1 << 3) +#define IPP2P_DATA_DC (1 << 4) +#define IPP2P_DC (1 << 5) +#define IPP2P_DATA_GNU (1 << 6) +#define IPP2P_GNU (1 << 7) +#define IPP2P_KAZAA (1 << 8) +#define IPP2P_BIT (1 << 9) +#define IPP2P_APPLE (1 << 10) +#define IPP2P_SOUL (1 << 11) +#define IPP2P_WINMX (1 << 12) +#define IPP2P_ARES (1 << 13) +#define IPP2P_MUTE (1 << 14) +#define IPP2P_WASTE (1 << 15) +#define IPP2P_XDCC (1 << 16) diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_iprange.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_iprange.h new file mode 100644 index 00000000..3ecb3bd6 --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_iprange.h @@ -0,0 +1,23 @@ +#ifndef _IPT_IPRANGE_H +#define _IPT_IPRANGE_H + +#define IPRANGE_SRC 0x01 /* Match source IP address */ +#define IPRANGE_DST 0x02 /* Match destination IP address */ +#define IPRANGE_SRC_INV 0x10 /* Negate the condition */ +#define IPRANGE_DST_INV 0x20 /* Negate the condition */ + +struct ipt_iprange { + /* Inclusive: network order. */ + u_int32_t min_ip, max_ip; +}; + +struct ipt_iprange_info +{ + struct ipt_iprange src; + struct ipt_iprange dst; + + /* Flags from above */ + u_int8_t flags; +}; + +#endif /* _IPT_IPRANGE_H */ diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_layer7.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_layer7.h new file mode 100644 index 00000000..aee1f5d5 --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_layer7.h @@ -0,0 +1,26 @@ +/* + By Matthew Strait <quadong@users.sf.net>, Dec 2003. + http://l7-filter.sf.net + + 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. + http://www.gnu.org/licenses/gpl.txt +*/ + +#ifndef _IPT_LAYER7_H +#define _IPT_LAYER7_H + +#define MAX_PATTERN_LEN 8192 +#define MAX_PROTOCOL_LEN 256 + +typedef char *(*proc_ipt_search) (char *, char, char *); + +struct ipt_layer7_info { + char protocol[MAX_PROTOCOL_LEN]; + char invert:1; + char pattern[MAX_PATTERN_LEN]; +}; + +#endif /* _IPT_LAYER7_H */ diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_macsave.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_macsave.h new file mode 100644 index 00000000..9d5b218d --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_macsave.h @@ -0,0 +1,17 @@ +/* + + macsave match + Copyright (C) 2006 Jonathan Zarate + + Licensed under GNU GPL v2 or later. + +*/ +#ifndef _IPT_MACSAVE_MATCH_H +#define _IPT_MACSAVE_MATCH_H + +struct ipt_macsave_match_info { + int invert; + unsigned char mac[6]; +}; + +#endif diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_quota.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_quota.h new file mode 100644 index 00000000..f2a06716 --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_quota.h @@ -0,0 +1,12 @@ +#ifndef _IPT_QUOTA_H +#define _IPT_QUOTA_H + +/* print debug info in both kernel/netfilter module & iptable library */ +//#define DEBUG_IPT_QUOTA + +struct ipt_quota_info { + u_int64_t quota; + struct ipt_quota_info *master; +}; + +#endif /*_IPT_QUOTA_H*/ diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_recent.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_recent.h new file mode 100644 index 00000000..eb008fb4 --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_recent.h @@ -0,0 +1,28 @@ +#ifndef _IPT_RECENT_H +#define _IPT_RECENT_H + +#define RECENT_NAME "ipt_recent" +#define RECENT_VER "v0.3.1" + +#define IPT_RECENT_CHECK 1 +#define IPT_RECENT_SET 2 +#define IPT_RECENT_UPDATE 4 +#define IPT_RECENT_REMOVE 8 +#define IPT_RECENT_TTL 16 + +#define IPT_RECENT_SOURCE 0 +#define IPT_RECENT_DEST 1 + +#define IPT_RECENT_NAME_LEN 200 + +struct ipt_recent_info { + u_int32_t seconds; + u_int32_t hit_count; + u_int8_t check_set; + u_int8_t invert; + char name[IPT_RECENT_NAME_LEN]; + u_int8_t side; +}; + +#endif /*_IPT_RECENT_H*/ + diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_string.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_string.h new file mode 100644 index 00000000..17d71034 --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_string.h @@ -0,0 +1,21 @@ +#ifndef _IPT_STRING_H +#define _IPT_STRING_H + +/* *** PERFORMANCE TWEAK *** + * Packet size and search string threshold, + * above which sublinear searches is used. */ +#define IPT_STRING_HAYSTACK_THRESH 100 +#define IPT_STRING_NEEDLE_THRESH 20 + +#define BM_MAX_NLEN 256 +#define BM_MAX_HLEN 1024 + +typedef char *(*proc_ipt_search) (char *, char *, int, int); + +struct ipt_string_info { + char string[BM_MAX_NLEN]; + u_int16_t invert; + u_int16_t len; +}; + +#endif /* _IPT_STRING_H */ diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_time.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_time.h index 1ccdbb3d..277c6de5 100644 --- a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_time.h +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_time.h @@ -3,10 +3,12 @@ struct ipt_time_info { - unsigned int days_match; /* 1 bit per day (bit 0 = Sunday) */ - unsigned int time_start; /* 0 < time_start < 24*60*60-1 = 86399 */ - unsigned int time_stop; /* 0 < time_end < 24*60*60-1 = 86399 */ - int kerneltime; /* ignore skb time (and use kerneltime) or not. */ + u_int8_t days_match; /* 1 bit per day. -SMTWTFS */ + u_int16_t time_start; /* 0 < time_start < 23*60+59 = 1439 */ + u_int16_t time_stop; /* 0:0 < time_stat < 23:59 */ + u_int8_t kerneltime; /* ignore skb time (and use kerneltime) or not. */ + time_t date_start; + time_t date_stop; }; diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_u32.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_u32.h new file mode 100644 index 00000000..694fdc08 --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_u32.h @@ -0,0 +1,40 @@ +#ifndef _IPT_U32_H +#define _IPT_U32_H +#include <linux/netfilter_ipv4/ip_tables.h> + +enum ipt_u32_ops +{ + IPT_U32_AND, + IPT_U32_LEFTSH, + IPT_U32_RIGHTSH, + IPT_U32_AT +}; + +struct ipt_u32_location_element +{ + u_int32_t number; + u_int8_t nextop; +}; +struct ipt_u32_value_element +{ + u_int32_t min; + u_int32_t max; +}; +/* *** any way to allow for an arbitrary number of elements? + for now I settle for a limit of 10 of each */ +#define U32MAXSIZE 10 +struct ipt_u32_test +{ + u_int8_t nnums; + struct ipt_u32_location_element location[U32MAXSIZE+1]; + u_int8_t nvalues; + struct ipt_u32_value_element value[U32MAXSIZE+1]; +}; + +struct ipt_u32 +{ + u_int8_t ntests; + struct ipt_u32_test tests[U32MAXSIZE+1]; +}; + +#endif /*_IPT_U32_H*/ diff --git a/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_web.h b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_web.h new file mode 100644 index 00000000..176208e2 --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv4/ipt_web.h @@ -0,0 +1,30 @@ +/* + + web (experimental) + HTTP client match + Copyright (C) 2006 Jonathan Zarate + + Licensed under GNU GPL v2 or later. + +*/ +#ifndef _IPT_WEB_H +#define _IPT_WEB_H + +#define IPT_WEB_MAXTEXT 512 + +typedef enum { + IPT_WEB_HTTP, + IPT_WEB_RURI, + IPT_WEB_PATH, + IPT_WEB_QUERY, + IPT_WEB_HOST, + IPT_WEB_HORE +} ipt_web_mode_t; + +struct ipt_web_info { + ipt_web_mode_t mode; + int invert; + char text[IPT_WEB_MAXTEXT]; +}; + +#endif diff --git a/release/src/linux/linux/include/linux/netfilter_ipv6/ip6t_IMQ.h b/release/src/linux/linux/include/linux/netfilter_ipv6/ip6t_IMQ.h new file mode 100644 index 00000000..4eefa612 --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv6/ip6t_IMQ.h @@ -0,0 +1,8 @@ +#ifndef _IP6T_IMQ_H +#define _IP6T_IMQ_H + +struct ip6t_imq_info { + unsigned int todev; /* target imq device */ +}; + +#endif /* _IP6T_IMQ_H */ diff --git a/release/src/linux/linux/include/linux/netfilter_ipv6/ip6t_ROUTE.h b/release/src/linux/linux/include/linux/netfilter_ipv6/ip6t_ROUTE.h new file mode 100644 index 00000000..c5ec871b --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv6/ip6t_ROUTE.h @@ -0,0 +1,23 @@ +/* Header file for iptables ip6t_ROUTE target + * + * (C) 2003 by Cédric de Launois <delaunois@info.ucl.ac.be> + * + * This software is distributed under GNU GPL v2, 1991 + */ +#ifndef _IPT_ROUTE_H_target +#define _IPT_ROUTE_H_target + +#define IP6T_ROUTE_IFNAMSIZ 16 + +struct ip6t_route_target_info { + char oif[IP6T_ROUTE_IFNAMSIZ]; /* Output Interface Name */ + char iif[IP6T_ROUTE_IFNAMSIZ]; /* Input Interface Name */ + u_int32_t gw[4]; /* IPv6 address of gateway */ + u_int8_t flags; +}; + +/* Values for "flags" field */ +#define IP6T_ROUTE_CONTINUE 0x01 +#define IP6T_ROUTE_TEE 0x02 + +#endif /*_IP6T_ROUTE_H_target*/ diff --git a/release/src/linux/linux/include/linux/netfilter_ipv6/ip6t_condition.h b/release/src/linux/linux/include/linux/netfilter_ipv6/ip6t_condition.h new file mode 100644 index 00000000..164ff86e --- /dev/null +++ b/release/src/linux/linux/include/linux/netfilter_ipv6/ip6t_condition.h @@ -0,0 +1,11 @@ +#ifndef __IP6T_CONDITION_MATCH__ +#define __IP6T_CONDITION_MATCH__ + +#define CONDITION6_NAME_LEN 32 + +struct condition6_info { + char name[CONDITION6_NAME_LEN]; + int invert; +}; + +#endif diff --git a/release/src/linux/linux/include/linux/pkt_sched.h b/release/src/linux/linux/include/linux/pkt_sched.h index fec8ad62..331feebf 100644 --- a/release/src/linux/linux/include/linux/pkt_sched.h +++ b/release/src/linux/linux/include/linux/pkt_sched.h @@ -173,8 +173,36 @@ struct tc_sfq_qopt * * The only reason for this is efficiency, it is possible * to change these parameters in compile time. + * + * If you need to play with these values use esfq instead. */ +/* ESFQ section */ + +enum +{ + /* traditional */ + TCA_SFQ_HASH_CLASSIC, + TCA_SFQ_HASH_DST, + TCA_SFQ_HASH_SRC, + TCA_SFQ_HASH_FWMARK, + /* direct */ + TCA_SFQ_HASH_DSTDIR, + TCA_SFQ_HASH_SRCDIR, + TCA_SFQ_HASH_FWMARKDIR, +}; + +struct tc_esfq_qopt +{ + unsigned quantum; /* Bytes per round allocated to flow */ + int perturb_period; /* Period of hash perturbation */ + __u32 limit; /* Maximal packets in queue */ + unsigned divisor; /* Hash divisor */ + unsigned flows; /* Maximal number of flows */ + unsigned hash_kind; /* Hash function to use for flow identification */ +}; + + /* RED section */ enum @@ -290,6 +318,37 @@ struct tc_htb_xstats __u32 ctokens; }; +/* HFSC section */ + +struct tc_hfsc_qopt +{ + __u16 defcls; /* default class */ +}; + +struct tc_service_curve +{ + __u32 m1; /* slope of the first segment in bps */ + __u32 d; /* x-projection of the first segment in us */ + __u32 m2; /* slope of the second segment in bps */ +}; + +struct tc_hfsc_stats +{ + __u64 work; /* total work done */ + __u64 rtwork; /* work done by real-time criteria */ + __u32 period; /* current period */ + __u32 level; /* class level in hierarchy */ +}; + +enum +{ + TCA_HFSC_UNSPEC, + TCA_HFSC_RSC, + TCA_HFSC_FSC, + TCA_HFSC_USC, + TCA_HFSC_MAX = TCA_HFSC_USC +}; + /* CBQ section */ #define TC_CBQ_MAXPRIO 8 diff --git a/release/src/linux/linux/include/linux/rbtree.h b/release/src/linux/linux/include/linux/rbtree.h index 96f20e14..d7ba5df4 100644 --- a/release/src/linux/linux/include/linux/rbtree.h +++ b/release/src/linux/linux/include/linux/rbtree.h @@ -121,6 +121,12 @@ rb_root_t; extern void rb_insert_color(rb_node_t *, rb_root_t *); extern void rb_erase(rb_node_t *, rb_root_t *); +/* Find logical next and previous nodes in a tree */ +extern rb_node_t *rb_next(rb_node_t *); +extern rb_node_t *rb_prev(rb_node_t *); +extern rb_node_t *rb_first(rb_root_t *); +extern rb_node_t *rb_last(rb_root_t *); + static inline void rb_link_node(rb_node_t * node, rb_node_t * parent, rb_node_t ** rb_link) { node->rb_parent = parent; diff --git a/release/src/linux/linux/include/linux/skbuff.h b/release/src/linux/linux/include/linux/skbuff.h index 7529ded2..c39889d6 100644 --- a/release/src/linux/linux/include/linux/skbuff.h +++ b/release/src/linux/linux/include/linux/skbuff.h @@ -93,6 +93,9 @@ struct nf_ct_info { struct nf_conntrack *master; }; #endif +#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) +struct nf_info; +#endif struct sk_buff_head { /* These two members must be first. */ @@ -178,7 +181,7 @@ struct sk_buff { unsigned int len; /* Length of actual data */ unsigned int data_len; unsigned int csum; /* Checksum */ - unsigned char __unused, /* Dead field, may be reused */ + unsigned char imq_flags, /* intermediate queueing device */ cloned, /* head may be cloned (check refcnt to be sure). */ pkt_type, /* Packet class */ ip_summed; /* Driver fed us an IP checksum */ @@ -215,6 +218,9 @@ struct sk_buff { #ifdef CONFIG_NET_SCHED __u32 tc_index; /* traffic control index */ #endif +#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) + struct nf_info *nf_info; +#endif }; #define SK_WMEM_MAX 65535 diff --git a/release/src/linux/linux/include/linux/squashfs_fs.h b/release/src/linux/linux/include/linux/squashfs_fs.h index d810c596..5c79e38b 100644 --- a/release/src/linux/linux/include/linux/squashfs_fs.h +++ b/release/src/linux/linux/include/linux/squashfs_fs.h @@ -1,9 +1,11 @@ #ifndef SQUASHFS_FS #define SQUASHFS_FS + /* * Squashfs * - * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.net> + * Copyright (c) 2002, 2003, 2004, 2005, 2006 + * Phillip Lougher <phillip@lougher.org.uk> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -22,7 +24,23 @@ * squashfs_fs.h */ -#define SQUASHFS_MAJOR 2 +#ifndef CONFIG_SQUASHFS_2_0_COMPATIBILITY +#define CONFIG_SQUASHFS_2_0_COMPATIBILITY +#endif + +#ifdef CONFIG_SQUASHFS_VMALLOC +#define SQUASHFS_ALLOC(a) vmalloc(a) +#define SQUASHFS_FREE(a) vfree(a) +#else +#define SQUASHFS_ALLOC(a) kmalloc(a, GFP_KERNEL) +#define SQUASHFS_FREE(a) kfree(a) +#endif +#ifdef CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE +#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE +#else +#define SQUASHFS_CACHED_FRAGMENTS 3 +#endif +#define SQUASHFS_MAJOR 3 #define SQUASHFS_MINOR 0 #define SQUASHFS_MAGIC 0x73717368 #define SQUASHFS_MAGIC_SWAP 0x68737173 @@ -46,8 +64,9 @@ #define SQUASHFS_NAME_LEN 256 #define SQUASHFS_INVALID ((long long) 0xffffffffffff) -#define SQUASHFS_INVALID_BLK ((long long) 0xffffffff) -#define SQUASHFS_USED_BLK ((long long) 0xfffffffe) +#define SQUASHFS_INVALID_FRAG ((unsigned int) 0xffffffff) +#define SQUASHFS_INVALID_BLK ((long long) -1) +#define SQUASHFS_USED_BLK ((long long) -2) /* Filesystem flags */ #define SQUASHFS_NOI 0 @@ -57,15 +76,34 @@ #define SQUASHFS_NO_FRAG 4 #define SQUASHFS_ALWAYS_FRAG 5 #define SQUASHFS_DUPLICATE 6 + #define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1) -#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, SQUASHFS_NOI) -#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, SQUASHFS_NOD) -#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, SQUASHFS_NOF) -#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, SQUASHFS_NO_FRAG) -#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, SQUASHFS_ALWAYS_FRAG) -#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, SQUASHFS_DUPLICATE) -#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, SQUASHFS_CHECK) -#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, duplicate_checking) (noi | (nod << 1) | (check_data << 2) | (nof << 3) | (no_frag << 4) | (always_frag << 5) | (duplicate_checking << 6)) + +#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_NOI) + +#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_NOD) + +#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_NOF) + +#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_NO_FRAG) + +#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_ALWAYS_FRAG) + +#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_DUPLICATE) + +#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_CHECK) + +#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \ + duplicate_checking) (noi | (nod << 1) | (check_data << 2) \ + | (nof << 3) | (no_frag << 4) | (always_frag << 5) | \ + (duplicate_checking << 6)) /* Max number of types and file types */ #define SQUASHFS_DIR_TYPE 1 @@ -75,73 +113,114 @@ #define SQUASHFS_CHRDEV_TYPE 5 #define SQUASHFS_FIFO_TYPE 6 #define SQUASHFS_SOCKET_TYPE 7 +#define SQUASHFS_LDIR_TYPE 8 +#define SQUASHFS_LREG_TYPE 9 /* 1.0 filesystem type definitions */ #define SQUASHFS_TYPES 5 #define SQUASHFS_IPC_TYPE 0 -/* Flag whether block is compressed or uncompressed, bit is set if block is uncompressed */ +/* Flag whether block is compressed or uncompressed, bit is set if block is + * uncompressed */ #define SQUASHFS_COMPRESSED_BIT (1 << 15) + #define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \ - (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT) + (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT) #define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT)) #define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24) -#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) (((B) & ~SQUASHFS_COMPRESSED_BIT_BLOCK) ? \ - (B) & ~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK) -#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK)) +#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) (((B) & \ + ~SQUASHFS_COMPRESSED_BIT_BLOCK) ? (B) & \ + ~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK) + +#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK)) /* - * Inode number ops. Inodes consist of a compressed block number, and an uncompressed - * offset within that block + * Inode number ops. Inodes consist of a compressed block number, and an + * uncompressed offset within that block */ #define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16)) + #define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff)) -#define SQUASHFS_MKINODE(A, B) ((squashfs_inode)(((squashfs_inode) (A) << 16)\ - + (B))) + +#define SQUASHFS_MKINODE(A, B) ((squashfs_inode_t)(((squashfs_inode_t) (A)\ + << 16) + (B))) /* Compute 32 bit VFS inode number from squashfs inode number */ -#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + ((b) >> 2) + 1)) +#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + \ + ((b) >> 2) + 1)) +/* XXX */ /* Translate between VFS mode and squashfs mode */ #define SQUASHFS_MODE(a) ((a) & 0xfff) /* fragment and fragment table defines */ -typedef unsigned int squashfs_fragment_index; -#define SQUASHFS_FRAGMENT_BYTES(A) (A * sizeof(squashfs_fragment_entry)) -#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / SQUASHFS_METADATA_SIZE) -#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % SQUASHFS_METADATA_SIZE) -#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + SQUASHFS_METADATA_SIZE - 1) / SQUASHFS_METADATA_SIZE) -#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) * sizeof(squashfs_fragment_index)) -#define SQUASHFS_CACHED_FRAGMENTS 3 +#define SQUASHFS_FRAGMENT_BYTES(A) (A * sizeof(struct squashfs_fragment_entry)) + +#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \ + SQUASHFS_METADATA_SIZE - 1) / \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\ + sizeof(long long)) /* cached data constants for filesystem */ #define SQUASHFS_CACHED_BLKS 8 -#define SQUASHFS_MAX_FILE_SIZE_LOG 32 -#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << (SQUASHFS_MAX_FILE_SIZE_LOG - 1)) +#define SQUASHFS_MAX_FILE_SIZE_LOG 64 + +#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << \ + (SQUASHFS_MAX_FILE_SIZE_LOG - 2)) #define SQUASHFS_MARKER_BYTE 0xff +/* meta index cache */ +#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int)) +#define SQUASHFS_META_ENTRIES 31 +#define SQUASHFS_META_NUMBER 8 +#define SQUASHFS_SLOTS 4 + +struct meta_entry { + long long data_block; + unsigned int index_block; + unsigned short offset; + unsigned short pad; +}; + +struct meta_index { + unsigned int inode_number; + unsigned int offset; + unsigned short entries; + unsigned short skip; + unsigned short locked; + unsigned short pad; + struct meta_entry meta_entry[SQUASHFS_META_ENTRIES]; +}; + + /* * definitions for structures on disk */ -typedef unsigned int squashfs_block; -typedef long long squashfs_inode; - -typedef unsigned int squashfs_uid; +typedef long long squashfs_block_t; +typedef long long squashfs_inode_t; -typedef struct squashfs_super_block { +struct squashfs_super_block { unsigned int s_magic; unsigned int inodes; - unsigned int bytes_used; - unsigned int uid_start; - unsigned int guid_start; - unsigned int inode_table_start; - unsigned int directory_table_start; + unsigned int bytes_used_2; + unsigned int uid_start_2; + unsigned int guid_start_2; + unsigned int inode_table_start_2; + unsigned int directory_table_start_2; unsigned int s_major:16; unsigned int s_minor:16; unsigned int block_size_1:16; @@ -150,88 +229,125 @@ typedef struct squashfs_super_block { unsigned int no_uids:8; unsigned int no_guids:8; unsigned int mkfs_time /* time of filesystem creation */; - squashfs_inode root_inode; + squashfs_inode_t root_inode; unsigned int block_size; unsigned int fragments; - unsigned int fragment_table_start; -} __attribute__ ((packed)) squashfs_super_block; - -typedef struct { - unsigned int inode_type:4; - unsigned int mode:12; /* protection */ - unsigned int uid:8; /* index into uid table */ - unsigned int guid:8; /* index into guid table */ -} __attribute__ ((packed)) squashfs_base_inode_header; - -typedef squashfs_base_inode_header squashfs_ipc_inode_header; - -typedef struct { - unsigned int inode_type:4; - unsigned int mode:12; /* protection */ - unsigned int uid:8; /* index into uid table */ - unsigned int guid:8; /* index into guid table */ + unsigned int fragment_table_start_2; + long long bytes_used; + long long uid_start; + long long guid_start; + long long inode_table_start; + long long directory_table_start; + long long fragment_table_start; + long long unused; +} __attribute__ ((packed)); + +struct squashfs_dir_index { + unsigned int index; + unsigned int start_block; + unsigned char size; + unsigned char name[0]; +} __attribute__ ((packed)); + +#define SQUASHFS_BASE_INODE_HEADER \ + unsigned int inode_type:4; \ + unsigned int mode:12; \ + unsigned int uid:8; \ + unsigned int guid:8; \ + unsigned int mtime; \ + unsigned int inode_number; + +struct squashfs_base_inode_header { + SQUASHFS_BASE_INODE_HEADER; +} __attribute__ ((packed)); + +struct squashfs_ipc_inode_header { + SQUASHFS_BASE_INODE_HEADER; + unsigned int nlink; +} __attribute__ ((packed)); + +struct squashfs_dev_inode_header { + SQUASHFS_BASE_INODE_HEADER; + unsigned int nlink; unsigned short rdev; -} __attribute__ ((packed)) squashfs_dev_inode_header; +} __attribute__ ((packed)); -typedef struct { - unsigned int inode_type:4; - unsigned int mode:12; /* protection */ - unsigned int uid:8; /* index into uid table */ - unsigned int guid:8; /* index into guid table */ +struct squashfs_symlink_inode_header { + SQUASHFS_BASE_INODE_HEADER; + unsigned int nlink; unsigned short symlink_size; char symlink[0]; -} __attribute__ ((packed)) squashfs_symlink_inode_header; +} __attribute__ ((packed)); -typedef struct { - unsigned int inode_type:4; - unsigned int mode:12; /* protection */ - unsigned int uid:8; /* index into uid table */ - unsigned int guid:8; /* index into guid table */ - unsigned int mtime; - squashfs_block start_block; +struct squashfs_reg_inode_header { + SQUASHFS_BASE_INODE_HEADER; + squashfs_block_t start_block; unsigned int fragment; unsigned int offset; - unsigned int file_size:SQUASHFS_MAX_FILE_SIZE_LOG; + unsigned int file_size; unsigned short block_list[0]; -} __attribute__ ((packed)) squashfs_reg_inode_header; +} __attribute__ ((packed)); -typedef struct { - unsigned int inode_type:4; - unsigned int mode:12; /* protection */ - unsigned int uid:8; /* index into uid table */ - unsigned int guid:8; /* index into guid table */ +struct squashfs_lreg_inode_header { + SQUASHFS_BASE_INODE_HEADER; + unsigned int nlink; + squashfs_block_t start_block; + unsigned int fragment; + unsigned int offset; + long long file_size; + unsigned short block_list[0]; +} __attribute__ ((packed)); + +struct squashfs_dir_inode_header { + SQUASHFS_BASE_INODE_HEADER; + unsigned int nlink; unsigned int file_size:19; unsigned int offset:13; - unsigned int mtime; - unsigned int start_block:24; -} __attribute__ ((packed)) squashfs_dir_inode_header; - -typedef union { - squashfs_base_inode_header base; - squashfs_dev_inode_header dev; - squashfs_symlink_inode_header symlink; - squashfs_reg_inode_header reg; - squashfs_dir_inode_header dir; - squashfs_ipc_inode_header ipc; -} squashfs_inode_header; + unsigned int start_block; + unsigned int parent_inode; +} __attribute__ ((packed)); + +struct squashfs_ldir_inode_header { + SQUASHFS_BASE_INODE_HEADER; + unsigned int nlink; + unsigned int file_size:27; + unsigned int offset:13; + unsigned int start_block; + unsigned int i_count:16; + unsigned int parent_inode; + struct squashfs_dir_index index[0]; +} __attribute__ ((packed)); + +union squashfs_inode_header { + struct squashfs_base_inode_header base; + struct squashfs_dev_inode_header dev; + struct squashfs_symlink_inode_header symlink; + struct squashfs_reg_inode_header reg; + struct squashfs_lreg_inode_header lreg; + struct squashfs_dir_inode_header dir; + struct squashfs_ldir_inode_header ldir; + struct squashfs_ipc_inode_header ipc; +}; -typedef struct { +struct squashfs_dir_entry { unsigned int offset:13; unsigned int type:3; unsigned int size:8; + int inode_number:16; char name[0]; -} __attribute__ ((packed)) squashfs_dir_entry; +} __attribute__ ((packed)); -typedef struct { +struct squashfs_dir_header { unsigned int count:8; - unsigned int start_block:24; -} __attribute__ ((packed)) squashfs_dir_header; - - -typedef struct { unsigned int start_block; + unsigned int inode_number; +} __attribute__ ((packed)); + +struct squashfs_fragment_entry { + long long start_block; unsigned int size; -} __attribute__ ((packed)) squashfs_fragment_entry; + unsigned int unused; +} __attribute__ ((packed)); extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen); extern int squashfs_uncompress_init(void); @@ -239,20 +355,28 @@ extern int squashfs_uncompress_exit(void); /* * macros to convert each packed bitfield structure from little endian to big - * endian and vice versa. These are needed when creating or using a filesystem on a - * machine with different byte ordering to the target architecture. + * endian and vice versa. These are needed when creating or using a filesystem + * on a machine with different byte ordering to the target architecture. * */ +#define SQUASHFS_SWAP_START \ + int bits;\ + int b_pos;\ + unsigned long long val;\ + unsigned char *s;\ + unsigned char *d; + #define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\ - SQUASHFS_MEMSET(s, d, sizeof(squashfs_super_block));\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\ SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\ SQUASHFS_SWAP((s)->inodes, d, 32, 32);\ - SQUASHFS_SWAP((s)->bytes_used, d, 64, 32);\ - SQUASHFS_SWAP((s)->uid_start, d, 96, 32);\ - SQUASHFS_SWAP((s)->guid_start, d, 128, 32);\ - SQUASHFS_SWAP((s)->inode_table_start, d, 160, 32);\ - SQUASHFS_SWAP((s)->directory_table_start, d, 192, 32);\ + SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\ + SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\ + SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\ + SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\ + SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\ SQUASHFS_SWAP((s)->s_major, d, 224, 16);\ SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\ SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\ @@ -264,137 +388,218 @@ extern int squashfs_uncompress_exit(void); SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\ SQUASHFS_SWAP((s)->block_size, d, 408, 32);\ SQUASHFS_SWAP((s)->fragments, d, 440, 32);\ - SQUASHFS_SWAP((s)->fragment_table_start, d, 472, 32);\ + SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\ + SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\ + SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\ + SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\ + SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\ + SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\ + SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\ + SQUASHFS_SWAP((s)->unused, d, 888, 64);\ } -#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\ +#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\ SQUASHFS_MEMSET(s, d, n);\ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ SQUASHFS_SWAP((s)->uid, d, 16, 8);\ SQUASHFS_SWAP((s)->guid, d, 24, 8);\ + SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ + SQUASHFS_SWAP((s)->inode_number, d, 64, 32); + +#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\ } -#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_ipc_inode_header)) +#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ + sizeof(struct squashfs_ipc_inode_header))\ + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ +} #define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\ - SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dev_inode_header));\ - SQUASHFS_SWAP((s)->rdev, d, 32, 16);\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ + sizeof(struct squashfs_dev_inode_header)); \ + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ + SQUASHFS_SWAP((s)->rdev, d, 128, 16);\ } #define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\ - SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_symlink_inode_header));\ - SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ + sizeof(struct squashfs_symlink_inode_header));\ + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ + SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\ } #define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\ - SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_reg_inode_header));\ - SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ - SQUASHFS_SWAP((s)->start_block, d, 64, 32);\ - SQUASHFS_SWAP((s)->fragment, d, 96, 32);\ - SQUASHFS_SWAP((s)->offset, d, 128, 32);\ - SQUASHFS_SWAP((s)->file_size, d, 160, SQUASHFS_MAX_FILE_SIZE_LOG);\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ + sizeof(struct squashfs_reg_inode_header));\ + SQUASHFS_SWAP((s)->start_block, d, 96, 64);\ + SQUASHFS_SWAP((s)->fragment, d, 160, 32);\ + SQUASHFS_SWAP((s)->offset, d, 192, 32);\ + SQUASHFS_SWAP((s)->file_size, d, 224, 32);\ +} + +#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ + sizeof(struct squashfs_lreg_inode_header));\ + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 128, 64);\ + SQUASHFS_SWAP((s)->fragment, d, 192, 32);\ + SQUASHFS_SWAP((s)->offset, d, 224, 32);\ + SQUASHFS_SWAP((s)->file_size, d, 256, 64);\ } #define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\ - SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dir_inode_header));\ - SQUASHFS_SWAP((s)->file_size, d, 32, 19);\ - SQUASHFS_SWAP((s)->offset, d, 51, 13);\ - SQUASHFS_SWAP((s)->mtime, d, 64, 32);\ - SQUASHFS_SWAP((s)->start_block, d, 96, 24);\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ + sizeof(struct squashfs_dir_inode_header));\ + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ + SQUASHFS_SWAP((s)->file_size, d, 128, 19);\ + SQUASHFS_SWAP((s)->offset, d, 147, 13);\ + SQUASHFS_SWAP((s)->start_block, d, 160, 32);\ + SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\ +} + +#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ + sizeof(struct squashfs_ldir_inode_header));\ + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ + SQUASHFS_SWAP((s)->file_size, d, 128, 27);\ + SQUASHFS_SWAP((s)->offset, d, 155, 13);\ + SQUASHFS_SWAP((s)->start_block, d, 168, 32);\ + SQUASHFS_SWAP((s)->i_count, d, 200, 16);\ + SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\ +} + +#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\ + SQUASHFS_SWAP((s)->index, d, 0, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 32, 32);\ + SQUASHFS_SWAP((s)->size, d, 64, 8);\ } #define SQUASHFS_SWAP_DIR_HEADER(s, d) {\ - SQUASHFS_MEMSET(s, d, sizeof(squashfs_dir_header));\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\ SQUASHFS_SWAP((s)->count, d, 0, 8);\ - SQUASHFS_SWAP((s)->start_block, d, 8, 24);\ + SQUASHFS_SWAP((s)->start_block, d, 8, 32);\ + SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\ } #define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\ - SQUASHFS_MEMSET(s, d, sizeof(squashfs_dir_entry));\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\ SQUASHFS_SWAP((s)->offset, d, 0, 13);\ SQUASHFS_SWAP((s)->type, d, 13, 3);\ SQUASHFS_SWAP((s)->size, d, 16, 8);\ + SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\ } #define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\ - SQUASHFS_MEMSET(s, d, sizeof(squashfs_fragment_entry));\ - SQUASHFS_SWAP((s)->start_block, d, 0, 32);\ - SQUASHFS_SWAP((s)->size, d, 32, 32);\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\ + SQUASHFS_SWAP((s)->start_block, d, 0, 64);\ + SQUASHFS_SWAP((s)->size, d, 64, 32);\ } #define SQUASHFS_SWAP_SHORTS(s, d, n) {\ int entry;\ int bit_position;\ + SQUASHFS_SWAP_START\ SQUASHFS_MEMSET(s, d, n * 2);\ - for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += 16)\ + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ + 16)\ SQUASHFS_SWAP(s[entry], d, bit_position, 16);\ } #define SQUASHFS_SWAP_INTS(s, d, n) {\ int entry;\ int bit_position;\ + SQUASHFS_SWAP_START\ SQUASHFS_MEMSET(s, d, n * 4);\ - for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += 32)\ + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ + 32)\ SQUASHFS_SWAP(s[entry], d, bit_position, 32);\ } +#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\ + int entry;\ + int bit_position;\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, n * 8);\ + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ + 64)\ + SQUASHFS_SWAP(s[entry], d, bit_position, 64);\ +} + #define SQUASHFS_SWAP_DATA(s, d, n, bits) {\ int entry;\ int bit_position;\ + SQUASHFS_SWAP_START\ SQUASHFS_MEMSET(s, d, n * bits / 8);\ - for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += bits)\ + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ + bits)\ SQUASHFS_SWAP(s[entry], d, bit_position, bits);\ } -#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_INTS(s, d, n) +#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n) -#ifdef SQUASHFS_1_0_COMPATIBILITY -typedef struct { +#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY + +struct squashfs_base_inode_header_1 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:4; /* index into uid table */ unsigned int guid:4; /* index into guid table */ -} __attribute__ ((packed)) squashfs_base_inode_header_1; +} __attribute__ ((packed)); -typedef struct { +struct squashfs_ipc_inode_header_1 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:4; /* index into uid table */ unsigned int guid:4; /* index into guid table */ unsigned int type:4; unsigned int offset:4; -} __attribute__ ((packed)) squashfs_ipc_inode_header_1; +} __attribute__ ((packed)); -typedef struct { +struct squashfs_dev_inode_header_1 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:4; /* index into uid table */ unsigned int guid:4; /* index into guid table */ unsigned short rdev; -} __attribute__ ((packed)) squashfs_dev_inode_header_1; +} __attribute__ ((packed)); -typedef struct { +struct squashfs_symlink_inode_header_1 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:4; /* index into uid table */ unsigned int guid:4; /* index into guid table */ unsigned short symlink_size; char symlink[0]; -} __attribute__ ((packed)) squashfs_symlink_inode_header_1; +} __attribute__ ((packed)); -typedef struct { +struct squashfs_reg_inode_header_1 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:4; /* index into uid table */ unsigned int guid:4; /* index into guid table */ unsigned int mtime; - squashfs_block start_block; - unsigned int file_size:SQUASHFS_MAX_FILE_SIZE_LOG; + unsigned int start_block; + unsigned int file_size:32; unsigned short block_list[0]; -} __attribute__ ((packed)) squashfs_reg_inode_header_1; +} __attribute__ ((packed)); -typedef struct { +struct squashfs_dir_inode_header_1 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:4; /* index into uid table */ @@ -403,72 +608,308 @@ typedef struct { unsigned int offset:13; unsigned int mtime; unsigned int start_block:24; -} __attribute__ ((packed)) squashfs_dir_inode_header_1; +} __attribute__ ((packed)); -#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\ +#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \ SQUASHFS_MEMSET(s, d, n);\ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ SQUASHFS_SWAP((s)->uid, d, 16, 4);\ - SQUASHFS_SWAP((s)->guid, d, 20, 4);\ + SQUASHFS_SWAP((s)->guid, d, 20, 4); + +#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\ } #define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\ - SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, sizeof(squashfs_ipc_inode_header_1));\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ + sizeof(struct squashfs_ipc_inode_header_1));\ SQUASHFS_SWAP((s)->type, d, 24, 4);\ SQUASHFS_SWAP((s)->offset, d, 28, 4);\ } #define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\ - SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, sizeof(squashfs_dev_inode_header_1));\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ + sizeof(struct squashfs_dev_inode_header_1));\ SQUASHFS_SWAP((s)->rdev, d, 24, 16);\ } #define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\ - SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_symlink_inode_header_1));\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ + sizeof(struct squashfs_symlink_inode_header_1));\ SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\ } #define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\ - SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_reg_inode_header_1));\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ + sizeof(struct squashfs_reg_inode_header_1));\ SQUASHFS_SWAP((s)->mtime, d, 24, 32);\ SQUASHFS_SWAP((s)->start_block, d, 56, 32);\ - SQUASHFS_SWAP((s)->file_size, d, 88, SQUASHFS_MAX_FILE_SIZE_LOG);\ + SQUASHFS_SWAP((s)->file_size, d, 88, 32);\ } #define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\ - SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dir_inode_header_1));\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ + sizeof(struct squashfs_dir_inode_header_1));\ SQUASHFS_SWAP((s)->file_size, d, 24, 19);\ SQUASHFS_SWAP((s)->offset, d, 43, 13);\ SQUASHFS_SWAP((s)->mtime, d, 56, 32);\ SQUASHFS_SWAP((s)->start_block, d, 88, 24);\ } + +#endif + +#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY + +struct squashfs_dir_index_2 { + unsigned int index:27; + unsigned int start_block:29; + unsigned char size; + unsigned char name[0]; +} __attribute__ ((packed)); + +struct squashfs_base_inode_header_2 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ +} __attribute__ ((packed)); + +struct squashfs_ipc_inode_header_2 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ +} __attribute__ ((packed)); + +struct squashfs_dev_inode_header_2 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ + unsigned short rdev; +} __attribute__ ((packed)); + +struct squashfs_symlink_inode_header_2 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ + unsigned short symlink_size; + char symlink[0]; +} __attribute__ ((packed)); + +struct squashfs_reg_inode_header_2 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ + unsigned int mtime; + unsigned int start_block; + unsigned int fragment; + unsigned int offset; + unsigned int file_size:32; + unsigned short block_list[0]; +} __attribute__ ((packed)); + +struct squashfs_dir_inode_header_2 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ + unsigned int file_size:19; + unsigned int offset:13; + unsigned int mtime; + unsigned int start_block:24; +} __attribute__ ((packed)); + +struct squashfs_ldir_inode_header_2 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ + unsigned int file_size:27; + unsigned int offset:13; + unsigned int mtime; + unsigned int start_block:24; + unsigned int i_count:16; + struct squashfs_dir_index_2 index[0]; +} __attribute__ ((packed)); + +union squashfs_inode_header_2 { + struct squashfs_base_inode_header_2 base; + struct squashfs_dev_inode_header_2 dev; + struct squashfs_symlink_inode_header_2 symlink; + struct squashfs_reg_inode_header_2 reg; + struct squashfs_dir_inode_header_2 dir; + struct squashfs_ldir_inode_header_2 ldir; + struct squashfs_ipc_inode_header_2 ipc; +}; + +struct squashfs_dir_header_2 { + unsigned int count:8; + unsigned int start_block:24; +} __attribute__ ((packed)); + +struct squashfs_dir_entry_2 { + unsigned int offset:13; + unsigned int type:3; + unsigned int size:8; + char name[0]; +} __attribute__ ((packed)); + +struct squashfs_fragment_entry_2 { + unsigned int start_block; + unsigned int size; +} __attribute__ ((packed)); + +#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\ + SQUASHFS_MEMSET(s, d, n);\ + SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ + SQUASHFS_SWAP((s)->mode, d, 4, 12);\ + SQUASHFS_SWAP((s)->uid, d, 16, 8);\ + SQUASHFS_SWAP((s)->guid, d, 24, 8);\ + +#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\ +} + +#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \ + SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2)) + +#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ + sizeof(struct squashfs_dev_inode_header_2)); \ + SQUASHFS_SWAP((s)->rdev, d, 32, 16);\ +} + +#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ + sizeof(struct squashfs_symlink_inode_header_2));\ + SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\ +} + +#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ + sizeof(struct squashfs_reg_inode_header_2));\ + SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 64, 32);\ + SQUASHFS_SWAP((s)->fragment, d, 96, 32);\ + SQUASHFS_SWAP((s)->offset, d, 128, 32);\ + SQUASHFS_SWAP((s)->file_size, d, 160, 32);\ +} + +#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ + sizeof(struct squashfs_dir_inode_header_2));\ + SQUASHFS_SWAP((s)->file_size, d, 32, 19);\ + SQUASHFS_SWAP((s)->offset, d, 51, 13);\ + SQUASHFS_SWAP((s)->mtime, d, 64, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 96, 24);\ +} + +#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ + sizeof(struct squashfs_ldir_inode_header_2));\ + SQUASHFS_SWAP((s)->file_size, d, 32, 27);\ + SQUASHFS_SWAP((s)->offset, d, 59, 13);\ + SQUASHFS_SWAP((s)->mtime, d, 72, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 104, 24);\ + SQUASHFS_SWAP((s)->i_count, d, 128, 16);\ +} + +#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\ + SQUASHFS_SWAP((s)->index, d, 0, 27);\ + SQUASHFS_SWAP((s)->start_block, d, 27, 29);\ + SQUASHFS_SWAP((s)->size, d, 56, 8);\ +} +#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\ + SQUASHFS_SWAP((s)->count, d, 0, 8);\ + SQUASHFS_SWAP((s)->start_block, d, 8, 24);\ +} + +#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\ + SQUASHFS_SWAP((s)->offset, d, 0, 13);\ + SQUASHFS_SWAP((s)->type, d, 13, 3);\ + SQUASHFS_SWAP((s)->size, d, 16, 8);\ +} + +#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\ + SQUASHFS_SWAP((s)->start_block, d, 0, 32);\ + SQUASHFS_SWAP((s)->size, d, 32, 32);\ +} + +#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n) + +/* fragment and fragment table defines */ +#define SQUASHFS_FRAGMENT_BYTES_2(A) (A * sizeof(struct squashfs_fragment_entry_2)) + +#define SQUASHFS_FRAGMENT_INDEX_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) / \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) % \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_FRAGMENT_INDEXES_2(A) ((SQUASHFS_FRAGMENT_BYTES_2(A) + \ + SQUASHFS_METADATA_SIZE - 1) / \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A) (SQUASHFS_FRAGMENT_INDEXES_2(A) *\ + sizeof(int)) + #endif #ifdef __KERNEL__ + /* * macros used to swap each structure entry, taking into account - * bitfields and different bitfield placing conventions on differing architectures + * bitfields and different bitfield placing conventions on differing + * architectures */ + #include <asm/byteorder.h> + #ifdef __BIG_ENDIAN /* convert from little endian to big endian */ -#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, b_pos) +#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \ + tbits, b_pos) #else /* convert from big endian to little endian */ -#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, 64 - tbits - b_pos) +#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \ + tbits, 64 - tbits - b_pos) #endif #define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\ - int bits;\ - int b_pos = pos % 8;\ - unsigned long long val = 0;\ - unsigned char *s = (unsigned char *)p + (pos / 8);\ - unsigned char *d = ((unsigned char *) &val) + 7;\ + b_pos = pos % 8;\ + val = 0;\ + s = (unsigned char *)p + (pos / 8);\ + d = ((unsigned char *) &val) + 7;\ for(bits = 0; bits < (tbits + b_pos); bits += 8) \ *d-- = *s++;\ value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\ } + #define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n); + #endif #endif diff --git a/release/src/linux/linux/include/linux/squashfs_fs_i.h b/release/src/linux/linux/include/linux/squashfs_fs_i.h index 47043b37..0fe28cc4 100644 --- a/release/src/linux/linux/include/linux/squashfs_fs_i.h +++ b/release/src/linux/linux/include/linux/squashfs_fs_i.h @@ -3,7 +3,8 @@ /* * Squashfs * - * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.net> + * Copyright (c) 2002, 2003, 2004, 2005, 2006 + * Phillip Lougher <phillip@lougher.org.uk> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -22,12 +23,22 @@ * squashfs_fs_i.h */ -typedef struct squashfs_inode_info { - unsigned int start_block; - unsigned int block_list_start; +struct squashfs_inode_info { + long long start_block; unsigned int offset; - unsigned int fragment_start_block; - unsigned int fragment_size; - unsigned int fragment_offset; - } squashfs_inode_info; + union { + struct { + long long fragment_start_block; + unsigned int fragment_size; + unsigned int fragment_offset; + long long block_list_start; + } s1; + struct { + long long directory_index_start; + unsigned int directory_index_offset; + unsigned int directory_index_count; + unsigned int parent_inode; + } s2; + } u; +}; #endif diff --git a/release/src/linux/linux/include/linux/squashfs_fs_sb.h b/release/src/linux/linux/include/linux/squashfs_fs_sb.h index 6ce5e228..9ea7a11c 100644 --- a/release/src/linux/linux/include/linux/squashfs_fs_sb.h +++ b/release/src/linux/linux/include/linux/squashfs_fs_sb.h @@ -3,7 +3,8 @@ /* * Squashfs * - * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.net> + * Copyright (c) 2002, 2003, 2004, 2005, 2006 + * Phillip Lougher <phillip@lougher.org.uk> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -24,42 +25,50 @@ #include <linux/squashfs_fs.h> -typedef struct { - unsigned int block; +struct squashfs_cache { + long long block; int length; - unsigned int next_index; + long long next_index; char *data; - } squashfs_cache; +}; struct squashfs_fragment_cache { - unsigned int block; + long long block; int length; unsigned int locked; char *data; - }; +}; -typedef struct squashfs_sb_info { - squashfs_super_block sBlk; +struct squashfs_sb_info { + struct squashfs_super_block sblk; int devblksize; int devblksize_log2; int swap; - squashfs_cache *block_cache; + struct squashfs_cache *block_cache; struct squashfs_fragment_cache *fragment; int next_cache; int next_fragment; - squashfs_uid *uid; - squashfs_uid *guid; - squashfs_fragment_index *fragment_index; + int next_meta_index; + unsigned int *uid; + unsigned int *guid; + long long *fragment_index; + unsigned int *fragment_index_2; unsigned int read_size; char *read_data; char *read_page; + struct semaphore read_data_mutex; struct semaphore read_page_mutex; struct semaphore block_cache_mutex; struct semaphore fragment_mutex; + struct semaphore meta_index_mutex; wait_queue_head_t waitq; wait_queue_head_t fragment_wait_queue; - struct inode *(*iget)(struct super_block *s, squashfs_inode inode); - unsigned int (*read_blocklist)(struct inode *inode, int index, int readahead_blks, - char *block_list, char **block_p, unsigned int *bsize); - } squashfs_sb_info; + struct meta_index *meta_index; + struct inode *(*iget)(struct super_block *s, squashfs_inode_t \ + inode); + long long (*read_blocklist)(struct inode *inode, int \ + index, int readahead_blks, char *block_list, \ + unsigned short **block_p, unsigned int *bsize); + int (*read_fragment_index_table)(struct super_block *s); +}; #endif diff --git a/release/src/linux/linux/include/linux/sysctl.h b/release/src/linux/linux/include/linux/sysctl.h index ef417f6b..5742f382 100644 --- a/release/src/linux/linux/include/linux/sysctl.h +++ b/release/src/linux/linux/include/linux/sysctl.h @@ -292,7 +292,11 @@ enum NET_IPV4_NONLOCAL_BIND=88, NET_IPV4_ICMP_RATELIMIT=89, NET_IPV4_ICMP_RATEMASK=90, - NET_TCP_TW_REUSE=91 + NET_TCP_TW_REUSE=91, + NET_TCP_VEGAS=92, + NET_TCP_VEGAS_ALPHA=93, + NET_TCP_VEGAS_BETA=94, + NET_TCP_VEGAS_GAMMA=95 }; enum { diff --git a/release/src/linux/linux/include/net/pkt_cls.h b/release/src/linux/linux/include/net/pkt_cls.h index cb2bde23..0926f823 100644 --- a/release/src/linux/linux/include/net/pkt_cls.h +++ b/release/src/linux/linux/include/net/pkt_cls.h @@ -77,7 +77,11 @@ static inline int tc_classify(struct sk_buff *skb, struct tcf_proto *tp, struct return -1; } - +static inline void tcf_destroy(struct tcf_proto *tp) +{ + tp->ops->destroy(tp); + kfree(tp); +} extern int register_tcf_proto_ops(struct tcf_proto_ops *ops); extern int unregister_tcf_proto_ops(struct tcf_proto_ops *ops); diff --git a/release/src/linux/linux/include/net/pkt_sched.h b/release/src/linux/linux/include/net/pkt_sched.h index a9027b90..7b91dac6 100644 --- a/release/src/linux/linux/include/net/pkt_sched.h +++ b/release/src/linux/linux/include/net/pkt_sched.h @@ -198,6 +198,7 @@ typedef long psched_tdiff_t; #define PSCHED_GET_TIME(stamp) do_gettimeofday(&(stamp)) #define PSCHED_US2JIFFIE(usecs) (((usecs)+(1000000/HZ-1))/(1000000/HZ)) +#define PSCHED_JIFFIE2US(delay) ((delay)*(1000000/HZ)) #define PSCHED_EXPORTLIST EXPORT_SYMBOL(psched_tod_diff); @@ -212,12 +213,16 @@ extern psched_time_t psched_time_base; #if PSCHED_CLOCK_SOURCE == PSCHED_JIFFIES -#if HZ == 100 +#if HZ < 96 +#define PSCHED_JSCALE 14 +#elif HZ >= 96 && HZ < 192 #define PSCHED_JSCALE 13 -#elif HZ == 1024 +#elif HZ >= 192 && HZ < 384 +#define PSCHED_JSCALE 12 +#elif HZ >= 384 && HZ < 768 +#define PSCHED_JSCALE 11 +#elif HZ >= 768 #define PSCHED_JSCALE 10 -#else -#define PSCHED_JSCALE 0 #endif #define PSCHED_EXPORTLIST_2 @@ -242,6 +247,7 @@ extern PSCHED_WATCHER psched_time_mark; #endif #define PSCHED_US2JIFFIE(delay) (((delay)+(1<<PSCHED_JSCALE)-1)>>PSCHED_JSCALE) +#define PSCHED_JIFFIE2US(delay) ((delay)<<PSCHED_JSCALE) #elif PSCHED_CLOCK_SOURCE == PSCHED_CPU @@ -252,6 +258,7 @@ extern int psched_clock_scale; EXPORT_SYMBOL(psched_clock_scale); #define PSCHED_US2JIFFIE(delay) (((delay)+psched_clock_per_hz-1)/psched_clock_per_hz) +#define PSCHED_JIFFIE2US(delay) ((delay)*psched_clock_per_hz) #ifdef CONFIG_X86_TSC diff --git a/release/src/linux/linux/include/net/sock.h b/release/src/linux/linux/include/net/sock.h index 0482a102..a2824afb 100644 --- a/release/src/linux/linux/include/net/sock.h +++ b/release/src/linux/linux/include/net/sock.h @@ -417,7 +417,19 @@ struct tcp_opt { unsigned int keepalive_intvl; /* time interval between keep alive probes */ int linger2; - unsigned long last_synq_overflow; + unsigned long last_synq_overflow; + +/* Vegas variables */ + struct { + __u32 beg_snd_nxt; /* right edge during last RTT */ + __u32 beg_snd_una; /* left edge during last RTT */ + __u32 beg_snd_cwnd; /* saves the size of the cwnd */ + __u8 do_vegas; /* do vegas for this connection */ + __u8 doing_vegas_now;/* if true, do vegas for this RTT */ + __u16 cntRTT; /* # of RTTs measured within last RTT */ + __u32 minRTT; /* min of RTTs measured within last RTT (in usec) */ + __u32 baseRTT; /* the min of all Vegas RTT measurements seen (in usec) */ + } vegas; }; diff --git a/release/src/linux/linux/include/net/tcp.h b/release/src/linux/linux/include/net/tcp.h index 6571f4b2..e9a9e254 100644 --- a/release/src/linux/linux/include/net/tcp.h +++ b/release/src/linux/linux/include/net/tcp.h @@ -456,6 +456,10 @@ extern int sysctl_tcp_rmem[3]; extern int sysctl_tcp_app_win; extern int sysctl_tcp_adv_win_scale; extern int sysctl_tcp_tw_reuse; +extern int sysctl_tcp_vegas_cong_avoid; +extern int sysctl_tcp_vegas_alpha; +extern int sysctl_tcp_vegas_beta; +extern int sysctl_tcp_vegas_gamma; extern atomic_t tcp_memory_allocated; extern atomic_t tcp_sockets_allocated; @@ -1070,6 +1074,59 @@ static inline __u32 tcp_recalc_ssthresh(struct tcp_opt *tp) return max(tp->snd_cwnd >> 1U, 2U); } +/* Stop taking Vegas samples for now. */ +#define tcp_vegas_disable(__tp) ((__tp)->vegas.doing_vegas_now = 0) + +/* Is this TCP connection using Vegas (regardless of whether it is taking + * Vegas measurements at the current time)? + */ +#define tcp_is_vegas(__tp) ((__tp)->vegas.do_vegas) + +static inline void tcp_vegas_enable(struct tcp_opt *tp) +{ + /* There are several situations when we must "re-start" Vegas: + * + * o when a connection is established + * o after an RTO + * o after fast recovery + * o when we send a packet and there is no outstanding + * unacknowledged data (restarting an idle connection) + * + * In these circumstances we cannot do a Vegas calculation at the + * end of the first RTT, because any calculation we do is using + * stale info -- both the saved cwnd and congestion feedback are + * stale. + * + * Instead we must wait until the completion of an RTT during + * which we actually receive ACKs. + */ + + /* Begin taking Vegas samples next time we send something. */ + tp->vegas.doing_vegas_now = 1; + + /* Set the beginning of the next send window. */ + tp->vegas.beg_snd_nxt = tp->snd_nxt; + + tp->vegas.cntRTT = 0; + tp->vegas.minRTT = 0x7fffffff; +} + +/* Should we be taking Vegas samples right now? */ +#define tcp_vegas_enabled(__tp) ((__tp)->vegas.doing_vegas_now) + +extern void tcp_vegas_init(struct tcp_opt *tp); + +static inline void tcp_set_ca_state(struct tcp_opt *tp, u8 ca_state) +{ + if (tcp_is_vegas(tp)) { + if (ca_state == TCP_CA_Open) + tcp_vegas_enable(tp); + else + tcp_vegas_disable(tp); + } + tp->ca_state = ca_state; +} + /* If cwnd > ssthresh, we may raise ssthresh to be half-way to cwnd. * The exception is rate halving phase, when cwnd is decreasing towards * ssthresh. @@ -1129,7 +1186,7 @@ static inline void tcp_enter_cwr(struct tcp_opt *tp) tp->prior_ssthresh = 0; if (tp->ca_state < TCP_CA_CWR) { __tcp_enter_cwr(tp); - tp->ca_state = TCP_CA_CWR; + tcp_set_ca_state(tp, TCP_CA_CWR); } } diff --git a/release/src/linux/linux/lib/Config.in b/release/src/linux/linux/lib/Config.in index 527477aa..5edba1f5 100644 --- a/release/src/linux/linux/lib/Config.in +++ b/release/src/linux/linux/lib/Config.in @@ -8,14 +8,12 @@ comment 'Library routines' # Do we need the compression support? # if [ "$CONFIG_CRAMFS" = "y" -o \ - "$CONFIG_SQUASHFS" = "y" -o \ "$CONFIG_PPP_DEFLATE" = "y" -o \ "$CONFIG_JFFS2_FS" = "y" -o \ "$CONFIG_ZISOFS_FS" = "y" ]; then define_tristate CONFIG_ZLIB_INFLATE y else if [ "$CONFIG_CRAMFS" = "m" -o \ - "$CONFIG_SQUASHFS" = "m" -o \ "$CONFIG_PPP_DEFLATE" = "m" -o \ "$CONFIG_JFFS2_FS" = "m" -o \ "$CONFIG_ZISOFS_FS" = "m" ]; then diff --git a/release/src/linux/linux/lib/rbtree.c b/release/src/linux/linux/lib/rbtree.c index bed359bd..f941d73e 100644 --- a/release/src/linux/linux/lib/rbtree.c +++ b/release/src/linux/linux/lib/rbtree.c @@ -294,3 +294,76 @@ void rb_erase(rb_node_t * node, rb_root_t * root) __rb_erase_color(child, parent, root); } EXPORT_SYMBOL(rb_erase); + +/* + * This function returns the first node (in sort order) of the tree. + */ +rb_node_t *rb_first(rb_root_t *root) +{ + rb_node_t *n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->rb_left) + n = n->rb_left; + return n; +} +EXPORT_SYMBOL(rb_first); + +rb_node_t *rb_last(rb_root_t *root) +{ + rb_node_t *n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->rb_right) + n = n->rb_right; + return n; +} +EXPORT_SYMBOL(rb_last); + +rb_node_t *rb_next(rb_node_t *node) +{ + /* If we have a right-hand child, go down and then left as far + as we can. */ + if (node->rb_right) { + node = node->rb_right; + while (node->rb_left) + node = node->rb_left; + return node; + } + + /* No right-hand children. Everything down and left is + smaller than us, so any 'next' node must be in the general + direction of our parent. Go up the tree; any time the + ancestor is a right-hand child of its parent, keep going + up. First time it's a left-hand child of its parent, said + parent is our 'next' node. */ + while (node->rb_parent && node == node->rb_parent->rb_right) + node = node->rb_parent; + + return node->rb_parent; +} +EXPORT_SYMBOL(rb_next); + +rb_node_t *rb_prev(rb_node_t *node) +{ + /* If we have a left-hand child, go down and then right as far + as we can. */ + if (node->rb_left) { + node = node->rb_left; + while (node->rb_right) + node = node->rb_right; + return node; + } + + /* No left-hand children. Go up till we find an ancestor which + is a right-hand child of its parent */ + while (node->rb_parent && node == node->rb_parent->rb_left) + node = node->rb_parent; + + return node->rb_parent; +} +EXPORT_SYMBOL(rb_prev); diff --git a/release/src/linux/linux/net/core/skbuff.c b/release/src/linux/linux/net/core/skbuff.c index 57d19374..32476545 100644 --- a/release/src/linux/linux/net/core/skbuff.c +++ b/release/src/linux/linux/net/core/skbuff.c @@ -201,6 +201,10 @@ struct sk_buff *alloc_skb(unsigned int size,int gfp_mask) /* Set up other state */ skb->len = 0; skb->cloned = 0; +#if defined(CONFIG_IMQ) || defined (CONFIG_IMQ_MODULE) + skb->imq_flags = 0; + skb->nf_info = NULL; +#endif skb->data_len = 0; atomic_set(&skb->users, 1); @@ -248,6 +252,10 @@ static inline void skb_headerinit(void *p, kmem_cache_t *cache, #ifdef CONFIG_NET_SCHED skb->tc_index = 0; #endif +#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) + skb->imq_flags = 0; + skb->nf_info = NULL; +#endif } static void skb_drop_fraglist(struct sk_buff *skb) @@ -397,6 +405,10 @@ struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask) #ifdef CONFIG_NET_SCHED C(tc_index); #endif +#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) + C(imq_flags); + C(nf_info); +#endif atomic_inc(&(skb_shinfo(skb)->dataref)); skb->cloned = 1; @@ -440,6 +452,10 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) #ifdef CONFIG_NET_SCHED new->tc_index = old->tc_index; #endif +#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) + new->imq_flags=old->imq_flags; + new->nf_info=old->nf_info; +#endif } /** diff --git a/release/src/linux/linux/net/ipv4/arp.c b/release/src/linux/linux/net/ipv4/arp.c index aecd020a..e458f7d5 100644 --- a/release/src/linux/linux/net/ipv4/arp.c +++ b/release/src/linux/linux/net/ipv4/arp.c @@ -171,8 +171,8 @@ struct neigh_table arp_tbl = { id: "arp_cache", parms: { tbl: &arp_tbl, - /*zhijian 2006-10-23 modify to solve arp entry timeout problem(cdrouter3.3 scaling module)*/ - #if 0 +/*zhijian 2006-10-23 modify to solve arp entry timeout problem(cdrouter3.3 scaling module)*/ +#if 0 base_reachable_time: 30 * HZ, retrans_time: 1 * HZ, gc_staletime: 60 * HZ, @@ -181,16 +181,16 @@ struct neigh_table arp_tbl = { queue_len: 3, ucast_probes: 3, mcast_probes: 3, - #else - base_reachable_time: 60 * HZ, - retrans_time: 5 * HZ, - gc_staletime: 120 * HZ, - reachable_time: 60 * HZ, - delay_probe_time: 10 * HZ, - queue_len: 3, - ucast_probes: 6, - mcast_probes: 6, - #endif +#else + base_reachable_time: 60 * HZ, + retrans_time: 5 * HZ, + gc_staletime: 120 * HZ, + reachable_time: 60 * HZ, + delay_probe_time: 10 * HZ, + queue_len: 3, + ucast_probes: 6, + mcast_probes: 6, +#endif anycast_delay: 1 * HZ, proxy_delay: (8 * HZ) / 10, proxy_qlen: 64, diff --git a/release/src/linux/linux/net/ipv4/igmp.c b/release/src/linux/linux/net/ipv4/igmp.c index 3f718f2a..c53d8feb 100644 --- a/release/src/linux/linux/net/ipv4/igmp.c +++ b/release/src/linux/linux/net/ipv4/igmp.c @@ -677,8 +677,9 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) count++; } err = -ENOBUFS; - //if (iml == NULL || count >= sysctl_igmp_max_memberships) - if (iml == NULL || count > sysctl_igmp_max_memberships)// modify for cdrouter v3.3 item 300(cdrouter_mcast_100) bug + // if (iml == NULL || count >= sysctl_igmp_max_memberships) + // 43011: modify for cdrouter v3.3 item 300(cdrouter_mcast_100) bug + if (iml == NULL || count > sysctl_igmp_max_memberships) goto done; memcpy(&iml->multi, imr, sizeof(*imr)); iml->next = sk->protinfo.af_inet.mc_list; diff --git a/release/src/linux/linux/net/ipv4/netfilter/Config.in b/release/src/linux/linux/net/ipv4/netfilter/Config.in index 7662305e..b1f7f985 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/Config.in +++ b/release/src/linux/linux/net/ipv4/netfilter/Config.in @@ -7,16 +7,17 @@ comment ' IP: Netfilter Configuration' tristate 'Connection tracking (required for masq/NAT)' CONFIG_IP_NF_CONNTRACK if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then dep_tristate ' FTP protocol support' CONFIG_IP_NF_FTP $CONFIG_IP_NF_CONNTRACK - dep_tristate ' TFTP protocol support' CONFIG_IP_NF_TFTP $CONFIG_IP_NF_CONNTRACK + bool ' Connection mark tracking support' CONFIG_IP_NF_CONNTRACK_MARK dep_tristate ' H.323 (netmeeting) support' CONFIG_IP_NF_H323 $CONFIG_IP_NF_CONNTRACK + dep_tristate ' TFTP protocol support' CONFIG_IP_NF_TFTP $CONFIG_IP_NF_CONNTRACK dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK dep_tristate ' CuSeeMe protocol support' CONFIG_IP_NF_CUSEEME $CONFIG_IP_NF_CONNTRACK dep_tristate ' Quake III protocol support' CONFIG_IP_NF_QUAKE3 $CONFIG_IP_NF_CONNTRACK dep_tristate ' RTSP protocol support' CONFIG_IP_NF_RTSP $CONFIG_IP_NF_CONNTRACK dep_tristate ' MMS protocol support' CONFIG_IP_NF_MMS $CONFIG_IP_NF_CONNTRACK - dep_tristate ' SIP protocol support' CONFIG_IP_NF_SIP $CONFIG_IP_NF_CONNTRACK dep_tristate ' GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE + dep_tristate ' SIP protocol support' CONFIG_IP_NF_SIP $CONFIG_IP_NF_CONNTRACK dep_tristate ' ESP protocol support' CONFIG_IP_NF_CT_PROTO_ESP $CONFIG_IP_NF_CONNTRACK fi @@ -27,6 +28,10 @@ tristate 'IP tables support (required for filtering/masq/NAT)' CONFIG_IP_NF_IPTA if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then # The simple matches. dep_tristate ' limit match support' CONFIG_IP_NF_MATCH_LIMIT $CONFIG_IP_NF_IPTABLES + dep_tristate ' IPP2P match support' CONFIG_IP_NF_MATCH_IPP2P $CONFIG_IP_NF_IPTABLES + dep_tristate ' geoip match support' CONFIG_IP_NF_MATCH_GEOIP $CONFIG_IP_NF_IPTABLES + dep_tristate ' quota match support' CONFIG_IP_NF_MATCH_QUOTA $CONFIG_IP_NF_IPTABLES + dep_tristate ' IP range match support' CONFIG_IP_NF_MATCH_IPRANGE $CONFIG_IP_NF_IPTABLES dep_tristate ' IP address pool support' CONFIG_IP_NF_POOL $CONFIG_IP_NF_IPTABLES if [ "$CONFIG_IP_NF_POOL" = "y" -o "$CONFIG_IP_NF_POOL" = "m" ]; then @@ -39,6 +44,12 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then dep_tristate ' Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES dep_tristate ' Multiple port with ranges match support' CONFIG_IP_NF_MATCH_MPORT $CONFIG_IP_NF_IPTABLES dep_tristate ' TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES + dep_tristate ' recent match support' CONFIG_IP_NF_MATCH_RECENT $CONFIG_IP_NF_IPTABLES + dep_tristate ' account match support' CONFIG_IP_NF_MATCH_ACCOUNT $CONFIG_IP_NF_IPTABLES $CONFIG_PROC_FS + if [ "$CONFIG_IP_NF_MATCH_ACCOUNT" != "n" ]; then + bool ' account debugging output' CONFIG_IP_NF_MATCH_ACCOUNT_DEBUG + fi + dep_tristate ' condition match support' CONFIG_IP_NF_MATCH_CONDITION $CONFIG_IP_NF_IPTABLES dep_tristate ' TIME match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_TIME $CONFIG_IP_NF_IPTABLES dep_tristate ' ECN match support' CONFIG_IP_NF_MATCH_ECN $CONFIG_IP_NF_IPTABLES @@ -46,19 +57,36 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then dep_tristate ' AH/ESP match support' CONFIG_IP_NF_MATCH_AH_ESP $CONFIG_IP_NF_IPTABLES dep_tristate ' LENGTH match support' CONFIG_IP_NF_MATCH_LENGTH $CONFIG_IP_NF_IPTABLES + dep_tristate ' U32 match support' CONFIG_IP_NF_MATCH_U32 $CONFIG_IP_NF_U32 dep_tristate ' TTL match support' CONFIG_IP_NF_MATCH_TTL $CONFIG_IP_NF_IPTABLES dep_tristate ' tcpmss match support' CONFIG_IP_NF_MATCH_TCPMSS $CONFIG_IP_NF_IPTABLES + if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then dep_tristate ' Helper match support' CONFIG_IP_NF_MATCH_HELPER $CONFIG_IP_NF_IPTABLES fi if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then dep_tristate ' Connection state match support' CONFIG_IP_NF_MATCH_STATE $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES + dep_tristate ' Connections/IP limit match support' CONFIG_IP_NF_MATCH_CONNLIMIT $CONFIG_IP_NF_IPTABLES + if [ "$CONFIG_IP_NF_CONNTRACK_MARK" != "n" ]; then + dep_tristate ' Connection mark match support' CONFIG_IP_NF_MATCH_CONNMARK $CONFIG_IP_NF_IPTABLES + fi dep_tristate ' Connection tracking match support' CONFIG_IP_NF_MATCH_CONNTRACK $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' Unclean match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_UNCLEAN $CONFIG_IP_NF_IPTABLES + dep_tristate ' String match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_STRING $CONFIG_IP_NF_IPTABLES dep_tristate ' Webstr match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_WEBSTR $CONFIG_IP_NF_IPTABLES dep_tristate ' Owner match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_OWNER $CONFIG_IP_NF_IPTABLES + dep_tristate ' Layer 7 match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_LAYER7 $CONFIG_IP_NF_CONNTRACK + dep_mbool ' Layer 7 debugging output (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_LAYER7_DEBUG $CONFIG_IP_NF_MATCH_LAYER7 + + dep_tristate ' web match' CONFIG_IP_NF_MATCH_WEB $CONFIG_IP_NF_IPTABLES + dep_tristate ' BCOUNT target' CONFIG_IP_NF_TARGET_BCOUNT $CONFIG_IP_NF_IPTABLES + dep_tristate ' bcount match' CONFIG_IP_NF_MATCH_BCOUNT $CONFIG_IP_NF_TARGET_BCOUNT + dep_tristate ' MACSAVE target' CONFIG_IP_NF_TARGET_MACSAVE $CONFIG_IP_NF_IPTABLES + dep_tristate ' macsave match' CONFIG_IP_NF_MATCH_MACSAVE $CONFIG_IP_NF_TARGET_MACSAVE + dep_tristate ' exp match (experimental rig - do not use)' CONFIG_IP_NF_MATCH_EXP $CONFIG_IP_NF_IPTABLES + fi # The targets dep_tristate ' Packet filtering' CONFIG_IP_NF_FILTER $CONFIG_IP_NF_IPTABLES @@ -75,8 +103,6 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then define_bool CONFIG_IP_NF_NAT_NEEDED y dep_tristate ' MASQUERADE target support' CONFIG_IP_NF_TARGET_MASQUERADE $CONFIG_IP_NF_NAT dep_tristate ' REDIRECT target support' CONFIG_IP_NF_TARGET_REDIRECT $CONFIG_IP_NF_NAT - dep_tristate ' Automatic port forwarding (autofw) target support' CONFIG_IP_NF_AUTOFW $CONFIG_IP_NF_NAT - dep_tristate ' TRIGGER target support (port-trigger)' CONFIG_IP_NF_TARGET_TRIGGER $CONFIG_IP_NF_NAT if [ "$CONFIG_IP_NF_H323" = "m" ]; then define_tristate CONFIG_IP_NF_NAT_H323 m else @@ -84,6 +110,8 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then define_tristate CONFIG_IP_NF_NAT_H323 $CONFIG_IP_NF_NAT fi fi + dep_tristate ' Automatic port forwarding (autofw) target support' CONFIG_IP_NF_AUTOFW $CONFIG_IP_NF_NAT + dep_tristate ' TRIGGER target support (port-trigger)' CONFIG_IP_NF_TARGET_TRIGGER $CONFIG_IP_NF_NAT if [ "$CONFIG_IP_NF_PPTP" = "m" ]; then define_tristate CONFIG_IP_NF_NAT_PPTP m else @@ -109,13 +137,20 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT fi + if [ "$CONFIG_IP_NF_RTSP" = "m" ]; then + define_tristate CONFIG_IP_NF_NAT_RTSP m + else + if [ "$CONFIG_IP_NF_RTSP" = "y" ]; then + define_tristate CONFIG_IP_NF_NAT_RTSP $CONFIG_IP_NF_NAT + fi + fi if [ "$CONFIG_IP_NF_IRC" = "m" ]; then define_tristate CONFIG_IP_NF_NAT_IRC m else if [ "$CONFIG_IP_NF_IRC" = "y" ]; then define_tristate CONFIG_IP_NF_NAT_IRC $CONFIG_IP_NF_NAT fi - fi + fi if [ "$CONFIG_IP_NF_CUSEEME" = "m" ]; then define_tristate CONFIG_IP_NF_NAT_CUSEEME m else @@ -153,13 +188,6 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then define_tristate CONFIG_IP_NF_NAT_TFTP $CONFIG_IP_NF_NAT fi fi - if [ "$CONFIG_IP_NF_RTSP" = "m" ]; then - define_tristate CONFIG_IP_NF_NAT_RTSP m - else - if [ "$CONFIG_IP_NF_RTSP" = "y" ]; then - define_tristate CONFIG_IP_NF_NAT_RTSP $CONFIG_IP_NF_NAT - fi - fi if [ "$CONFIG_IP_NF_CT_PROTO_ESP" = "m" ]; then define_tristate CONFIG_IP_NF_NAT_PROTO_ESP m else @@ -178,8 +206,15 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then dep_tristate ' DSCP target support' CONFIG_IP_NF_TARGET_DSCP $CONFIG_IP_NF_MANGLE dep_tristate ' MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE + dep_tristate ' ROUTE target support' CONFIG_IP_NF_TARGET_ROUTE $CONFIG_IP_NF_MANGLE + dep_tristate ' CLASSIFY target support (EXPERIMENTAL)' CONFIG_IP_NF_TARGET_CLASSIFY $CONFIG_IP_NF_FILTER + dep_tristate ' IMQ target support' CONFIG_IP_NF_TARGET_IMQ $CONFIG_IP_NF_MANGLE fi dep_tristate ' LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES + if [ "$CONFIG_IP_NF_CONNTRACK_MARK" != "n" ]; then + dep_tristate ' CONNMARK target support' CONFIG_IP_NF_TARGET_CONNMARK $CONFIG_IP_NF_IPTABLES + fi + dep_tristate ' TTL target support' CONFIG_IP_NF_TARGET_TTL $CONFIG_IP_NF_IPTABLES dep_tristate ' ULOG target support' CONFIG_IP_NF_TARGET_ULOG $CONFIG_IP_NF_IPTABLES dep_tristate ' TCPMSS target support' CONFIG_IP_NF_TARGET_TCPMSS $CONFIG_IP_NF_IPTABLES fi @@ -189,6 +224,10 @@ if [ "$CONFIG_IP_NF_ARPTABLES" != "n" ]; then dep_tristate ' ARP packet filtering' CONFIG_IP_NF_ARPFILTER $CONFIG_IP_NF_ARPTABLES fi +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'tomato_ct' CONFIG_IP_NF_TOMATOCT +fi + # Backwards compatibility modules: only if you don't build in the others. if [ "$CONFIG_IP_NF_CONNTRACK" != "y" ]; then if [ "$CONFIG_IP_NF_IPTABLES" != "y" ]; then diff --git a/release/src/linux/linux/net/ipv4/netfilter/Makefile b/release/src/linux/linux/net/ipv4/netfilter/Makefile index abf55469..80de56f3 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/Makefile +++ b/release/src/linux/linux/net/ipv4/netfilter/Makefile @@ -33,10 +33,10 @@ obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o # H.323 support obj-$(CONFIG_IP_NF_H323) += ip_conntrack_h323.o -obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o -ifdef CONFIG_IP_NF_NAT_H323 +ifdef CONFIG_IP_NF_H323 export-objs += ip_conntrack_h323.o endif +obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o # connection tracking protocol helpers @@ -83,10 +83,14 @@ obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o ifdef CONFIG_IP_NF_NAT_IRC export-objs += ip_conntrack_irc.o endif + +# rtsp protocol support obj-$(CONFIG_IP_NF_RTSP) += ip_conntrack_rtsp.o ifdef CONFIG_IP_NF_NAT_RTSP export-objs += ip_conntrack_rtsp.o endif +obj-$(CONFIG_IP_NF_NAT_RTSP) += ip_nat_rtsp.o + # NAT helpers obj-$(CONFIG_IP_NF_NAT_CUSEEME) += ip_nat_cuseeme.o obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o @@ -95,7 +99,6 @@ obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o obj-$(CONFIG_IP_NF_NAT_QUAKE3) += ip_nat_quake3.o -obj-$(CONFIG_IP_NF_NAT_RTSP) += ip_nat_rtsp.o obj-$(CONFIG_IP_NF_NAT_MMS) += ip_nat_mms.o # generic IP tables @@ -109,48 +112,64 @@ obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o # matches obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o +obj-$(CONFIG_IP_NF_MATCH_IPP2P) += ipt_ipp2p.o +obj-$(CONFIG_IP_NF_MATCH_GEOIP) += ipt_geoip.o +obj-$(CONFIG_IP_NF_MATCH_QUOTA) += ipt_quota.o +obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o obj-$(CONFIG_IP_NF_POOL) += ipt_pool.o ip_pool.o obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o - obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o - obj-$(CONFIG_IP_NF_MATCH_MPORT) += ipt_mport.o - obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o - +obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o +obj-$(CONFIG_IP_NF_MATCH_ACCOUNT) += ipt_account.o +obj-$(CONFIG_IP_NF_MATCH_CONDITION) += ipt_condition.o obj-$(CONFIG_IP_NF_MATCH_TIME) += ipt_time.o - obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o obj-$(CONFIG_IP_NF_MATCH_DSCP) += ipt_dscp.o obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o - obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o - +obj-$(CONFIG_IP_NF_MATCH_U32) += ipt_u32.o obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o +obj-$(CONFIG_IP_NF_MATCH_CONNLIMIT) += ipt_connlimit.o +obj-$(CONFIG_IP_NF_MATCH_CONNMARK) += ipt_connmark.o obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o +obj-$(CONFIG_IP_NF_MATCH_STRING) += ipt_string.o obj-$(CONFIG_IP_NF_MATCH_WEBSTR) += ipt_webstr.o obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o +obj-$(CONFIG_IP_NF_MATCH_LAYER7) += ipt_layer7.o +obj-$(CONFIG_IP_NF_MATCH_WEB) += ipt_web.o +obj-$(CONFIG_IP_NF_MATCH_MACSAVE) += ipt_macsave.o +obj-$(CONFIG_IP_NF_MATCH_EXP) += ipt_exp.o +obj-$(CONFIG_IP_NF_MATCH_BCOUNT) += ipt_bcount.o # targets obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o obj-$(CONFIG_IP_NF_TARGET_MIRROR) += ipt_MIRROR.o +obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o +obj-$(CONFIG_IP_NF_TARGET_IMQ) += ipt_IMQ.o obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o +obj-$(CONFIG_IP_NF_TARGET_ROUTE) += ipt_ROUTE.o obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o +obj-$(CONFIG_IP_NF_TARGET_CONNMARK) += ipt_CONNMARK.o +obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o obj-$(CONFIG_IP_NF_AUTOFW) += ip_autofw.o obj-$(CONFIG_IP_NF_TARGET_TRIGGER) += ipt_TRIGGER.o +obj-$(CONFIG_IP_NF_TARGET_MACSAVE) += ipt_MACSAVE.o +obj-$(CONFIG_IP_NF_TARGET_BCOUNT) += ipt_BCOUNT.o # generic ARP tables obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o @@ -164,6 +183,8 @@ obj-$(CONFIG_IP_NF_COMPAT_IPFWADM) += ipfwadm.o obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o +obj-$(CONFIG_IP_NF_TOMATOCT) += tomato_ct.o + include $(TOPDIR)/Rules.make ip_conntrack.o: $(ip_conntrack-objs) diff --git a/release/src/linux/linux/net/ipv4/netfilter/arp_tables.c b/release/src/linux/linux/net/ipv4/netfilter/arp_tables.c index aa1c034a..757fc2ab 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/arp_tables.c +++ b/release/src/linux/linux/net/ipv4/netfilter/arp_tables.c @@ -986,13 +986,12 @@ static int do_add_counters(void *user, unsigned int len) goto free; write_lock_bh(&t->lock); - /************************************* - * modify by tanghui @ 2006-10-11 - * for a RACE CONDITION in the "do_add_counters()" function - *************************************/ - //if (t->private->number != paddc->num_counters) { - if (t->private->number != tmp.num_counters) { - /*************************************/ + +#if 0 // removed 1.11 forward bug test + // 43011 (09?): checkme: modify by tanghui @ 2006-10-11 for a RACE CONDITION in the "do_add_counters()" function + // if (t->private->number != tmp.num_counters) { +#endif + if (t->private->number != paddc->num_counters) { ret = -EINVAL; goto unlock_up_free; } diff --git a/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_core.c b/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_core.c index 9c6f040f..324951ee 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_core.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_core.c @@ -34,7 +34,12 @@ /* For ERR_PTR(). Yeah, I know... --RR */ #include <linux/fs.h> -#include <linux/netdevice.h> +#define TEST_JHASH // test jhash from 2.4.33 -- zzz + +#ifdef TEST_JHASH +#include <linux/jhash.h> +#include <linux/random.h> +#endif /* This rwlock protects the main hash table, protocol/helper/expected registrations, conntrack timers*/ @@ -71,7 +76,7 @@ static kmem_cache_t *ip_conntrack_cachep; int sysctl_ip_conntrack_tcp_timeouts[10] = { 30 MINS, /* TCP_CONNTRACK_NONE, */ - 5 DAYS, /* TCP_CONNTRACK_ESTABLISHED, */ + 4 HOURS, /* TCP_CONNTRACK_ESTABLISHED, */ // was 5 days zzz 2 MINS, /* TCP_CONNTRACK_SYN_SENT, */ 60 SECS, /* TCP_CONNTRACK_SYN_RECV, */ 2 MINS, /* TCP_CONNTRACK_FIN_WAIT, */ @@ -128,9 +133,20 @@ ip_conntrack_put(struct ip_conntrack *ct) nf_conntrack_put(&ct->infos[0]); } +#ifdef TEST_JHASH +static int ip_conntrack_hash_rnd_initted; +static unsigned int ip_conntrack_hash_rnd; +#endif + static inline u_int32_t hash_conntrack(const struct ip_conntrack_tuple *tuple) { +#ifdef TEST_JHASH + return (jhash_3words(tuple->src.ip, + (tuple->dst.ip ^ tuple->dst.protonum), + (tuple->src.u.all | (tuple->dst.u.all << 16)), + ip_conntrack_hash_rnd) % ip_conntrack_htable_size); +#else /* ntohl because more differences in low bits. */ /* To ensure that halves of the same connection don't hash clash, we add the source per-proto again. */ @@ -139,6 +155,7 @@ hash_conntrack(const struct ip_conntrack_tuple *tuple) + tuple->dst.protonum) + ntohs(tuple->src.u.all)) % ip_conntrack_htable_size; +#endif } inline int @@ -314,9 +331,6 @@ clean_from_lists(struct ip_conntrack *ct) { DEBUGP("clean_from_lists(%p)\n", ct); MUST_BE_WRITE_LOCKED(&ip_conntrack_lock); - /* Remove from both hash lists: must not NULL out next ptrs, - otherwise we'll look unconfirmed. Fortunately, LIST_DELETE - doesn't do this. --RR */ LIST_DELETE(&ip_conntrack_hash [hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple)], &ct->tuplehash[IP_CT_DIR_ORIGINAL]); @@ -359,6 +373,14 @@ destroy_conntrack(struct nf_conntrack *nfct) list_del(&ct->master->expected_list); kfree(ct->master); } + + #if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE) + if(ct->layer7.app_proto) + kfree(ct->layer7.app_proto); + if(ct->layer7.app_data) + kfree(ct->layer7.app_data); + #endif + WRITE_UNLOCK(&ip_conntrack_lock); DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct); @@ -489,6 +511,7 @@ __ip_conntrack_confirm(struct nf_ct_info *nfct) ct->timeout.expires += jiffies; add_timer(&ct->timeout); atomic_inc(&ct->ct_general.use); + set_bit(IPS_CONFIRMED_BIT, &ct->status); WRITE_UNLOCK(&ip_conntrack_lock); return NF_ACCEPT; } @@ -606,7 +629,7 @@ icmp_error_track(struct sk_buff *skb, connection. Too bad: we're in trouble anyway. */ static inline int unreplied(const struct ip_conntrack_tuple_hash *i) { - return !(i->ctrack->status & IPS_ASSURED); + return !(test_bit(IPS_ASSURED_BIT, &i->ctrack->status)); } static int early_drop(struct list_head *chain) @@ -632,31 +655,6 @@ static int early_drop(struct list_head *chain) return dropped; } -/******************lzh add *************************************** -* DESCRIPTION:delete seleted ip conntrack from conntrack_hash list -* INPUT : ip_conntrack_tuple_hash h -* OUTPUT: NULL -* AUTHOR: linzhihong -* DATE : 2006.7.20 -*****************************************************************/ -void del_selected_conntrack(struct ip_conntrack_tuple_hash *h) -{ - DEBUGP("hahaha enter %s\n", __FUNCTION__); - if(h) - { - #if 1 - ip_ct_refresh(h->ctrack, 1*HZ); - #else - if(del_timer(&h->ctrack->timeout)) - { - death_by_timeout((unsigned long)h->ctrack); - } - //ip_conntrack_put(h->ctrack); - #endif - } -} -/**************************** lzh end ******************************/ - static inline int helper_cmp(const struct ip_conntrack_helper *i, const struct ip_conntrack_tuple *rtuple) { @@ -670,41 +668,6 @@ struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *t tuple); } -#define RESERVE_CONNTRACK_FOR_ROUTER -#ifdef RESERVE_CONNTRACK_FOR_ROUTER -#define RESERVE_CONNTRACK_NUM 20 -/* - Check if the packet is for Router AP(LAN side only), or generate from - Router itself(Both sides). - */ -static int cmp_local_ip(u_int32_t dst, u_int32_t src) -{ -#define IF_LAN_NAME "br0" - - int ret = -1; - struct in_device *in_dev; - struct net_device *dev; - struct in_ifaddr **ifap = NULL; - struct in_ifaddr *ifa = NULL; - - for(dev = dev_base; dev != NULL; dev = dev->next){ - if((in_dev=__in_dev_get(dev)) != NULL){ - for(ifap=&in_dev->ifa_list; (ifa=*ifap) != NULL; ifap=&ifa->ifa_next){ - if((ifa->ifa_address == dst && !strcmp(IF_LAN_NAME, ifa->ifa_label)) || ifa->ifa_address == src){ - /*match*/ - ret = 0; - break; - } - } - } - } - - return ret; - -#undef IF_LAN_NAME -} -#endif - /* Allocate a new conntrack: we return -ENOMEM if classification failed due to stress. Otherwise it really is unclassifiable. */ static struct ip_conntrack_tuple_hash * @@ -719,9 +682,15 @@ init_conntrack(const struct ip_conntrack_tuple *tuple, int i; static unsigned int drop_next = 0; +#ifdef TEST_JHASH + if (!ip_conntrack_hash_rnd_initted) { + get_random_bytes(&ip_conntrack_hash_rnd, 4); + ip_conntrack_hash_rnd_initted = 1; + } +#endif + hash = hash_conntrack(tuple); - #ifndef RESERVE_CONNTRACK_FOR_ROUTER if (ip_conntrack_max && atomic_read(&ip_conntrack_count) >= ip_conntrack_max) { /* Try dropping from random chain, or else from the @@ -738,32 +707,6 @@ init_conntrack(const struct ip_conntrack_tuple *tuple, return ERR_PTR(-ENOMEM); } } - #else -#define IPV4_BROADCAST_ADDR 0x000000FF -#define IPV4_MULTICAST_ADDR 0xE0000000 - if (ip_conntrack_max && - (ip_conntrack_max - atomic_read(&ip_conntrack_count)) <= RESERVE_CONNTRACK_NUM){ - if((atomic_read(&ip_conntrack_count) < ip_conntrack_max) && - (((tuple->dst).ip & IPV4_BROADCAST_ADDR == IPV4_BROADCAST_ADDR) || ((tuple->dst).ip & IPV4_BROADCAST_ADDR == IPV4_MULTICAST_ADDR) || !cmp_local_ip((tuple->dst).ip, (tuple->src).ip))){ - //packet for router(LAN side only) or packet from router, let it go thru - } - else{ - /* Try dropping from random chain, or else from the - chain about to put into (in case they're trying to - bomb one hash chain). */ - unsigned int next = (drop_next++)%ip_conntrack_htable_size; - - if (!early_drop(&ip_conntrack_hash[next]) - && !early_drop(&ip_conntrack_hash[hash])) { - if (net_ratelimit()) - printk(KERN_WARNING - "ip_conntrack: table full, dropping" - " packet.\n"); - return ERR_PTR(-ENOMEM); - } - } - } - #endif if (!invert_tuple(&repl_tuple, tuple, protocol)) { DEBUGP("Can't invert tuple.\n"); @@ -829,9 +772,12 @@ init_conntrack(const struct ip_conntrack_tuple *tuple, conntrack, expected); /* Welcome, Mr. Bond. We've been expecting you... */ IP_NF_ASSERT(master_ct(conntrack)); - conntrack->status = IPS_EXPECTED; + __set_bit(IPS_EXPECTED_BIT, &conntrack->status); conntrack->master = expected; expected->sibling = conntrack; +#if CONFIG_IP_NF_CONNTRACK_MARK + conntrack->mark = expected->expectant->mark; +#endif LIST_DELETE(&ip_conntrack_expect_list, expected); INIT_LIST_HEAD(&expected->list); expected->expectant->expecting--; @@ -878,11 +824,11 @@ resolve_normal_ct(struct sk_buff *skb, *set_reply = 1; } else { /* Once we've had two way comms, always ESTABLISHED. */ - if (h->ctrack->status & IPS_SEEN_REPLY) { + if (test_bit(IPS_SEEN_REPLY_BIT, &h->ctrack->status)) { DEBUGP("ip_conntrack_in: normal packet for %p\n", h->ctrack); *ctinfo = IP_CT_ESTABLISHED; - } else if (h->ctrack->status & IPS_EXPECTED) { + } else if (test_bit(IPS_EXPECTED_BIT, &h->ctrack->status)) { DEBUGP("ip_conntrack_in: related packet for %p\n", h->ctrack); *ctinfo = IP_CT_RELATED; @@ -1056,16 +1002,15 @@ int ip_conntrack_expect_related(struct ip_conntrack *related_to, } if (old) { - /************************* lzh add ****************************************** - * fix sip alg CDROUTE test fail - * 2007/3/16 - ***************************************************************************/ - if (old->help.exp_sip_info.nated && (old->help.exp_sip_info.type == CONN_RTP)) - { - DEBUGP("%s: found old exp and nated, rtp port=%d\n", __FUNCTION__,ntohs(old->tuple.dst.u.udp.port)); - related_to->help.ct_sip_info.rtpport = ntohs(old->tuple.dst.u.udp.port); +#if 0 // removed 1.11 forward bug test + if (1) { // 43011 (09?): checkme + // lzh add, fix sip alg CDROUTE test fail, 2007/3/16 + if (old->help.exp_sip_info.nated && (old->help.exp_sip_info.type == CONN_RTP)) { + DEBUGP("%s: found old exp and nated, rtp port=%d\n", __FUNCTION__,ntohs(old->tuple.dst.u.udp.port)); + related_to->help.ct_sip_info.rtpport = ntohs(old->tuple.dst.u.udp.port); + } } - /************************ lzh end ******************************************/ +#endif WRITE_UNLOCK(&ip_conntrack_lock); return -EEXIST; } @@ -1530,6 +1475,7 @@ int __init ip_conntrack_init(void) unsigned int i; int ret; +#if 0 /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB * machine has 256 buckets. >= 1GB machines have 8192 buckets. */ if (hashsize) { @@ -1544,6 +1490,33 @@ int __init ip_conntrack_init(void) ip_conntrack_htable_size = 16; } ip_conntrack_max = 8 * ip_conntrack_htable_size; +#else +/* + + sizeof(list_head) = 8 + x 4096 = 32K + + sizeof(ip_conntrack) = 368 + x 2048 = 736K + +*/ + +#ifdef TEST_JHASH +/* + if (hashsize) ip_conntrack_htable_size = hashsize; + else ip_conntrack_htable_size = 4096; + ip_conntrack_max = 2048; +*/ + if (hashsize) ip_conntrack_htable_size = hashsize; + else ip_conntrack_htable_size = 8092; + ip_conntrack_max = 4096; +#else + if (hashsize) ip_conntrack_htable_size = hashsize; + else ip_conntrack_htable_size = 4099; + ip_conntrack_max = 2048; +#endif + +#endif printk("ip_conntrack version %s (%u buckets, %d max)" " - %d bytes per conntrack\n", IP_CONNTRACK_VERSION, @@ -1605,3 +1578,5 @@ err_unreg_sockopt: return -ENOMEM; } + + diff --git a/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_h323.c b/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_h323.c index cb0b1da5..c6172945 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_h323.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_h323.c @@ -104,30 +104,26 @@ static int h245_help(const struct iphdr *iph, size_t len, exp->seq = ntohl(tcph->seq) + i; - *((u_int32_t *)data) = ct->tuplehash[!dir].tuple.dst.ip; //!!! Netmeeting fix - - { - unsigned int chksum; - - chksum = csum_partial((char *)tcph + tcph->doff*4, - datalen, 0); - - tcph->check = 0; - tcph->check = tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, - csum_partial((char *)tcph, tcph->doff*4, chksum)); - - } - + // 43011 (09?): checkme + if (1) { + unsigned int chksum; + + *((u_int32_t *)data) = ct->tuplehash[!dir].tuple.dst.ip; //!!! Netmeeting fix + chksum = csum_partial((char *)tcph + tcph->doff*4, datalen, 0); + tcph->check = 0; + tcph->check = tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, + csum_partial((char *)tcph, tcph->doff*4, chksum)); + } exp->tuple = ((struct ip_conntrack_tuple) { { ct->tuplehash[!dir].tuple.src.ip, { 0 } }, { data_ip, - { data_port }, + { .tcp = { data_port } }, IPPROTO_UDP }}); exp->mask = ((struct ip_conntrack_tuple) { { 0xFFFFFFFF, { 0 } }, - { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); + { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }}); exp->expectfn = NULL; @@ -252,11 +248,11 @@ static int h225_help(const struct iphdr *iph, size_t len, { { ct->tuplehash[!dir].tuple.src.ip, { 0 } }, { data_ip, - { data_port }, + { .tcp = { data_port } }, IPPROTO_TCP }}); exp->mask = ((struct ip_conntrack_tuple) { { 0xFFFFFFFF, { 0 } }, - { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); + { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }}); exp->expectfn = h225_expect; @@ -317,9 +313,7 @@ static void __exit fini(void) ip_conntrack_helper_unregister(&h225); } -#ifdef CONFIG_IP_NF_NAT_NEEDED EXPORT_SYMBOL(ip_h323_lock); -#endif module_init(init); module_exit(fini); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_pptp.c b/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_pptp.c index 17cf2b7b..a0b41051 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_pptp.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_pptp.c @@ -1,5 +1,5 @@ /* - * ip_conntrack_pptp.c - Version 1.11 + * ip_conntrack_pptp.c - Version 1.9 * * Connection tracking support for PPTP (Point to Point Tunneling Protocol). * PPTP is a a protocol for creating virtual private networks. @@ -9,7 +9,7 @@ * GRE is defined in RFC 1701 and RFC 1702. Documentation of * PPTP can be found in RFC 2637 * - * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>, + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org> * * Development of this code funded by Astaro AG (http://www.astaro.com/) * @@ -21,6 +21,18 @@ * TODO: - finish support for multiple calls within one session * (needs expect reservations in newnat) * - testing of incoming PPTP calls + * + * Changes: + * 2002-02-05 - Version 1.3 + * - Call ip_conntrack_unexpect_related() from + * pptp_timeout_related() to destroy expectations in case + * CALL_DISCONNECT_NOTIFY or tcp fin packet was seen + * (Philip Craig <philipc@snapgear.com>) + * - Add Version information at module loadtime + * 2002-02-10 - Version 1.6 + * - move to C99 style initializers + * - remove second expectation if first arrives + * */ #include <linux/config.h> @@ -35,13 +47,21 @@ #include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> #include <linux/netfilter_ipv4/ip_conntrack_pptp.h> +#define IP_CT_PPTP_VERSION "1.9" + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP"); DECLARE_LOCK(ip_pptp_lock); +#if 0 +#include "ip_conntrack_pptp_priv.h" +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \ + ": " format, ## args) +#else #define DEBUGP(format, args...) +#endif #define SECS *HZ #define MINS * 60 SECS @@ -53,8 +73,8 @@ DECLARE_LOCK(ip_pptp_lock); static int pptp_expectfn(struct ip_conntrack *ct) { - struct ip_conntrack_expect *exp, *other_exp; struct ip_conntrack *master; + struct ip_conntrack_expect *exp; DEBUGP("increasing timeouts\n"); /* increase timeout of GRE data channel conntrack entry */ @@ -67,6 +87,12 @@ static int pptp_expectfn(struct ip_conntrack *ct) return 0; } + exp = ct->master; + if (!exp) { + DEBUGP("no expectation!!\n"); + return 0; + } + DEBUGP("completing tuples with ct info\n"); /* we can do this, since we're unconfirmed */ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == @@ -83,6 +109,26 @@ static int pptp_expectfn(struct ip_conntrack *ct) ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = htonl(master->help.ct_pptp_info.pac_call_id); } + + /* delete other expectation */ + if (exp->expected_list.next != &exp->expected_list) { + struct ip_conntrack_expect *other_exp; + struct list_head *cur_item, *next; + + for (cur_item = master->sibling_list.next; + cur_item != &master->sibling_list; cur_item = next) { + next = cur_item->next; + other_exp = list_entry(cur_item, + struct ip_conntrack_expect, + expected_list); + /* remove only if occurred at same sequence number */ + if (other_exp != exp && other_exp->seq == exp->seq) { + DEBUGP("unexpecting other direction\n"); + ip_ct_gre_keymap_destroy(other_exp); + ip_conntrack_unexpect_related(other_exp); + } + } + } return 0; } @@ -90,15 +136,21 @@ static int pptp_expectfn(struct ip_conntrack *ct) /* timeout GRE data connections */ static int pptp_timeout_related(struct ip_conntrack *ct) { - struct list_head *cur_item; + struct list_head *cur_item, *next; struct ip_conntrack_expect *exp; - list_for_each(cur_item, &ct->sibling_list) { + /* FIXME: do we have to lock something ? */ + for (cur_item = ct->sibling_list.next; + cur_item != &ct->sibling_list; cur_item = next) { + next = cur_item->next; exp = list_entry(cur_item, struct ip_conntrack_expect, expected_list); - if (!exp->sibling) + ip_ct_gre_keymap_destroy(exp); + if (!exp->sibling) { + ip_conntrack_unexpect_related(exp); continue; + } DEBUGP("setting timeout of conntrack %p to 0\n", exp->sibling); @@ -110,7 +162,7 @@ static int pptp_timeout_related(struct ip_conntrack *ct) return 0; } -/* expect GRE connection in PNS->PAC direction */ +/* expect GRE connections (PNS->PAC and PAC->PNS direction) */ static inline int exp_gre(struct ip_conntrack *master, u_int32_t seq, @@ -121,7 +173,7 @@ exp_gre(struct ip_conntrack *master, struct ip_conntrack_tuple inv_tuple; memset(&exp, 0, sizeof(exp)); - /* tuple in original direction, PAC->PNS */ + /* tuple in original direction, PNS->PAC */ exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; exp.tuple.src.u.gre.key = htonl(ntohs(peer_callid)); exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; @@ -149,11 +201,43 @@ exp_gre(struct ip_conntrack *master, DUMP_TUPLE_RAW(&exp.tuple); /* Add GRE keymap entries */ + if (ip_ct_gre_keymap_add(&exp, &exp.tuple, 0) != 0) + return 1; + + invert_tuplepr(&inv_tuple, &exp.tuple); + if (ip_ct_gre_keymap_add(&exp, &inv_tuple, 1) != 0) { + ip_ct_gre_keymap_destroy(&exp); + return 1; + } + + if (ip_conntrack_expect_related(master, &exp) != 0) { + ip_ct_gre_keymap_destroy(&exp); + DEBUGP("cannot expect_related()\n"); + return 1; + } + + /* tuple in reply direction, PAC->PNS */ + exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; + exp.tuple.src.u.gre.key = htonl(ntohs(callid)); + exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + exp.tuple.dst.u.gre.key = htonl(ntohs(peer_callid)); + + DEBUGP("calling expect_related "); + DUMP_TUPLE_RAW(&exp.tuple); + + /* Add GRE keymap entries */ ip_ct_gre_keymap_add(&exp, &exp.tuple, 0); invert_tuplepr(&inv_tuple, &exp.tuple); ip_ct_gre_keymap_add(&exp, &inv_tuple, 1); + /* FIXME: cannot handle error correctly, since we need to free + * the above keymap :( */ - ip_conntrack_expect_related(master, &exp); + if (ip_conntrack_expect_related(master, &exp) != 0) { + /* free the second pair of keypmaps */ + ip_ct_gre_keymap_destroy(&exp); + DEBUGP("cannot expect_related():\n"); + return 1; + } return 0; } @@ -240,7 +324,8 @@ pptp_inbound_pkt(struct tcphdr *tcph, info->cstate = PPTP_CALL_OUT_CONF; seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph); - exp_gre(ct, seq, *cid, *pcid); + if (exp_gre(ct, seq, *cid, *pcid) != 0) + printk("ip_conntrack_pptp: error during exp_gre\n"); break; case PPTP_IN_CALL_REQUEST: @@ -282,7 +367,8 @@ pptp_inbound_pkt(struct tcphdr *tcph, /* we expect a GRE connection from PAC to PNS */ seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph); - exp_gre(ct, seq, *cid, *pcid); + if (exp_gre(ct, seq, *cid, *pcid) != 0) + printk("ip_conntrack_pptp: error during exp_gre\n"); break; @@ -294,7 +380,6 @@ pptp_inbound_pkt(struct tcphdr *tcph, /* untrack this call id, unexpect GRE packets */ pptp_timeout_related(ct); - /* NEWNAT: look up exp for call id and unexpct_related */ break; case PPTP_WAN_ERROR_NOTIFY: @@ -446,7 +531,8 @@ conntrack_pptp_help(const struct iphdr *iph, size_t len, if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, csum_partial((char *) tcph, tcplen, 0))) { printk(KERN_NOTICE __FILE__ ": bad csum\n"); -// return NF_ACCEPT; + /* W2K PPTP server sends TCP packets with wrong checksum :(( */ + //return NF_ACCEPT; } if (tcph->fin || tcph->rst) { @@ -456,8 +542,6 @@ conntrack_pptp_help(const struct iphdr *iph, size_t len, /* untrack this call id, unexpect GRE packets */ pptp_timeout_related(ct); - /* no need to call unexpect_related since master conn - * dies anyway */ } @@ -482,6 +566,8 @@ conntrack_pptp_help(const struct iphdr *iph, size_t len, LOCK_BH(&ip_pptp_lock); + /* FIXME: We just blindly assume that the control connection is always + * established from PNS->PAC. However, RFC makes no guarantee */ if (dir == IP_CT_DIR_ORIGINAL) /* client -> server (PNS -> PAC) */ ret = pptp_outbound_pkt(tcph, pptph, datalen, ct, ctinfo); @@ -497,13 +583,31 @@ conntrack_pptp_help(const struct iphdr *iph, size_t len, /* control protocol helper */ static struct ip_conntrack_helper pptp = { - { NULL, NULL }, - "pptp", IP_CT_HELPER_F_REUSE_EXPECT, THIS_MODULE, 2, 0, - { { 0, { tcp: { port: __constant_htons(PPTP_CONTROL_PORT) } } }, - { 0, { 0 }, IPPROTO_TCP } }, - { { 0, { tcp: { port: 0xffff } } }, - { 0, { 0 }, 0xffff } }, - conntrack_pptp_help }; + .list = { NULL, NULL }, + .name = "pptp", + .flags = IP_CT_HELPER_F_REUSE_EXPECT, + .me = THIS_MODULE, + .max_expected = 2, + .timeout = 0, + .tuple = { .src = { .ip = 0, + .u = { .tcp = { .port = + __constant_htons(PPTP_CONTROL_PORT) } } + }, + .dst = { .ip = 0, + .u = { .all = 0 }, + .protonum = IPPROTO_TCP + } + }, + .mask = { .src = { .ip = 0, + .u = { .tcp = { .port = 0xffff } } + }, + .dst = { .ip = 0, + .u = { .all = 0 }, + .protonum = 0xffff + } + }, + .help = conntrack_pptp_help +}; /* ip_conntrack_pptp initialization */ static int __init init(void) @@ -517,12 +621,14 @@ static int __init init(void) return -EIO; } + printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION); return 0; } static void __exit fini(void) { ip_conntrack_helper_unregister(&pptp); + printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION); } module_init(init); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_esp.c b/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_esp.c index bcb8d892..bcb8d892 100755..100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_esp.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_esp.c diff --git a/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_gre.c b/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_gre.c index 4ff06dcb..55b3ecea 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_gre.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_gre.c @@ -1,5 +1,5 @@ /* - * ip_conntrack_proto_gre.c - Version 1.11 + * ip_conntrack_proto_gre.c - Version 1.2 * * Connection tracking protocol helper module for GRE. * @@ -17,7 +17,7 @@ * * Documentation about PPTP can be found in RFC 2637 * - * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org> + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org> * * Development of this code funded by Astaro AG (http://www.astaro.com/) * @@ -54,8 +54,18 @@ MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE"); #define GRE_TIMEOUT (30*HZ) #define GRE_STREAM_TIMEOUT (180*HZ) +#if 0 +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \ + ": " format, ## args) +#define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x:%u:0x%x\n", \ + NIPQUAD((x)->src.ip), ntohl((x)->src.u.gre.key), \ + NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.gre.key), \ + (x)->dst.u.gre.version, \ + ntohs((x)->dst.u.gre.protocol)) +#else #define DEBUGP(x, args...) #define DUMP_TUPLE_GRE(x) +#endif /* GRE KEYMAP HANDLING FUNCTIONS */ static LIST_HEAD(gre_keymap_list); @@ -103,7 +113,6 @@ int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp, memset(km, 0, sizeof(*km)); memcpy(&km->tuple, t, sizeof(*t)); - km->master = exp; if (!reply) exp->proto.gre.keymap_orig = km; @@ -132,6 +141,26 @@ void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km, WRITE_UNLOCK(&ip_ct_gre_lock); } +/* destroy the keymap entries associated with specified expect */ +void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp) +{ + DEBUGP("entering for exp %p\n", exp); + WRITE_LOCK(&ip_ct_gre_lock); + if (exp->proto.gre.keymap_orig) { + DEBUGP("removing %p from list\n", exp->proto.gre.keymap_orig); + list_del(&exp->proto.gre.keymap_orig->list); + kfree(exp->proto.gre.keymap_orig); + exp->proto.gre.keymap_orig = NULL; + } + if (exp->proto.gre.keymap_reply) { + DEBUGP("removing %p from list\n", exp->proto.gre.keymap_reply); + list_del(&exp->proto.gre.keymap_reply->list); + kfree(exp->proto.gre.keymap_reply); + exp->proto.gre.keymap_reply = NULL; + } + WRITE_UNLOCK(&ip_ct_gre_lock); +} + /* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */ @@ -186,6 +215,10 @@ static int gre_pkt_to_tuple(const void *datah, size_t datalen, srckey = gre_keymap_lookup(tuple); +#if 0 + DEBUGP("found src key %x for tuple ", ntohl(srckey)); + DUMP_TUPLE_GRE(tuple); +#endif tuple->src.u.gre.key = srckey; return 1; @@ -256,18 +289,7 @@ static void gre_destroy(struct ip_conntrack *ct) return; } - WRITE_LOCK(&ip_ct_gre_lock); - if (master->proto.gre.keymap_orig) { - DEBUGP("removing %p from list\n", master->proto.gre.keymap_orig); - list_del(&master->proto.gre.keymap_orig->list); - kfree(master->proto.gre.keymap_orig); - } - if (master->proto.gre.keymap_reply) { - DEBUGP("removing %p from list\n", master->proto.gre.keymap_reply); - list_del(&master->proto.gre.keymap_reply->list); - kfree(master->proto.gre.keymap_reply); - } - WRITE_UNLOCK(&ip_ct_gre_lock); + ip_ct_gre_keymap_destroy(master); } /* protocol helper struct */ @@ -304,7 +326,7 @@ static void __exit fini(void) /* delete all keymap entries */ WRITE_LOCK(&ip_ct_gre_lock); list_for_each_safe(pos, n, &gre_keymap_list) { - DEBUGP("deleting keymap %p\n", pos); + DEBUGP("deleting keymap %p at module unload time\n", pos); list_del(pos); kfree(pos); } @@ -315,6 +337,7 @@ static void __exit fini(void) EXPORT_SYMBOL(ip_ct_gre_keymap_add); EXPORT_SYMBOL(ip_ct_gre_keymap_change); +EXPORT_SYMBOL(ip_ct_gre_keymap_destroy); module_init(init); module_exit(fini); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c index 02f20742..ebb9b493 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c @@ -173,7 +173,7 @@ static int tcp_packet(struct ip_conntrack *conntrack, have an established connection: this is a fairly common problem case, so we can delete the conntrack immediately. --RR */ - if (!(conntrack->status & IPS_SEEN_REPLY) && tcph->rst) { + if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) && tcph->rst) { WRITE_UNLOCK(&tcp_lock); if (del_timer(&conntrack->timeout)) conntrack->timeout.function((unsigned long)conntrack); @@ -211,12 +211,6 @@ static int tcp_new(struct ip_conntrack *conntrack, return 0; } - if (tcph->syn && tcph->ack) - { - DEBUGP("ip_conntrack_tcp: invalid new deleting.\n"); - return 0; - } - conntrack->proto.tcp.state = newconntrack; return 1; } diff --git a/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c b/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c index 49ac62c7..af660a27 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c @@ -7,25 +7,13 @@ #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> #include <linux/netfilter_ipv4/ip_conntrack_udp.h> -unsigned long ip_ct_udp_isakmp_timeout = (300*HZ); - static int udp_pkt_to_tuple(const void *datah, size_t datalen, struct ip_conntrack_tuple *tuple) { const struct udphdr *hdr = datah; - struct isakmp_hdr *isakmp_h = (void *)hdr + 8; tuple->src.u.udp.port = hdr->source; tuple->dst.u.udp.port = hdr->dest; - if(ntohs(hdr->source) == 500 && ntohs(hdr->dest) == 500) - { - if(NULL == isakmp_h) - tuple->dst.u.udp.init_cookie = 0; - else - tuple->dst.u.udp.init_cookie = (unsigned int)(isakmp_h->init_cookie[0]); - } - else - tuple->dst.u.udp.init_cookie = 0; return 1; } @@ -35,7 +23,6 @@ static int udp_invert_tuple(struct ip_conntrack_tuple *tuple, { tuple->src.u.udp.port = orig->dst.u.udp.port; tuple->dst.u.udp.port = orig->src.u.udp.port; - tuple->dst.u.udp.init_cookie = orig->dst.u.udp.init_cookie; return 1; } @@ -60,21 +47,16 @@ static int udp_packet(struct ip_conntrack *conntrack, struct iphdr *iph, size_t len, enum ip_conntrack_info conntrackinfo) { - u_int16_t *portptr; - portptr = &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port; /* If we've seen traffic both ways, this is some kind of UDP stream. Extend timeout. */ - if (conntrack->status & IPS_SEEN_REPLY) - { - if(ntohs(*portptr) == 500) - ip_ct_refresh(conntrack, ip_ct_udp_isakmp_timeout); - else - ip_ct_refresh(conntrack, sysctl_ip_conntrack_udp_timeouts[UDP_STREAM_TIMEOUT]); + if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) { + ip_ct_refresh(conntrack, + sysctl_ip_conntrack_udp_timeouts[UDP_STREAM_TIMEOUT]); /* Also, more likely to be important, and not a probe */ set_bit(IPS_ASSURED_BIT, &conntrack->status); - } - else - ip_ct_refresh(conntrack, sysctl_ip_conntrack_udp_timeouts[UDP_TIMEOUT]); + } else + ip_ct_refresh(conntrack, + sysctl_ip_conntrack_udp_timeouts[UDP_TIMEOUT]); return NF_ACCEPT; } diff --git a/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_standalone.c b/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_standalone.c index c7e31931..78c3062c 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -32,503 +32,6 @@ struct module *ip_conntrack_module = THIS_MODULE; MODULE_LICENSE("GPL"); -#define CLEAR_IP_CONNTRACK -#define DEL_IP_CONNTRACK_ENTRY 1 -#ifdef DEL_IP_CONNTRACK_ENTRY -/* - * - *This part of code add for delete an entry in ip_conntrack table. - * - */ - - -#define DEL_LIST_PATH "/tmp/.del_ip_conntrack" -#define printkerrline() printk("del_ip_conntrack error : %s %s %d\n", __FILE__, __func__, __LINE__) - -struct del_list -{ - unsigned short proto; - unsigned int begin_port; - unsigned int end_port; - unsigned int ip; - struct del_list *next; -}; - -void free_del_list(struct del_list *head); -void print_del_list(struct del_list *head); -static struct del_list * malloc_new_node(const char *buf, struct del_list * head); -struct del_list * init_del_list(const char *buf, size_t size); -static int read_del_file(char * buf, unsigned int size, char *path); -static int del_match_method(const struct ip_conntrack_tuple_hash *pConn, const struct del_list * pList); -static int del_conntrack_check(const struct ip_conntrack_tuple_hash *pConn, const struct del_list * head); -void pf_del_ip_conntrack(void); -static int proc_read_del_ip_conntrack(char *page, char **start, off_t off, int count, int *eof, void *context); -static int proc_write_del_ip_conntrack(struct file *file, const char *buffer, unsigned long count, void *data); -static int end_proc_read(const char *p, char *page, off_t off, int count, char **start, int *eof); - -void pf_del_ip_conntrack(void) -{ -#define MAX_BUF_SIZE 1024*2 - int i; - char buf[MAX_BUF_SIZE]; - struct del_list * del_head = NULL; - struct list_head *head, *temp_head; - struct ip_conntrack_tuple_hash *tuple_hash; - - //printk("pf_del_ip_conntrack---------------------------------------1\n"); - memset(buf, 0, MAX_BUF_SIZE); - - if(read_del_file(buf, MAX_BUF_SIZE, DEL_LIST_PATH) == -1) - { - goto final_return; - } - - buf[MAX_BUF_SIZE - 1] = '\0'; - del_head = init_del_list(buf, MAX_BUF_SIZE - 1); - //print_del_list(del_head); - READ_LOCK(&ip_conntrack_lock); - for (i = 0; i < ip_conntrack_htable_size; i++) - { - head = &ip_conntrack_hash[i]; - temp_head = head; - while(1) - { - temp_head = temp_head->next; - if(temp_head == head) - { - head = NULL; - temp_head = NULL; - break; - } - tuple_hash = (struct ip_conntrack_tuple_hash *)temp_head; - if(del_conntrack_check(tuple_hash, del_head) == 1) - { - del_selected_conntrack(tuple_hash); - } - } - } - READ_UNLOCK(&ip_conntrack_lock); - free_del_list(del_head); - -final_return: - - //printk("pf_del_ip_conntrack---------------------------------------2\n"); - return; -#undef MAX_BUF_SIZE -} - -static int del_conntrack_check(const struct ip_conntrack_tuple_hash *pConn, const struct del_list * head) -{ - int ret; - const struct del_list * p; - - ret = 0; - - if(pConn == NULL || head == NULL) - { - ret = -1; - goto final_return; - } - - for(p = head; p; p = p->next) - { - if(del_match_method(pConn, p) == 1) - { - //Match,jump out - ret = 1; - break; - } - } - -final_return: - return ret; -} - -static int del_match_method(const struct ip_conntrack_tuple_hash *pConn, const struct del_list * pList) -{ - int ret; - typedef enum - { - TCP_PROTO = 0x06, - UDP_PROTO = 0x11, - }proto_type; - proto_type pt[2] = {TCP_PROTO, UDP_PROTO}; - - ret = 0; - //Check tcp and udp only - if(pConn->tuple.dst.protonum == TCP_PROTO || pConn->tuple.dst.protonum == UDP_PROTO) - { - //Check proto match - if((pList->proto == 3) || - ((pList->proto == 0 || pList->proto == 1) && (pConn->tuple.dst.protonum == pt[pList->proto]))) - { - //Chcek ip address match - if(pConn->ctrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip == pList->ip) - { - //Check port match - unsigned int tport; - if(pConn->tuple.dst.protonum == TCP_PROTO) - { - //TCP - tport = pConn->ctrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port; - } - else - { - //UDP - tport = pConn->ctrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.udp.port; - } - tport = htons(tport); - if(tport >= pList->begin_port && tport <= pList->end_port) - { - ret = 1; - } - } - } - } - return ret; -} - -static int read_del_file(char * buf, unsigned int size, char *path) -{ - int retval, orgfsuid, orgfsgid; - mm_segment_t orgfs; - struct file *srcf; - - // Save uid and gid used for filesystem access. - // Set user and group to 0 (root) - orgfsuid = current->fsuid; - orgfsgid = current->fsgid; - current->fsuid=current->fsgid = 0; - orgfs = get_fs(); - set_fs(KERNEL_DS); - - if(path && *path) - { - srcf = filp_open(path, O_RDONLY, 0); - if(IS_ERR(srcf)) - { - printkerrline(); - retval = -1; - goto final_return; - } - else - { - if(srcf->f_op && srcf->f_op->read) - { - memset(buf, 0x00, size); - retval=srcf->f_op->read(srcf, buf, size, &srcf->f_pos); - if(retval < 0) - { - printkerrline(); - retval = -1; - goto final_return; - } - else - { - //Success,go! - retval = 0; - goto final_return; - } - } - else - { - printkerrline(); - retval = -1; - goto final_return; - } - } - } - else - { - printkerrline(); - retval = -1; - goto final_return; - } - -final_return: - if(!IS_ERR(srcf)) - { - retval=filp_close(srcf,NULL); - if(retval) - { - printkerrline(); - retval = -1; - } - } - set_fs(orgfs); - current->fsuid = orgfsuid; - current->fsgid = orgfsgid; - - return retval; -} - -struct del_list * init_del_list(const char *buf, size_t size) -{ -#define LINE_FEED "\n" -#define TMP_BUF_SIZE 100 - const char *begin, *end; - char tmpbuf[TMP_BUF_SIZE]; - struct del_list * head = NULL, *tmp_p; - - if(buf == NULL || size <= 0 || buf[size] != '\0') - { - head = NULL; - goto final_return; - } - - for(begin = end = buf; begin && (begin - buf < size); begin = end + strlen(LINE_FEED)) - { - end = strstr(begin, LINE_FEED); - if(end) - { - if((end - begin) > (TMP_BUF_SIZE - 1)) - { - //Too large,go on - continue; - } - else - { - memcpy(tmpbuf, begin, end - begin); - tmpbuf[end - begin] = '\0'; - //printk("obtain string : %s\n", tmpbuf); - if((tmp_p = malloc_new_node(tmpbuf, head)) == NULL) - { - //Invalid format or malloc fail,go on - continue; - } - else - { - head = tmp_p; - } - } - } - else - { - //printk("Last string : %s\n", begin); - if((tmp_p = malloc_new_node(begin, head)) == NULL) - { - //Invalid format or malloc fail,jump out - break; - } - else - { - head = tmp_p; - } - } - } - -final_return: - return head; - -#undef TMP_BUF_SIZE -#undef LINE_FEED -} - -static struct del_list * malloc_new_node(const char *buf, struct del_list * head) -{ -#define SSCANF_MATCH_NUM 7 - int i, j, k, c1, c2, c3, c4; - struct del_list *p = NULL; - - if(sscanf(buf, "%d %d.%d.%d.%d %d-%d", &i, &c4, &c3, &c2, &c1, &j, &k) != SSCANF_MATCH_NUM) - { - p = NULL; - goto final_return; - } - else - { - if(p = (struct del_list *)kmalloc(sizeof(struct del_list), GFP_ATOMIC)) - { - p->proto = i; - #if 0 - //Big endian - ((char *)&(p->ip))[0] = (char)c1; - ((char *)&(p->ip))[1] = (char)c2; - ((char *)&(p->ip))[2] = (char)c3; - ((char *)&(p->ip))[3] = (char)c4; - #else - //Little endian - ((char *)&(p->ip))[3] = (char)c1; - ((char *)&(p->ip))[2] = (char)c2; - ((char *)&(p->ip))[1] = (char)c3; - ((char *)&(p->ip))[0] = (char)c4; - #endif - p->begin_port = j; - p->end_port = k; - p->next = head; - } - else - { - p = NULL; - goto final_return; - } - } - -final_return: - return p; -#undef SSCANF_MATCH_NUM -} - -void print_del_list(struct del_list *head) -{ - int i; - struct del_list *tmp_p; - - for(i = 1, tmp_p = head; tmp_p; tmp_p = tmp_p->next, i++) - { - printk("Node(%d): proto=%d | ip=%0x | port=[%d-%d]\n", i, tmp_p->proto, tmp_p->ip, tmp_p->begin_port, tmp_p->end_port); - } -} - -void free_del_list(struct del_list *head) -{ - int i; - struct del_list *tmp_p; - - if(head == NULL) - { - goto final_return; - } - for(i = 1, tmp_p = head; head; head = tmp_p, i++) - { - tmp_p = head->next; - //printk("Free@Node(%d):proto=%d | ip=%0x | port=[%d-%d]\n", i, head->proto, head->ip, head->begin_port, head->end_port); - kfree(head); - } - -final_return: - return; -} - -static int proc_read_del_ip_conntrack(char *page, char **start, off_t off, int count, int *eof, void *context) -{ - char *p; - - p = page; - p += sprintf(page, "%s\n", "use echo \"1(0)\" to enable or disbable"); - return end_proc_read(p, page, off, count, start, eof); -} - -static int proc_write_del_ip_conntrack(struct file *file, const char *buffer, unsigned long count, void *data) -{ - unsigned char tmp[2]; - - if(buffer) - { - memset(tmp, 0, sizeof(tmp)); - copy_from_user(tmp, buffer, count); - tmp[1] = 0x00; - switch(*tmp) - { - case '0': - //Do something here - break; - - case '1': - pf_del_ip_conntrack(); - break; - - default: - printk("<1>invalid args\n"); - } - return count; - } - return 0; -} - -static int end_proc_read(const char *p, char *page, off_t off, int count, char **start, int *eof) -{ - int len = p - page; - - if(len < off + count) - { - *eof = 1; - } - - *start = page + off; - len -= off; - if(len > count) - { - len = count; - } - - if(len < 0) - { - len = 0; - } - - return len; -} - -#endif - -#ifdef CLEAR_IP_CONNTRACK -void clear_ip_conntrack(void) -{ - int i; - struct list_head *head, *temp_head; - struct ip_conntrack_tuple_hash *tuple_hash; - - printk("warning : %s %d\n", __func__, __LINE__); - - READ_LOCK(&ip_conntrack_lock); - for (i = 0; i < ip_conntrack_htable_size; i++) - { - head = &ip_conntrack_hash[i]; - temp_head = head; - while(1) - { - temp_head = temp_head->next; - if(temp_head == head) - { - head = NULL; - temp_head = NULL; - break; - } - tuple_hash = (struct ip_conntrack_tuple_hash *)temp_head; - del_selected_conntrack(tuple_hash); - } - } - READ_UNLOCK(&ip_conntrack_lock); -} - -static int proc_read_clear_ip_conntrack(char *page, char **start, off_t off, int count, int *eof, void *context) -{ - char *p; - - p = page; - p += sprintf(page, "%s\n", "use echo \"1(0)\" to enable or disbable"); - return end_proc_read(p, page, off, count, start, eof); -} - -static int proc_write_clear_ip_conntrack(struct file *file, const char *buffer, unsigned long count, void *data) -{ - unsigned char tmp[2]; - - if(buffer) - { - memset(tmp, 0, sizeof(tmp)); - copy_from_user(tmp, buffer, count); - tmp[1] = 0x00; - switch(*tmp) - { - case '0': - //Do something here - break; - - case '1': - clear_ip_conntrack(); - break; - - default: - printk("<1>invalid args\n"); - } - return count; - } - return 0; -} -#endif - static int kill_proto(const struct ip_conntrack *i, void *data) { return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == @@ -575,7 +78,7 @@ print_expect(char *buffer, const struct ip_conntrack_expect *expect) } static unsigned int -print_conntrack(char *buffer, const struct ip_conntrack *conntrack) +print_conntrack(char *buffer, struct ip_conntrack *conntrack) { unsigned int len; struct ip_conntrack_protocol *proto @@ -593,15 +96,38 @@ print_conntrack(char *buffer, const struct ip_conntrack *conntrack) len += print_tuple(buffer + len, &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple, proto); - if (!(conntrack->status & IPS_SEEN_REPLY)) + if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status))) len += sprintf(buffer + len, "[UNREPLIED] "); len += print_tuple(buffer + len, &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple, proto); - if (conntrack->status & IPS_ASSURED) + if (test_bit(IPS_ASSURED_BIT, &conntrack->status)) len += sprintf(buffer + len, "[ASSURED] "); len += sprintf(buffer + len, "use=%u ", atomic_read(&conntrack->ct_general.use)); +#if defined(CONFIG_IP_NF_CONNTRACK_MARK) + len += sprintf(buffer + len, "mark=%ld ", conntrack->mark); +#endif +#if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE) + if(conntrack->layer7.app_proto) + len += sprintf(buffer + len, "l7proto=%s ", + conntrack->layer7.app_proto); +#endif +#if defined(CONFIG_IP_NF_TARGET_MACSAVE) || defined(CONFIG_IP_NF_TARGET_MACSAVE_MODULE) + if ((*((u32 *)conntrack->macsave) != 0) || (*((u16*)(conntrack->macsave + 4)) != 0)) { + len += sprintf(buffer + len, "macsave=%02X:%02X:%02X:%02X:%02X:%02X ", + conntrack->macsave[0], conntrack->macsave[1], conntrack->macsave[2], + conntrack->macsave[3], conntrack->macsave[4], conntrack->macsave[5]); + } +#endif +#if defined(CONFIG_IP_NF_TARGET_BCOUNT) || defined(CONFIG_IP_NF_TARGET_BCOUNT_MODULE) +#if 0 + if (conntrack->bcount != 0) { +// len += sprintf(buffer + len, "bcount=0x%lx ", conntrack->bcount); + len += sprintf(buffer + len, "bcount=%ldK ", conntrack->bcount / 1024); + } +#endif +#endif len += sprintf(buffer + len, "\n"); return len; @@ -748,30 +274,6 @@ static int init_or_cleanup(int init) if (ret < 0) goto cleanup_nothing; -#ifdef DEL_IP_CONNTRACK_ENTRY - proc = proc_net_create("del_ip_conntrack", S_IFREG | S_IRUGO | S_IWUSR, proc_read_del_ip_conntrack); - if(proc) - { - proc->write_proc = proc_write_del_ip_conntrack; - proc->owner = THIS_MODULE; - } - else - { - //Maybe we can just let it go! - } -#endif -#ifdef CLEAR_IP_CONNTRACK - proc = proc_net_create("clear_ip_conntrack", S_IFREG | S_IRUGO | S_IWUSR, proc_read_clear_ip_conntrack); - if(proc) - { - proc->write_proc = proc_write_clear_ip_conntrack; - proc->owner = THIS_MODULE; - } - else - { - //Maybe we can just let it go! - } -#endif proc = proc_net_create("ip_conntrack",0,list_conntracks); if (!proc) goto cleanup_init; proc->owner = THIS_MODULE; diff --git a/release/src/linux/linux/net/ipv4/netfilter/ip_nat_core.c b/release/src/linux/linux/net/ipv4/netfilter/ip_nat_core.c index f64ddabf..de6b4925 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ip_nat_core.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ip_nat_core.c @@ -763,12 +763,11 @@ do_bindings(struct ip_conntrack *ct, /* if this expectation is already established, skip */ if (exp->sibling) { - //lzh add 2007/3/16 for fix sip alg CDROUTE test - exp = NULL; - //lzh end +#if 0 // removed 1.11 forward bug test + exp = NULL; // lzh add 2007/3/16 for fix sip alg CDROUTE test +#endif continue; } - if (exp_for_packet(exp, pskb)) { DEBUGP("calling nat helper (exp=%p) for packet\n", diff --git a/release/src/linux/linux/net/ipv4/netfilter/ip_nat_h323.c b/release/src/linux/linux/net/ipv4/netfilter/ip_nat_h323.c index 2c080cf3..bcf886e8 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ip_nat_h323.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ip_nat_h323.c @@ -129,7 +129,7 @@ h225_nat_expected(struct sk_buff **pskb, mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; mr.range[0].min = mr.range[0].max = ((union ip_conntrack_manip_proto) - { port }); + { .tcp = { port } }); } ret = ip_nat_setup_info(ct, &mr, hooknum); @@ -184,12 +184,14 @@ static int h323_signal_address_fixup(struct ip_conntrack *ct, if (!between(info->seq[i] + 6, ntohl(tcph->seq), ntohl(tcph->seq) + datalen)) { /* Partial retransmisison. It's a cracker being funky. */ +#if 0 // ... or a miss id? zzz if (net_ratelimit()) { printk("H.323_NAT: partial packet %u/6 in %u/%u\n", info->seq[i], ntohl(tcph->seq), ntohl(tcph->seq) + datalen); } +#endif return 0; } @@ -252,18 +254,18 @@ static int h323_data_fixup(struct ip_ct_h225_expect *info, DEBUGP("h323_data_fixup: offset %u + 6 in %u\n", info->offset, tcplen); DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); - - memset(&newtuple, 0, sizeof(newtuple)); if (!between(expect->seq + 6, ntohl(tcph->seq), ntohl(tcph->seq) + tcplen - tcph->doff * 4)) { /* Partial retransmisison. It's a cracker being funky. */ +#if 1 // also caused by bad id? if (net_ratelimit()) { printk("H.323_NAT: partial packet %u/6 in %u/%u\n", expect->seq, ntohl(tcph->seq), ntohl(tcph->seq) + tcplen - tcph->doff * 4); } +#endif return 0; } @@ -392,9 +394,9 @@ static struct ip_nat_helper h225 = "H.225", /* name */ IP_NAT_HELPER_F_ALWAYS, /* flags */ THIS_MODULE, /* module */ - { { 0, { __constant_htons(H225_PORT) } }, /* tuple */ + { { 0, { .tcp = { __constant_htons(H225_PORT) } } }, /* tuple */ { 0, { 0 }, IPPROTO_TCP } }, - { { 0, { 0xFFFF } }, /* mask */ + { { 0, { .tcp = { 0xFFFF } } }, /* mask */ { 0, { 0 }, 0xFFFF } }, h225_nat_help, /* helper */ h225_nat_expected /* expectfn */ diff --git a/release/src/linux/linux/net/ipv4/netfilter/ip_nat_helper.c b/release/src/linux/linux/net/ipv4/netfilter/ip_nat_helper.c index ffde5133..e7987430 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ip_nat_helper.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ip_nat_helper.c @@ -79,7 +79,6 @@ ip_nat_resize_packet(struct sk_buff **skb, iph = (*skb)->nh.iph; if (iph->protocol == IPPROTO_TCP) { struct tcphdr *tcph = (void *)iph + iph->ihl*4; - void *data = (void *)tcph + tcph->doff*4; DEBUGP("ip_nat_resize_packet: Seq_offset before: "); DUMP_OFFSET(this_way); @@ -354,54 +353,49 @@ sack_adjust(struct tcphdr *tcph, } -/* TCP SACK sequence number adjustment, return 0 if sack found and adjusted */ -static inline int +/* TCP SACK sequence number adjustment. */ +static inline void ip_nat_sack_adjust(struct sk_buff *skb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { - struct iphdr *iph; struct tcphdr *tcph; - unsigned char *ptr; - int length, dir, sack_adjusted = 0; + unsigned char *ptr, *optend; + unsigned int dir; - iph = skb->nh.iph; - tcph = (void *)iph + iph->ihl*4; - length = (tcph->doff*4)-sizeof(struct tcphdr); + tcph = (void *)skb->nh.iph + skb->nh.iph->ihl*4; + optend = (unsigned char *)tcph + tcph->doff*4; ptr = (unsigned char *)(tcph+1); dir = CTINFO2DIR(ctinfo); - while (length > 0) { - int opcode = *ptr++; + while (ptr < optend) { + int opcode = ptr[0]; int opsize; switch (opcode) { case TCPOPT_EOL: - return !sack_adjusted; + return; case TCPOPT_NOP: - length--; + ptr++; continue; default: - opsize = *ptr++; - if (opsize > length) /* no partial opts */ - return !sack_adjusted; + opsize = ptr[1]; + /* no partial opts */ + if (ptr + opsize > optend || opsize < 2) + return; if (opcode == TCPOPT_SACK) { /* found SACK */ if((opsize >= (TCPOLEN_SACK_BASE +TCPOLEN_SACK_PERBLOCK)) && !((opsize - TCPOLEN_SACK_BASE) % TCPOLEN_SACK_PERBLOCK)) - sack_adjust(tcph, ptr-2, + sack_adjust(tcph, ptr, &ct->nat.info.seq[!dir]); - - sack_adjusted = 1; } - ptr += opsize-2; - length -= opsize; + ptr += opsize; } } - return !sack_adjusted; } /* TCP sequence number adjustment */ diff --git a/release/src/linux/linux/net/ipv4/netfilter/ip_nat_pptp.c b/release/src/linux/linux/net/ipv4/netfilter/ip_nat_pptp.c index 71077933..358a4579 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ip_nat_pptp.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ip_nat_pptp.c @@ -1,5 +1,5 @@ /* - * ip_nat_pptp.c - Version 1.11 + * ip_nat_pptp.c - Version 1.5 * * NAT support for PPTP (Point to Point Tunneling Protocol). * PPTP is a a protocol for creating virtual private networks. @@ -9,7 +9,7 @@ * GRE is defined in RFC 1701 and RFC 1702. Documentation of * PPTP can be found in RFC 2637 * - * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org> + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org> * * Development of this code funded by Astaro AG (http://www.astaro.com/) * @@ -17,7 +17,18 @@ * (needs netfilter newnat code) * - NAT to a unique tuple, not to TCP source port * (needs netfilter tuple reservation) - * - Support other NAT scenarios than SNAT of PNS + * + * Changes: + * 2002-02-10 - Version 1.3 + * - Use ip_nat_mangle_tcp_packet() because of cloned skb's + * in local connections (Philip Craig <philipc@snapgear.com>) + * - add checks for magicCookie and pptp version + * - make argument list of pptp_{out,in}bound_packet() shorter + * - move to C99 style initializers + * - print version number at module loadtime + * 2003-09-22 - Version 1.5 + * - use SNATed tcp sourceport as callid, since we get called before + * TCP header is mangled (Philip Craig <philipc@snapgear.com>) * */ @@ -34,6 +45,8 @@ #include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> #include <linux/netfilter_ipv4/ip_conntrack_pptp.h> +#define IP_NAT_PPTP_VERSION "1.5" + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP"); @@ -57,7 +70,7 @@ pptp_nat_expected(struct sk_buff **pskb, struct ip_nat_multi_range mr; struct ip_ct_pptp_master *ct_pptp_info; struct ip_nat_pptp *nat_pptp_info; - u_int32_t newsrcip, newdstip, newcid; + u_int32_t newip, newcid; int ret; IP_NF_ASSERT(info); @@ -72,7 +85,7 @@ pptp_nat_expected(struct sk_buff **pskb, /* need to alter GRE tuple because conntrack expectfn() used 'wrong' * (unmanipulated) values */ - if (hooknum == NF_IP_PRE_ROUTING) { + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { DEBUGP("completing tuples with NAT info \n"); /* we can do this, since we're unconfirmed */ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == @@ -80,68 +93,43 @@ pptp_nat_expected(struct sk_buff **pskb, /* assume PNS->PAC */ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = htonl(nat_pptp_info->pns_call_id); -// ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.gre.key = -// htonl(nat_pptp_info->pac_call_id); ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = htonl(nat_pptp_info->pns_call_id); + newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; + newcid = htonl(nat_pptp_info->pac_call_id); } else { /* assume PAC->PNS */ - DEBUGP("WRONG DIRECTION\n"); ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = htonl(nat_pptp_info->pac_call_id); ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = htonl(nat_pptp_info->pac_call_id); - } - } - - if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) - { - if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == htonl(ct_pptp_info->pac_call_id)) - { - /* assume PNS->PAC */ - newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; - newcid = htonl(nat_pptp_info->pac_call_id); - } - else - { - /* assume PAC->PNS */ - newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; + newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; newcid = htonl(nat_pptp_info->pns_call_id); } - mr.rangesize = 1; - mr.range[0].flags = IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED; - mr.range[0].min_ip = mr.range[0].max_ip = newdstip; - mr.range[0].min = mr.range[0].max = - ((union ip_conntrack_manip_proto ) { newcid }); - DEBUGP("change dest ip to %u.%u.%u.%u\n", - NIPQUAD(newdstip)); - DEBUGP("change dest key to 0x%x\n", ntohl(newcid)); - ret = ip_nat_setup_info(ct, &mr, hooknum); } else { - if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == htonl(ct_pptp_info->pac_call_id)) - { - newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == + htonl(ct_pptp_info->pac_call_id)) { + /* assume PNS->PAC */ + newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; newcid = htonl(ct_pptp_info->pns_call_id); } - else - { + else { /* assume PAC->PNS */ - newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; + newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; newcid = htonl(ct_pptp_info->pac_call_id); } - - mr.rangesize = 1; - mr.range[0].flags = IP_NAT_RANGE_MAP_IPS - |IP_NAT_RANGE_PROTO_SPECIFIED; - mr.range[0].min_ip = mr.range[0].max_ip = newsrcip; - mr.range[0].min = mr.range[0].max = - ((union ip_conntrack_manip_proto ) { newcid }); - DEBUGP("change src ip to %u.%u.%u.%u\n", - NIPQUAD(newsrcip)); - DEBUGP("change 'src' key to 0x%x\n", ntohl(newcid)); - ret = ip_nat_setup_info(ct, &mr, hooknum); } + mr.rangesize = 1; + mr.range[0].flags = IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED; + mr.range[0].min_ip = mr.range[0].max_ip = newip; + mr.range[0].min = mr.range[0].max = + ((union ip_conntrack_manip_proto ) { newcid }); + DEBUGP("change ip to %u.%u.%u.%u\n", + NIPQUAD(newip)); + DEBUGP("change key to 0x%x\n", ntohl(newcid)); + ret = ip_nat_setup_info(ct, &mr, hooknum); + UNLOCK_BH(&ip_pptp_lock); return ret; @@ -150,13 +138,17 @@ pptp_nat_expected(struct sk_buff **pskb, /* outbound packets == from PNS to PAC */ static inline unsigned int -pptp_outbound_pkt(struct tcphdr *tcph, struct pptp_pkt_hdr *pptph, - size_t datalen, +pptp_outbound_pkt(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, struct ip_conntrack_expect *exp) { + struct iphdr *iph = (*pskb)->nh.iph; + struct tcphdr *tcph = (void *) iph + iph->ihl*4; + struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *) + ((void *)tcph + tcph->doff*4); + struct PptpControlHeader *ctlh; union pptp_ctrl_union pptpReq; struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; @@ -164,6 +156,7 @@ pptp_outbound_pkt(struct tcphdr *tcph, struct pptp_pkt_hdr *pptph, u_int16_t msg, *cid = NULL, new_callid; + /* FIXME: size checks !!! */ ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph)); pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh)); @@ -172,11 +165,18 @@ pptp_outbound_pkt(struct tcphdr *tcph, struct pptp_pkt_hdr *pptph, switch (msg = ntohs(ctlh->messageType)) { case PPTP_OUT_CALL_REQUEST: cid = &pptpReq.ocreq->callID; + /* FIXME: ideally we would want to reserve a call ID + * here. current netfilter NAT core is not able to do + * this :( For now we use TCP source port. This breaks + * multiple calls within one control session */ /* save original call ID in nat_info */ nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id; - new_callid = tcph->source; + /* don't use tcph->source since we are at a DSTmanip + * hook (e.g. PREROUTING) and pkt is not mangled yet */ + new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port; + /* save new call ID in ct info */ ct_pptp_info->pns_call_id = ntohs(new_callid); break; @@ -186,10 +186,6 @@ pptp_outbound_pkt(struct tcphdr *tcph, struct pptp_pkt_hdr *pptph, case PPTP_CALL_CLEAR_REQUEST: cid = &pptpReq.clrreq->callID; break; - case PPTP_CALL_DISCONNECT_NOTIFY: - cid = &pptpReq.disc->callID; - break; - default: DEBUGP("unknown outbound packet 0x%04x:%s\n", msg, (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]); @@ -204,11 +200,6 @@ pptp_outbound_pkt(struct tcphdr *tcph, struct pptp_pkt_hdr *pptph, case PPTP_ECHO_REQUEST: case PPTP_ECHO_REPLY: /* no need to alter packet */ - DEBUGP("outbound control message %s\n", strMName[msg]); - DEBUGP("ct->pac_call_id = %d\n", ct_pptp_info->pac_call_id); - DEBUGP("ct->pns_call_id = %d\n", ct_pptp_info->pns_call_id); - DEBUGP("nat->pac_call_id = %d\n", nat_pptp_info->pac_call_id); - DEBUGP("nat->pns_call_id = %d\n", nat_pptp_info->pns_call_id); return NF_ACCEPT; } @@ -216,27 +207,27 @@ pptp_outbound_pkt(struct tcphdr *tcph, struct pptp_pkt_hdr *pptph, DEBUGP("altering call id from 0x%04x to 0x%04x\n", ntohs(*cid), ntohs(new_callid)); + /* mangle packet */ - tcph->check = ip_nat_cheat_check(*cid^0xFFFF, - new_callid, tcph->check); - *cid = new_callid; - - DEBUGP("outbound control message %s\n", strMName[msg]); - DEBUGP("ct->pac_call_id = %d\n", ct_pptp_info->pac_call_id); - DEBUGP("ct->pns_call_id = %d\n", ct_pptp_info->pns_call_id); - DEBUGP("nat->pac_call_id = %d\n", nat_pptp_info->pac_call_id); - DEBUGP("nat->pns_call_id = %d\n", nat_pptp_info->pns_call_id); + ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)cid - (void *)pptph, + sizeof(new_callid), (char *)&new_callid, + sizeof(new_callid)); + return NF_ACCEPT; } /* inbound packets == from PAC to PNS */ static inline unsigned int -pptp_inbound_pkt(struct tcphdr *tcph, struct pptp_pkt_hdr *pptph, - size_t datalen, +pptp_inbound_pkt(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, struct ip_conntrack_expect *oldexp) { + struct iphdr *iph = (*pskb)->nh.iph; + struct tcphdr *tcph = (void *) iph + iph->ihl*4; + struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *) + ((void *)tcph + tcph->doff*4); + struct PptpControlHeader *ctlh; union pptp_ctrl_union pptpReq; struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; @@ -245,8 +236,10 @@ pptp_inbound_pkt(struct tcphdr *tcph, struct pptp_pkt_hdr *pptph, u_int16_t msg, new_cid = 0, new_pcid, *pcid = NULL, *cid = NULL; u_int32_t old_dst_ip; - struct ip_conntrack_tuple t; + struct ip_conntrack_tuple t, inv_t; + struct ip_conntrack_tuple *orig_t, *reply_t; + /* FIXME: size checks !!! */ ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph)); pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh)); @@ -262,23 +255,30 @@ pptp_inbound_pkt(struct tcphdr *tcph, struct pptp_pkt_hdr *pptph, } old_dst_ip = oldexp->tuple.dst.ip; t = oldexp->tuple; + invert_tuplepr(&inv_t, &t); /* save original PAC call ID in nat_info */ nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id; - /* store new callID in ct_info, so conntrack works */ - //ct_pptp_info->pac_call_id = ntohs(tcph->source); - //new_cid = htons(ct_pptp_info->pac_call_id); - /* alter expectation */ - if (t.dst.ip == ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip) { + orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; + if (t.src.ip == orig_t->src.ip && t.dst.ip == orig_t->dst.ip) { /* expectation for PNS->PAC direction */ - t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id); t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id); + t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id); + inv_t.src.ip = reply_t->src.ip; + inv_t.dst.ip = reply_t->dst.ip; + inv_t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id); + inv_t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id); } else { /* expectation for PAC->PNS direction */ - t.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; - DEBUGP("EXPECTATION IN WRONG DIRECTION!!!\n"); + t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id); + t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id); + inv_t.src.ip = orig_t->src.ip; + inv_t.dst.ip = orig_t->dst.ip; + inv_t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id); + inv_t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id); } if (!ip_conntrack_change_expect(oldexp, &t)) { @@ -287,13 +287,7 @@ pptp_inbound_pkt(struct tcphdr *tcph, struct pptp_pkt_hdr *pptph, DEBUGP("can't change expect\n"); } ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_orig, &t); - /* reply keymap */ - t.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; - t.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; - t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id); - t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id); - ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_reply, &t); - + ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_reply, &inv_t); break; case PPTP_IN_CALL_CONNECT: pcid = &pptpReq.iccon->peersCallID; @@ -323,9 +317,10 @@ pptp_inbound_pkt(struct tcphdr *tcph, struct pptp_pkt_hdr *pptph, case PPTP_WAN_ERROR_NOTIFY: pcid = &pptpReq.wanerr->peersCallID; break; - case PPTP_SET_LINK_INFO: - pcid = &pptpReq.setlink->peersCallID; + case PPTP_CALL_DISCONNECT_NOTIFY: + pcid = &pptpReq.disc->callID; break; + default: DEBUGP("unknown inbound packet %s\n", (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]); @@ -334,14 +329,10 @@ pptp_inbound_pkt(struct tcphdr *tcph, struct pptp_pkt_hdr *pptph, case PPTP_START_SESSION_REQUEST: case PPTP_START_SESSION_REPLY: case PPTP_STOP_SESSION_REQUEST: + case PPTP_STOP_SESSION_REPLY: case PPTP_ECHO_REQUEST: case PPTP_ECHO_REPLY: /* no need to alter packet */ - DEBUGP("inbound control message %s\n", strMName[msg]); - DEBUGP("ct->pac_call_id = %d\n", ct_pptp_info->pac_call_id); - DEBUGP("ct->pns_call_id = %d\n", ct_pptp_info->pns_call_id); - DEBUGP("nat->pac_call_id = %d\n", nat_pptp_info->pac_call_id); - DEBUGP("nat->pns_call_id = %d\n", nat_pptp_info->pns_call_id); return NF_ACCEPT; } @@ -349,25 +340,21 @@ pptp_inbound_pkt(struct tcphdr *tcph, struct pptp_pkt_hdr *pptph, IP_NF_ASSERT(pcid); DEBUGP("altering peer call id from 0x%04x to 0x%04x\n", ntohs(*pcid), ntohs(new_pcid)); - tcph->check = ip_nat_cheat_check(*pcid^0xFFFF, - new_pcid, tcph->check); - *pcid = new_pcid; + ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)pcid - (void *)pptph, + sizeof(new_pcid), (char *)&new_pcid, + sizeof(new_pcid)); if (new_cid) { IP_NF_ASSERT(cid); DEBUGP("altering call id from 0x%04x to 0x%04x\n", ntohs(*cid), ntohs(new_cid)); - tcph->check = ip_nat_cheat_check(*cid^0xFFFF, - new_cid, tcph->check); - *cid = new_cid; + ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, + (void *)cid - (void *)pptph, + sizeof(new_cid), (char *)&new_cid, + sizeof(new_cid)); } /* great, at least we don't need to resize packets */ - DEBUGP("inbound control message %s\n", strMName[msg]); - DEBUGP("ct->pac_call_id = %d\n", ct_pptp_info->pac_call_id); - DEBUGP("ct->pns_call_id = %d\n", ct_pptp_info->pns_call_id); - DEBUGP("nat->pac_call_id = %d\n", nat_pptp_info->pac_call_id); - DEBUGP("nat->pns_call_id = %d\n", nat_pptp_info->pns_call_id); return NF_ACCEPT; } @@ -387,12 +374,13 @@ static unsigned int tcp_help(struct ip_conntrack *ct, DEBUGP("entering\n"); - /* Only mangle things once: original direction in POST_ROUTING - and reply direction on PRE_ROUTING. */ + /* Only mangle things once: DST for original direction + and SRC for reply direction. */ dir = CTINFO2DIR(ctinfo); - if (!((HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC && dir == IP_CT_DIR_ORIGINAL) - || (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST && dir == IP_CT_DIR_REPLY))) - { + if (!((HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC + && dir == IP_CT_DIR_ORIGINAL) + || (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST + && dir == IP_CT_DIR_REPLY))) { DEBUGP("Not touching dir %s at hook %s\n", dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" @@ -409,13 +397,11 @@ static unsigned int tcp_help(struct ip_conntrack *ct, return NF_ACCEPT; } - pptph = (struct pptp_pkt_hdr *) ((void *)tcph + tcph->doff*4); /* if it's not a control message, we can't handle it */ if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL || - ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) - { + ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) { DEBUGP("not a pptp control packet\n"); return NF_ACCEPT; } @@ -424,10 +410,10 @@ static unsigned int tcp_help(struct ip_conntrack *ct, if (dir == IP_CT_DIR_ORIGINAL) { /* reuqests sent by client to server (PNS->PAC) */ - pptp_outbound_pkt(tcph, pptph, datalen, ct, ctinfo, exp); + pptp_outbound_pkt(pskb, ct, ctinfo, exp); } else { /* response from the server to the client (PAC->PNS) */ - pptp_inbound_pkt(tcph, pptph, datalen, ct, ctinfo, exp); + pptp_inbound_pkt(pskb, ct, ctinfo, exp); } UNLOCK_BH(&ip_pptp_lock); @@ -437,29 +423,52 @@ static unsigned int tcp_help(struct ip_conntrack *ct, /* nat helper struct for control connection */ static struct ip_nat_helper pptp_tcp_helper = { - { NULL, NULL }, - "pptp", IP_NAT_HELPER_F_ALWAYS, THIS_MODULE, - { { 0, { tcp: { port: __constant_htons(PPTP_CONTROL_PORT) } } }, - { 0, { 0 }, IPPROTO_TCP } }, - { { 0, { tcp: { port: 0xFFFF } } }, - { 0, { 0 }, 0xFFFF } }, - tcp_help, pptp_nat_expected }; + .list = { NULL, NULL }, + .name = "pptp", + .flags = IP_NAT_HELPER_F_ALWAYS, + .me = THIS_MODULE, + .tuple = { .src = { .ip = 0, + .u = { .tcp = { .port = + __constant_htons(PPTP_CONTROL_PORT) } + } + }, + .dst = { .ip = 0, + .u = { .all = 0 }, + .protonum = IPPROTO_TCP + } + }, + + .mask = { .src = { .ip = 0, + .u = { .tcp = { .port = 0xFFFF } } + }, + .dst = { .ip = 0, + .u = { .all = 0 }, + .protonum = 0xFFFF + } + }, + .help = tcp_help, + .expect = pptp_nat_expected +}; static int __init init(void) { - DEBUGP("init_module\n" ); - - if (ip_nat_helper_register(&pptp_tcp_helper)) + DEBUGP("%s: registering NAT helper\n", __FILE__); + if (ip_nat_helper_register(&pptp_tcp_helper)) { + printk(KERN_ERR "Unable to register NAT application helper " + "for pptp\n"); return -EIO; + } - return 0; + printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION); + return 0; } static void __exit fini(void) { DEBUGP("cleanup_module\n" ); - ip_nat_helper_unregister(&pptp_tcp_helper); + ip_nat_helper_unregister(&pptp_tcp_helper); + printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION); } module_init(init); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ip_nat_proto_esp.c b/release/src/linux/linux/net/ipv4/netfilter/ip_nat_proto_esp.c index a985539e..a985539e 100755..100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ip_nat_proto_esp.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ip_nat_proto_esp.c diff --git a/release/src/linux/linux/net/ipv4/netfilter/ip_nat_proto_gre.c b/release/src/linux/linux/net/ipv4/netfilter/ip_nat_proto_gre.c index 25aa1786..9be95857 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ip_nat_proto_gre.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ip_nat_proto_gre.c @@ -1,5 +1,5 @@ /* - * ip_nat_proto_gre.c - Version 1.11 + * ip_nat_proto_gre.c - Version 1.2 * * NAT protocol helper module for GRE. * @@ -17,7 +17,7 @@ * * Documentation about PPTP can be found in RFC 2637 * - * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org> + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org> * * Development of this code funded by Astaro AG (http://www.astaro.com/) * @@ -35,7 +35,12 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE"); +#if 0 +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \ + ": " format, ## args) +#else #define DEBUGP(x, args...) +#endif /* is key in given range between min and max */ static int @@ -44,8 +49,15 @@ gre_in_range(const struct ip_conntrack_tuple *tuple, const union ip_conntrack_manip_proto *min, const union ip_conntrack_manip_proto *max) { - return ntohl(tuple->src.u.gre.key) >= ntohl(min->gre.key) - && ntohl(tuple->src.u.gre.key) <= ntohl(max->gre.key); + u_int32_t key; + + if (maniptype == IP_NAT_MANIP_SRC) + key = tuple->src.u.gre.key; + else + key = tuple->dst.u.gre.key; + + return ntohl(key) >= ntohl(min->gre.key) + && ntohl(key) <= ntohl(max->gre.key); } /* generate unique tuple ... */ @@ -122,6 +134,7 @@ gre_manip_pkt(struct iphdr *iph, size_t len, break; } if (greh->csum) { + /* FIXME: Never tested this code... */ *(gre_csum(greh)) = ip_nat_cheat_check(~*(gre_key(greh)), manip->u.gre.key, diff --git a/release/src/linux/linux/net/ipv4/netfilter/ip_nat_proto_udp.c b/release/src/linux/linux/net/ipv4/netfilter/ip_nat_proto_udp.c index 05aefcd4..622aee05 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ip_nat_proto_udp.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ip_nat_proto_udp.c @@ -40,9 +40,6 @@ udp_unique_tuple(struct ip_conntrack_tuple *tuple, else portptr = &tuple->dst.u.udp.port; - if(ntohs(*portptr) == 500) - return 0;//must not be "return 1" - /* If no range specified... */ if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { /* If it's dst rewrite, can't change port */ diff --git a/release/src/linux/linux/net/ipv4/netfilter/ip_tables.c b/release/src/linux/linux/net/ipv4/netfilter/ip_tables.c index 99438ca0..2e3004db 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ip_tables.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ip_tables.c @@ -332,7 +332,7 @@ ipt_do_table(struct sk_buff **pskb, continue; } if (table_base + v - != (void *)e + e->next_offset) { + != (void *)e + e->next_offset && !(e->ip.flags & IPT_F_GOTO)) { /* Save old back ptr in next entry */ struct ipt_entry *next = (void *)e + e->next_offset; @@ -374,6 +374,12 @@ ipt_do_table(struct sk_buff **pskb, if (verdict == IPT_CONTINUE) e = (void *)e + e->next_offset; + else if (verdict == IPT_RETURN) { // added -- zzz + e = back; + back = get_entry(table_base, + back->comefrom); + continue; + } else /* Verdict */ break; @@ -1169,13 +1175,11 @@ do_add_counters(void *user, unsigned int len) goto free; write_lock_bh(&t->lock); - /************************************* - * modify by tanghui @ 2006-10-11 - * for a RACE CONDITION in the "do_add_counters()" function - *************************************/ - //if (t->private->number != paddc->num_counters) { - if (t->private->number != tmp.num_counters) { - /*************************************/ + +#if 0 // removed 1.11 forward bug test + // if (t->private->number != tmp.num_counters) { // 43011: modify by tanghui @ 2006-10-11 for a RACE CONDITION in the "do_add_counters()" function +#endif + if (t->private->number != paddc->num_counters) { ret = -EINVAL; goto unlock_up_free; } @@ -1676,7 +1680,7 @@ static struct ipt_match icmp_matchstruct = { { NULL, NULL }, "icmp", &icmp_match, &icmp_checkentry, NULL }; #ifdef CONFIG_PROC_FS -static inline int print_name(const char *i, +static int print_name(const char *i, off_t start_offset, char *buffer, int length, off_t *pos, unsigned int *count) { @@ -1694,6 +1698,15 @@ static inline int print_name(const char *i, return 0; } +static inline int print_target(const struct ipt_target *t, + off_t start_offset, char *buffer, int length, + off_t *pos, unsigned int *count) +{ + if (t == &ipt_standard_target || t == &ipt_error_target) + return 0; + return print_name((char *)t, start_offset, buffer, length, pos, count); +} + static int ipt_get_tables(char *buffer, char **start, off_t offset, int length) { off_t pos = 0; @@ -1720,7 +1733,7 @@ static int ipt_get_targets(char *buffer, char **start, off_t offset, int length) if (down_interruptible(&ipt_mutex) != 0) return 0; - LIST_FIND(&ipt_target, print_name, void *, + LIST_FIND(&ipt_target, print_target, struct ipt_target *, offset, buffer, length, &pos, &count); up(&ipt_mutex); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_BCOUNT.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_BCOUNT.c new file mode 100644 index 00000000..b40e7e2e --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_BCOUNT.c @@ -0,0 +1,63 @@ +/* + + BCOUNT target + Copyright (C) 2006 Jonathan Zarate + + Licensed under GNU GPL v2 or later. + +*/ +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/if_ether.h> + +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ip_conntrack.h> +#include <linux/netfilter_ipv4/ipt_BCOUNT.h> + +// #define DEBUG_BCOUNT + +static unsigned int target(struct sk_buff **pskb, unsigned int hooknum, + const struct net_device *in, const struct net_device *out, + const void *targinfo, void *userinfo) +{ + struct ip_conntrack *ct; + enum ip_conntrack_info ctinfo; + + ct = ip_conntrack_get(*pskb, &ctinfo); + if (ct) { + ct->bcount += (*pskb)->len; + if (ct->bcount >= 0x0FFFFFFF) ct->bcount = 0x0FFFFFFF; +#ifdef DEBUG_BCOUNT + if (net_ratelimit()) + printf(KERN_DEBUG "BCOUNT %lx %lx\n", (*pskb)->len, ct->bcount); +#endif + } + return IPT_CONTINUE; +} + +static int checkentry(const char *tablename, const struct ipt_entry *e, void *targinfo, + unsigned int targinfosize, unsigned int hook_mask) +{ + return (targinfosize == IPT_ALIGN(sizeof(struct ipt_BCOUNT_target))); +} + +static struct ipt_target BCOUNT_target += { { NULL, NULL }, "BCOUNT", target, checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_target(&BCOUNT_target); +} + +static void __exit fini(void) +{ + ipt_unregister_target(&BCOUNT_target); +} + +module_init(init); +module_exit(fini); + + +MODULE_AUTHOR("Jonathan Zarate"); +MODULE_DESCRIPTION("BCOUNT target"); +MODULE_LICENSE("GPL"); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_CLASSIFY.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_CLASSIFY.c new file mode 100644 index 00000000..f7320721 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_CLASSIFY.c @@ -0,0 +1,82 @@ +/* + * This is a module which is used for setting the skb->priority field + * of an skb for qdisc classification. + */ + +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/ip.h> +#include <net/checksum.h> + +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ipt_CLASSIFY.h> + +MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("iptables qdisc classification target module"); + +static unsigned int +target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + const struct ipt_classify_target_info *clinfo = targinfo; + + if((*pskb)->priority != clinfo->priority) { + (*pskb)->priority = clinfo->priority; + (*pskb)->nfcache |= NFC_ALTERED; + } + + return IPT_CONTINUE; +} + +static int +checkentry(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_classify_target_info))){ + printk(KERN_ERR "CLASSIFY: invalid size (%u != %u).\n", + targinfosize, + IPT_ALIGN(sizeof(struct ipt_classify_target_info))); + return 0; + } + + if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) { + printk(KERN_ERR "CLASSIFY: only valid in POST_ROUTING.\n"); + return 0; + } + + if (strcmp(tablename, "mangle") != 0) { + printk(KERN_WARNING "CLASSIFY: can only be called from " + "\"mangle\" table, not \"%s\".\n", + tablename); + return 0; + } + + return 1; +} + +static struct ipt_target ipt_classify_reg += { { NULL, NULL }, "CLASSIFY", target, checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + if (ipt_register_target(&ipt_classify_reg)) + return -EINVAL; + + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_classify_reg); +} + +module_init(init); +module_exit(fini); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_CONNMARK.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_CONNMARK.c new file mode 100644 index 00000000..a6038378 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_CONNMARK.c @@ -0,0 +1,128 @@ +/* This kernel module is used to modify the connection mark values, or + * to optionally restore the skb nfmark from the connection mark + * + * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com> + * by Henrik Nordstrom <hno@marasystems.com> + * + * 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 + */ +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/ip.h> +#include <net/checksum.h> + +MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>"); +MODULE_DESCRIPTION("IP tables CONNMARK matching module"); +MODULE_LICENSE("GPL"); + +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ipt_CONNMARK.h> +#include <linux/netfilter_ipv4/ip_conntrack.h> + +static unsigned int +target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + const struct ipt_connmark_target_info *markinfo = targinfo; + unsigned long diff; + unsigned long nfmark; + unsigned long newmark; + + enum ip_conntrack_info ctinfo; + struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo); + if (ct) { + switch(markinfo->mode) { + case IPT_CONNMARK_SET: + newmark = (ct->mark & ~markinfo->mask) | markinfo->mark; + if (newmark != ct->mark) + ct->mark = newmark; + break; + case IPT_CONNMARK_SET_RETURN: + // Set connmark and nfmark, apply mask to nfmark, do IPT_RETURN - zzz + newmark = ct->mark = markinfo->mark; + newmark &= markinfo->mask; + nfmark = (*pskb)->nfmark; + if (newmark != nfmark) { + (*pskb)->nfmark = newmark; + (*pskb)->nfcache |= NFC_ALTERED; + } + return IPT_RETURN; + case IPT_CONNMARK_SAVE: + newmark = (ct->mark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask); + if (ct->mark != newmark) + ct->mark = newmark; + break; + case IPT_CONNMARK_RESTORE: + nfmark = (*pskb)->nfmark; + diff = (ct->mark ^ nfmark) & markinfo->mask; // zzz + if (diff != 0) { + (*pskb)->nfmark = nfmark ^ diff; + (*pskb)->nfcache |= NFC_ALTERED; + } + break; + } + } + + return IPT_CONTINUE; +} + +static int +checkentry(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + struct ipt_connmark_target_info *matchinfo = targinfo; + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_connmark_target_info))) { + printk(KERN_WARNING "CONNMARK: targinfosize %u != %Zu\n", + targinfosize, + IPT_ALIGN(sizeof(struct ipt_connmark_target_info))); + return 0; + } + + if (matchinfo->mode == IPT_CONNMARK_RESTORE) { + if (strcmp(tablename, "mangle") != 0) { + printk(KERN_WARNING "CONNMARK: restore can only be called from \"mangle\" table, not \"%s\"\n", tablename); + return 0; + } + } + + return 1; +} + +static struct ipt_target ipt_connmark_reg = { + .name = "CONNMARK", + .target = &target, + .checkentry = &checkentry, + .me = THIS_MODULE +}; + +static int __init init(void) +{ + return ipt_register_target(&ipt_connmark_reg); +} + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_connmark_reg); +} + +module_init(init); +module_exit(fini); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_IMQ.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_IMQ.c new file mode 100644 index 00000000..2ba068b3 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_IMQ.c @@ -0,0 +1,78 @@ +/* This target marks packets to be enqueued to an imq device */ +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ipt_IMQ.h> +#include <linux/imq.h> + +static unsigned int imq_target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + struct ipt_imq_info *mr = (struct ipt_imq_info*)targinfo; + + (*pskb)->imq_flags = mr->todev | IMQ_F_ENQUEUE; + (*pskb)->nfcache |= NFC_ALTERED; + + return IPT_CONTINUE; +} + +static int imq_checkentry(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + struct ipt_imq_info *mr; + + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_imq_info))) { + printk(KERN_WARNING "IMQ: invalid targinfosize\n"); + return 0; + } + mr = (struct ipt_imq_info*)targinfo; + + if (strcmp(tablename, "mangle") != 0) { + printk(KERN_WARNING + "IMQ: IMQ can only be called from \"mangle\" table, not \"%s\"\n", + tablename); + return 0; + } + + if (mr->todev > IMQ_MAX_DEVS) { + printk(KERN_WARNING + "IMQ: invalid device specified, highest is %u\n", + IMQ_MAX_DEVS); + return 0; + } + + return 1; +} + +static struct ipt_target ipt_imq_reg = { + { NULL, NULL}, + "IMQ", + imq_target, + imq_checkentry, + NULL, + THIS_MODULE +}; + +static int __init init(void) +{ + if (ipt_register_target(&ipt_imq_reg)) + return -EINVAL; + + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_imq_reg); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_MACSAVE.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_MACSAVE.c new file mode 100644 index 00000000..62677279 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_MACSAVE.c @@ -0,0 +1,65 @@ +/* + + MACSAVE target + Copyright (C) 2006 Jonathan Zarate + + Licensed under GNU GPL v2 or later. + +*/ +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/if_ether.h> + +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ip_conntrack.h> +#include <linux/netfilter_ipv4/ipt_MACSAVE.h> + +static unsigned int target(struct sk_buff **pskb, unsigned int hooknum, + const struct net_device *in, const struct net_device *out, + const void *targinfo, void *userinfo) +{ +// const struct ipt_MACSAVE_target_info *info = targinfo; + struct sk_buff *skb = *pskb; + struct ip_conntrack *ct; + enum ip_conntrack_info ctinfo; + + if ((skb->mac.raw >= skb->head) && ((skb->mac.raw + ETH_HLEN) <= skb->data)) { + ct = ip_conntrack_get(skb, &ctinfo); + if (ct) { + memcpy(ct->macsave, skb->mac.ethernet->h_source, sizeof(ct->macsave)); + } + } + return IPT_CONTINUE; +} + +static int checkentry(const char *tablename, const struct ipt_entry *e, void *targinfo, + unsigned int targinfosize, unsigned int hook_mask) +{ + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_MACSAVE_target_info))) { + printk(KERN_ERR "MACSAVE: Invalid data size\n"); + return 0; + } + + if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_IN))) { + printk(KERN_ERR "MACSAVE: Valid only in PREROUTING, FORWARD and INPUT\n"); + return 0; + } + return 1; +} + +static struct ipt_target macsave_target += { { NULL, NULL }, "MACSAVE", target, checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_target(&macsave_target); +} + +static void __exit fini(void) +{ + ipt_unregister_target(&macsave_target); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_ROUTE.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_ROUTE.c new file mode 100644 index 00000000..b97d7792 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_ROUTE.c @@ -0,0 +1,422 @@ +/* + * This implements the ROUTE target, which enables you to setup unusual + * routes not supported by the standard kernel routing table. + * + * Copyright (C) 2002 Cedric de Launois <delaunois@info.ucl.ac.be> + * + * v 1.11 2004/11/23 + * + * This software is distributed under GNU GPL v2, 1991 + */ + +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/ip.h> +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ip_conntrack.h> +#include <linux/netfilter_ipv4/ipt_ROUTE.h> +#include <linux/netdevice.h> +#include <linux/route.h> +#include <net/ip.h> +#include <net/route.h> +#include <net/icmp.h> +#include <net/checksum.h> + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + + +/* Try to route the packet according to the routing keys specified in + * route_info. Keys are : + * - ifindex : + * 0 if no oif preferred, + * otherwise set to the index of the desired oif + * - route_info->gw : + * 0 if no gateway specified, + * otherwise set to the next host to which the pkt must be routed + * If success, skb->dev is the output device to which the packet must + * be sent and skb->dst is not NULL + * + * RETURN: -1 if an error occured + * 1 if the packet was succesfully routed to the + * destination desired + * 0 if the kernel routing table could not route the packet + * according to the keys specified + */ +static int route(struct sk_buff *skb, + unsigned int ifindex, + const struct ipt_route_target_info *route_info) +{ + int err; + struct rtable *rt; + struct iphdr *iph = skb->nh.iph; + struct rt_key key = { + dst:iph->daddr, + src:0, + oif:ifindex, + tos:RT_TOS(iph->tos) + }; + + /* The destination address may be overloaded by the target */ + if (route_info->gw) + key.dst = route_info->gw; + + /* Trying to route the packet using the standard routing table. */ + if ((err = ip_route_output_key(&rt, &key))) { + if (net_ratelimit()) + DEBUGP("ipt_ROUTE: couldn't route pkt (err: %i)",err); + return -1; + } + + /* Drop old route. */ + dst_release(skb->dst); + skb->dst = NULL; + + /* Success if no oif specified or if the oif correspond to the + * one desired */ + if (!ifindex || rt->u.dst.dev->ifindex == ifindex) { + skb->dst = &rt->u.dst; + skb->dev = skb->dst->dev; + return 1; + } + + /* The interface selected by the routing table is not the one + * specified by the user. This may happen because the dst address + * is one of our own addresses. + */ + if (net_ratelimit()) + DEBUGP("ipt_ROUTE: failed to route as desired gw=%u.%u.%u.%u oif=%i (got oif=%i)\n", + NIPQUAD(route_info->gw), ifindex, rt->u.dst.dev->ifindex); + + return 0; +} + + +/* Stolen from ip_finish_output2 + * PRE : skb->dev is set to the device we are leaving by + * skb->dst is not NULL + * POST: the packet is sent with the link layer header pushed + * the packet is destroyed + */ +static void ip_direct_send(struct sk_buff *skb) +{ + struct dst_entry *dst = skb->dst; + struct hh_cache *hh = dst->hh; + + if (hh) { + read_lock_bh(&hh->hh_lock); + memcpy(skb->data - 16, hh->hh_data, 16); + read_unlock_bh(&hh->hh_lock); + skb_push(skb, hh->hh_len); + hh->hh_output(skb); + } else if (dst->neighbour) + dst->neighbour->output(skb); + else { + if (net_ratelimit()) + DEBUGP(KERN_DEBUG "ipt_ROUTE: no hdr & no neighbour cache!\n"); + kfree_skb(skb); + } +} + + +/* PRE : skb->dev is set to the device we are leaving by + * POST: - the packet is directly sent to the skb->dev device, without + * pushing the link layer header. + * - the packet is destroyed + */ +static inline int dev_direct_send(struct sk_buff *skb) +{ + return dev_queue_xmit(skb); +} + + +static unsigned int route_oif(const struct ipt_route_target_info *route_info, + struct sk_buff *skb) +{ + unsigned int ifindex = 0; + struct net_device *dev_out = NULL; + + /* The user set the interface name to use. + * Getting the current interface index. + */ + if ((dev_out = dev_get_by_name(route_info->oif))) { + ifindex = dev_out->ifindex; + } else { + /* Unknown interface name : packet dropped */ + if (net_ratelimit()) + DEBUGP("ipt_ROUTE: oif interface %s not found\n", route_info->oif); + return NF_DROP; + } + + /* Trying the standard way of routing packets */ + switch (route(skb, ifindex, route_info)) { + case 1: + dev_put(dev_out); + if (route_info->flags & IPT_ROUTE_CONTINUE) + return IPT_CONTINUE; + + ip_direct_send(skb); + return NF_STOLEN; + + case 0: + /* Failed to send to oif. Trying the hard way */ + if (route_info->flags & IPT_ROUTE_CONTINUE) + return NF_DROP; + + if (net_ratelimit()) + DEBUGP("ipt_ROUTE: forcing the use of %i\n", + ifindex); + + /* We have to force the use of an interface. + * This interface must be a tunnel interface since + * otherwise we can't guess the hw address for + * the packet. For a tunnel interface, no hw address + * is needed. + */ + if ((dev_out->type != ARPHRD_TUNNEL) + && (dev_out->type != ARPHRD_IPGRE)) { + if (net_ratelimit()) + DEBUGP("ipt_ROUTE: can't guess the hw addr !\n"); + dev_put(dev_out); + return NF_DROP; + } + + /* Send the packet. This will also free skb + * Do not go through the POST_ROUTING hook because + * skb->dst is not set and because it will probably + * get confused by the destination IP address. + */ + skb->dev = dev_out; + dev_direct_send(skb); + dev_put(dev_out); + return NF_STOLEN; + + default: + /* Unexpected error */ + dev_put(dev_out); + return NF_DROP; + } +} + + +static unsigned int route_iif(const struct ipt_route_target_info *route_info, + struct sk_buff *skb) +{ + struct net_device *dev_in = NULL; + + /* Getting the current interface index. */ + if (!(dev_in = dev_get_by_name(route_info->iif))) { + if (net_ratelimit()) + DEBUGP("ipt_ROUTE: iif interface %s not found\n", route_info->iif); + return NF_DROP; + } + + skb->dev = dev_in; + dst_release(skb->dst); + skb->dst = NULL; + + netif_rx(skb); + dev_put(dev_in); + return NF_STOLEN; +} + + +static unsigned int route_gw(const struct ipt_route_target_info *route_info, + struct sk_buff *skb) +{ + if (route(skb, 0, route_info)!=1) + return NF_DROP; + + if (route_info->flags & IPT_ROUTE_CONTINUE) + return IPT_CONTINUE; + + ip_direct_send(skb); + return NF_STOLEN; +} + +/* To detect and deter routed packet loopback when using the --tee option, + * we take a page out of the raw.patch book: on the copied skb, we set up + * a fake ->nfct entry, pointing to the local &route_tee_track. We skip + * routing packets when we see they already have that ->nfct. + */ + +static struct ip_conntrack route_tee_track; + +static unsigned int ipt_route_target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + const struct ipt_route_target_info *route_info = targinfo; + struct sk_buff *skb = *pskb; + unsigned int res; + + /* If we are at PREROUTING or INPUT hook + * the TTL isn't decreased by the IP stack + */ + if (hooknum == NF_IP_PRE_ROUTING || + hooknum == NF_IP_LOCAL_IN) { + + struct iphdr *iph = skb->nh.iph; + + if (iph->ttl <= 1) { + struct rtable *rt; + + if (ip_route_output(&rt, iph->saddr, iph->daddr, + RT_TOS(iph->tos) | RTO_CONN, + 0)) { + return NF_DROP; + } + + if (skb->dev == rt->u.dst.dev) { + /* Drop old route. */ + dst_release(skb->dst); + skb->dst = &rt->u.dst; + + /* this will traverse normal stack, and + * thus call conntrack on the icmp packet */ + icmp_send(skb, ICMP_TIME_EXCEEDED, + ICMP_EXC_TTL, 0); + } + + return NF_DROP; + } + + /* + * If we are at INPUT the checksum must be recalculated since + * the length could change as the result of a defragmentation. + * -- Rickard Molin + */ + if(hooknum == NF_IP_LOCAL_IN) { + iph->ttl = iph->ttl - 1; + iph->check = 0; + iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); + } else { + ip_decrease_ttl(iph); + } + } + + if ((route_info->flags & IPT_ROUTE_TEE)) { + /* + * Copy the *pskb, and route the copy. Will later return + * IPT_CONTINUE for the original skb, which should continue + * on its way as if nothing happened. The copy should be + * independantly delivered to the ROUTE --gw. + */ + skb = skb_copy(*pskb, GFP_ATOMIC); + if (!skb) { + if (net_ratelimit()) + DEBUGP(KERN_DEBUG "ipt_ROUTE: copy failed!\n"); + return IPT_CONTINUE; + } + } + + /* Tell conntrack to forget this packet since it may get confused + * when a packet is leaving with dst address == our address. + * Good idea ? Dunno. Need advice. + * + * NEW: mark the skb with our &route_tee_track, so we avoid looping + * on any already routed packet. + */ + if (!(route_info->flags & IPT_ROUTE_CONTINUE)) { + nf_conntrack_put(skb->nfct); + skb->nfct = &route_tee_track.infos[IP_CT_NEW]; + nf_conntrack_get(skb->nfct); + skb->nfcache = 0; +#ifdef CONFIG_NETFILTER_DEBUG + skb->nf_debug = 0; +#endif + } + + if (route_info->oif[0]) { + res = route_oif(route_info, skb); + } else if (route_info->iif[0]) { + res = route_iif(route_info, skb); + } else if (route_info->gw) { + res = route_gw(route_info, skb); + } else { + if (net_ratelimit()) + DEBUGP(KERN_DEBUG "ipt_ROUTE: no parameter !\n"); + res = IPT_CONTINUE; + } + + if ((route_info->flags & IPT_ROUTE_TEE)) + res = IPT_CONTINUE; + + return res; +} + + +static int ipt_route_checkentry(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + if (strcmp(tablename, "mangle") != 0) { + printk("ipt_ROUTE: bad table `%s', use the `mangle' table.\n", + tablename); + return 0; + } + + if (hook_mask & ~( (1 << NF_IP_PRE_ROUTING) + | (1 << NF_IP_LOCAL_IN) + | (1 << NF_IP_FORWARD) + | (1 << NF_IP_LOCAL_OUT) + | (1 << NF_IP_POST_ROUTING))) { + printk("ipt_ROUTE: bad hook\n"); + return 0; + } + + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_route_target_info))) { + printk(KERN_WARNING "ipt_ROUTE: targinfosize %u != %Zu\n", + targinfosize, + IPT_ALIGN(sizeof(struct ipt_route_target_info))); + return 0; + } + + return 1; +} + + +static struct ipt_target ipt_route_reg += { { NULL, NULL }, "ROUTE", ipt_route_target, ipt_route_checkentry, NULL, + THIS_MODULE }; + + +static int __init init(void) +{ + /* Set up fake conntrack (stolen from raw.patch): + - to never be deleted, not in any hashes */ + atomic_set(&route_tee_track.ct_general.use, 1); + /* - and look it like as a confirmed connection */ + set_bit(IPS_CONFIRMED_BIT, &route_tee_track.status); + /* - and prepare the ctinfo field for REJECT/NAT. */ + route_tee_track.infos[IP_CT_NEW].master = + route_tee_track.infos[IP_CT_RELATED].master = + route_tee_track.infos[IP_CT_RELATED + IP_CT_IS_REPLY].master = + &route_tee_track.ct_general; + /* Initialize fake conntrack so that NAT will skip it */ + route_tee_track.nat.info.initialized |= + (1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST); + + if (ipt_register_target(&ipt_route_reg)) + return -EINVAL; + + return 0; +} + + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_route_reg); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_TRIGGER.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_TRIGGER.c index 99e7dfe7..07103fa5 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ipt_TRIGGER.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_TRIGGER.c @@ -62,7 +62,8 @@ LIST_HEAD(trigger_list); static void trigger_refresh(struct ipt_trigger *trig, unsigned long extra_jiffies) { - DEBUGP("%s: \n", __FUNCTION__); + DEBUGP("%s: mport=%u-%u\n", __FUNCTION__, trig->ports.mport[0], trig->ports.mport[1]); + IP_NF_ASSERT(trig); WRITE_LOCK(&ip_conntrack_lock); @@ -77,7 +78,8 @@ static void trigger_refresh(struct ipt_trigger *trig, unsigned long extra_jiffie static void __del_trigger(struct ipt_trigger *trig) { - DEBUGP("%s: \n", __FUNCTION__); + DEBUGP("%s: mport=%u-%u\n", __FUNCTION__, trig->ports.mport[0], trig->ports.mport[1]); + IP_NF_ASSERT(trig); MUST_BE_WRITE_LOCKED(&ip_conntrack_lock); @@ -90,7 +92,9 @@ static void trigger_timeout(unsigned long ul_trig) { struct ipt_trigger *trig= (void *) ul_trig; - DEBUGP("trigger list %p timed out\n", trig); +// DEBUGP("trigger list %p timed out\n", trig); + DEBUGP("%s: mport=%u-%u\n", __FUNCTION__, trig->ports.mport[0], trig->ports.mport[1]); + WRITE_LOCK(&ip_conntrack_lock); __del_trigger(trig); WRITE_UNLOCK(&ip_conntrack_lock); @@ -250,7 +254,7 @@ trigger_dnat(struct sk_buff **pskb, IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW)); DEBUGP("%s: got ", __FUNCTION__); - DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + DUMP_TUPLE_RAW(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); /* Alter the destination of imcoming packet. */ newrange = ((struct ip_nat_multi_range) @@ -310,7 +314,7 @@ trigger_check(const char *tablename, DEBUGP("trigger_check: size %u.\n", targinfosize); return 0; } - if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_FORWARD))) { + if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING))) { DEBUGP("trigger_check: bad hooks %x.\n", hook_mask); return 0; } diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_TTL.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_TTL.c new file mode 100644 index 00000000..2f0a4e7a --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_TTL.c @@ -0,0 +1,110 @@ +/* TTL modification target for IP tables + * (C) 2000 by Harald Welte <laforge@gnumonks.org> + * + * Version: 1.8 + * + * This software is distributed under the terms of GNU GPL + */ + +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/ip.h> +#include <net/checksum.h> + +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ipt_TTL.h> + +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); +MODULE_DESCRIPTION("IP tables TTL modification module"); +MODULE_LICENSE("GPL"); + +static unsigned int ipt_ttl_target(struct sk_buff **pskb, unsigned int hooknum, + const struct net_device *in, const struct net_device *out, + const void *targinfo, void *userinfo) +{ + struct iphdr *iph = (*pskb)->nh.iph; + const struct ipt_TTL_info *info = targinfo; + u_int16_t diffs[2]; + int new_ttl; + + switch (info->mode) { + case IPT_TTL_SET: + new_ttl = info->ttl; + break; + case IPT_TTL_INC: + new_ttl = iph->ttl + info->ttl; + if (new_ttl > 255) + new_ttl = 255; + break; + case IPT_TTL_DEC: + new_ttl = iph->ttl - info->ttl; + if (new_ttl < 0) + new_ttl = 0; + break; + default: + new_ttl = iph->ttl; + break; + } + + if (new_ttl != iph->ttl) { + diffs[0] = htons(((unsigned)iph->ttl) << 8) ^ 0xFFFF; + iph->ttl = new_ttl; + diffs[1] = htons(((unsigned)iph->ttl) << 8); + iph->check = csum_fold(csum_partial((char *)diffs, + sizeof(diffs), + iph->check^0xFFFF)); + (*pskb)->nfcache |= NFC_ALTERED; + } + + return IPT_CONTINUE; +} + +static int ipt_ttl_checkentry(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + struct ipt_TTL_info *info = targinfo; + + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_TTL_info))) { + printk(KERN_WARNING "TTL: targinfosize %u != %Zu\n", + targinfosize, + IPT_ALIGN(sizeof(struct ipt_TTL_info))); + return 0; + } + + if (strcmp(tablename, "mangle")) { + printk(KERN_WARNING "TTL: can only be called from \"mangle\" table, not \"%s\"\n", tablename); + return 0; + } + + if (info->mode > IPT_TTL_MAXMODE) { + printk(KERN_WARNING "TTL: invalid or unknown Mode %u\n", + info->mode); + return 0; + } + + if ((info->mode != IPT_TTL_SET) && (info->ttl == 0)) { + printk(KERN_WARNING "TTL: increment/decrement doesn't make sense with value 0\n"); + return 0; + } + + return 1; +} + +static struct ipt_target ipt_TTL = { { NULL, NULL }, "TTL", + ipt_ttl_target, ipt_ttl_checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_target(&ipt_TTL); +} + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_TTL); +} + +module_init(init); +module_exit(fini); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_account.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_account.c new file mode 100644 index 00000000..7fd34562 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_account.c @@ -0,0 +1,942 @@ +/* + * accounting match (ipt_account.c) + * (C) 2003,2004 by Piotr Gasidlo (quaker@barbara.eu.org) + * + * Version: 0.1.7 + * + * This software is distributed under the terms of GNU GPL + */ + +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/proc_fs.h> +#include <linux/spinlock.h> +#include <linux/vmalloc.h> +#include <linux/interrupt.h> +#include <linux/ctype.h> + +#include <linux/seq_file.h> + +#include <asm/uaccess.h> + +#include <linux/ip.h> +#include <linux/tcp.h> +#include <linux/udp.h> + +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ipt_account.h> + +#if defined(CONFIG_IP_NF_MATCH_ACCOUNT_DEBUG) + #define dprintk(format,args...) printk(format,##args) +#else + #define dprintk(format,args...) +#endif + +static char version[] = +KERN_INFO IPT_ACCOUNT_NAME " " IPT_ACCOUNT_VERSION " : Piotr Gasid³o <quaker@barbara.eu.org>, http://www.barbara.eu.org/~quaker/ipt_account/\n"; + +/* rights for files created in /proc/net/ipt_account/ */ +static int permissions = 0644; +/* maximal netmask for single table */ +static int netmask = 16; + +/* module information */ +MODULE_AUTHOR("Piotr Gasidlo <quaker@barbara.eu.org>"); +MODULE_DESCRIPTION("Traffic accounting modules"); +MODULE_LICENSE("GPL"); +MODULE_PARM(permissions,"i"); +MODULE_PARM_DESC(permissions,"permissions on /proc/net/ipt_account/* files"); +MODULE_PARM(netmask, "i"); +MODULE_PARM_DESC(netmask, "maximum *save* size of one list (netmask)"); + +/* structure with statistics counters */ +struct t_ipt_account_stat { + u_int64_t b_all, b_tcp, b_udp, b_icmp, b_other; /* byte counters for all/tcp/udp/icmp/other traffic */ + u_int64_t p_all, p_tcp, p_udp, p_icmp, p_other; /* packet counters for all/tcp/udp/icmp/other traffic */ +}; + +/* stucture with statistics counters, used when table is created with --ashort switch */ +struct t_ipt_account_stat_short { + u_int64_t b_all; /* byte counters for all traffic */ + u_int64_t p_all; /* packet counters for all traffic */ +}; + +/* structure holding to/from statistics for single ip */ +struct t_ipt_account_ip_list { + struct t_ipt_account_stat src; + struct t_ipt_account_stat dest; + unsigned long time; /* time when this record was last updated */ + +}; + +/* same as above, for tables with --ashort switch */ +struct t_ipt_account_ip_list_short { + struct t_ipt_account_stat_short src; + struct t_ipt_account_stat_short dest; + unsigned long time; +}; + +/* structure describing single table */ +struct t_ipt_account_table { + char name[IPT_ACCOUNT_NAME_LEN]; /* table name ( = filename in /proc/net/ipt_account/) */ + union { /* table with statistics for each ip in network/netmask */ + struct t_ipt_account_ip_list *l; + struct t_ipt_account_ip_list_short *s; + } ip_list; + u_int32_t network; /* network/netmask covered by table*/ + u_int32_t netmask; + u_int32_t count; + int shortlisting:1; /* show only total columns of counters */ + int use_count; /* rules counter - counting number of rules using this table */ + struct t_ipt_account_table *next; + spinlock_t ip_list_lock; + struct proc_dir_entry *status_file; +}; + +/* we must use spinlocks to avoid parallel modifications of table list */ +static spinlock_t account_lock = SPIN_LOCK_UNLOCKED; + +static struct proc_dir_entry *proc_net_ipt_account = NULL; + +/* root pointer holding list of the tables */ +static struct t_ipt_account_table *account_tables = NULL; + +/* convert ascii to ip */ +int atoip(char *buffer, u_int32_t *ip) { + + char *bufferptr = buffer; + int part, shift; + + /* zero ip */ + *ip = 0; + + /* first must be a digit */ + if (!isdigit(*bufferptr)) + return 0; + + /* parse first 3 octets (III.III.III.iii) */ + for (part = 0, shift = 24; *bufferptr && shift; bufferptr++) { + if (isdigit(*bufferptr)) { + part = part * 10 + (*bufferptr - '0'); + continue; + } + if (*bufferptr == '.') { + if (part > 255) + return 0; + *ip |= part << shift; + shift -= 8; + part = 0; + continue; + } + return 0; + } + + /* we expect more digts */ + if (!*bufferptr) + return 0; + /* parse last octet (iii.iii.iii.III) */ + for (; *bufferptr; bufferptr++) { + if (isdigit(*bufferptr)) { + part = part * 10 + (*bufferptr - '0'); + continue; + } else { + if (part > 255) + return 0; + *ip |= part; + break; + } + } + return (bufferptr - buffer); +} + +/* convert ascii to 64bit integer */ +int atoi64(char *buffer, u_int64_t *i) { + char *bufferptr = buffer; + + /* zero integer */ + *i = 0; + + while (isdigit(*bufferptr)) { + *i = *i * 10 + (*bufferptr - '0'); + bufferptr++; + } + return (bufferptr - buffer); +} + +static void *account_seq_start(struct seq_file *s, loff_t *pos) +{ + struct proc_dir_entry *pde = s->private; + struct t_ipt_account_table *table = pde->data; + + unsigned int *bucket; + + spin_lock_bh(&table->ip_list_lock); + if (*pos >= table->count) + return NULL; + + bucket = kmalloc(sizeof(unsigned int), GFP_KERNEL); + if (!bucket) + return ERR_PTR(-ENOMEM); + *bucket = *pos; + return bucket; +} + +static void *account_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + struct proc_dir_entry *pde = s->private; + struct t_ipt_account_table *table = pde->data; + + unsigned int *bucket = (unsigned int *)v; + + *pos = ++(*bucket); + if (*pos >= table->count) { + kfree(v); + return NULL; + } + return bucket; +} + +static void account_seq_stop(struct seq_file *s, void *v) +{ + struct proc_dir_entry *pde = s->private; + struct t_ipt_account_table *table = pde->data; + unsigned int *bucket = (unsigned int *)v; + kfree(bucket); + spin_unlock_bh(&table->ip_list_lock); +} + +static int account_seq_write(struct file *file, const char *ubuffer, + size_t ulength, loff_t *pos) +{ + struct proc_dir_entry *pde = ((struct seq_file *)file->private_data)->private; + struct t_ipt_account_table *table = pde->data; + char buffer[1024], *bufferptr; + int length; + + u_int32_t ip; + int len, i; + struct t_ipt_account_ip_list l; + struct t_ipt_account_ip_list_short s; + u_int64_t *p, dummy; + + + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() entered.\n"); + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() ulength = %zi.\n", ulength); + + length = ulength; + if (ulength > 1024) + length = 1024; + if (copy_from_user(buffer, ubuffer, length)) + return -EFAULT; + buffer[length - 1] = 0; + bufferptr = buffer; + + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() buffer = \'%s\' length = %i.\n", buffer, length); + + /* reset table counters */ + if (!memcmp(buffer, "reset", 5)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got \"reset\".\n"); + if (!table->shortlisting) { + spin_lock_bh(&table->ip_list_lock); + memset(table->ip_list.l, 0, sizeof(struct t_ipt_account_ip_list) * table->count); + spin_unlock_bh(&table->ip_list_lock); + } else { + spin_lock_bh(&table->ip_list_lock); + memset(table->ip_list.s, 0, sizeof(struct t_ipt_account_ip_list_short) * table->count); + spin_unlock_bh(&table->ip_list_lock); + } + return length; + } + + if (!memcmp(buffer, "ip", 2)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got \"ip\".\n"); + bufferptr += 2; + if (!isspace(*bufferptr)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); + return length; /* expected space */ + } + bufferptr += 1; + if (*bufferptr != '=') { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%ti).\n", bufferptr - buffer); + return length; /* expected equal */ + } + bufferptr += 1; + if (!isspace(*bufferptr)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); + return length; /* expected space */ + } + bufferptr += 1; + if (!(len = atoip(bufferptr, &ip))) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected ip (%ti).\n", bufferptr - buffer); + return length; /* expected ip */ + } + bufferptr += len; + if ((ip & table->netmask) != table->network) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected ip [%u.%u.%u.%u] from table's network/netmask [%u.%u.%u.%u/%u.%u.%u.%u].\n", HIPQUAD(ip), HIPQUAD(table->network), HIPQUAD(table->netmask)); + return length; /* expected ip from table's network/netmask */ + } + if (!table->shortlisting) { + memset(&l, 0, sizeof(struct t_ipt_account_ip_list)); + while(*bufferptr) { + if (!isspace(*bufferptr)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); + return length; /* expected space */ + } + bufferptr += 1; + if (!memcmp(bufferptr, "bytes_src", 9)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got bytes_src (%ti).\n", bufferptr - buffer); + p = &l.src.b_all; + bufferptr += 9; + } else if (!memcmp(bufferptr, "bytes_dest", 10)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got bytes_dest (%ti).\n", bufferptr - buffer); + p = &l.dest.b_all; + bufferptr += 10; + } else if (!memcmp(bufferptr, "packets_src", 11)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got packets_src (%ti).\n", bufferptr - buffer); + p = &l.src.p_all; + bufferptr += 11; + } else if (!memcmp(bufferptr, "packets_dest", 12)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got packets_dest (%ti).\n", bufferptr - buffer); + p = &l.dest.p_all; + bufferptr += 12; + } else if (!memcmp(bufferptr, "time", 4)) { + /* time hack, ignore time tokens */ + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got time (%ti).\n", bufferptr - buffer); + bufferptr += 4; + if (!isspace(*bufferptr)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); + return length; /* expected space */ + } + bufferptr += 1; + if (*bufferptr != '=') { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%ti).\n", bufferptr - buffer); + return length; /* expected equal */ + } + bufferptr += 1; + if (!isspace(*bufferptr)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); + return length; /* expected space */ + } + bufferptr += 1; + if (!(len = atoi64(bufferptr, &dummy))) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected int64 (%ti).\n", bufferptr - buffer); + return length; /* expected int64 */ + } + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got %llu (%ti).\n", dummy, bufferptr - buffer); + bufferptr += len; + continue; /* skip time token */ + } else + return length; /* expected token */ + if (!isspace(*bufferptr)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); + return length; /* expected space */ + } + bufferptr += 1; + if (*bufferptr != '=') { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%ti).\n", bufferptr - buffer); + return length; /* expected equal */ + } + bufferptr += 1; + for (i = 0; i < 5; i++) { + if (!isspace(*bufferptr)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); + return length; /* expected space */ + } + bufferptr += 1; + if (!(len = atoi64(bufferptr, p))) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected int64 (%ti).\n", bufferptr - buffer); + return length; /* expected int64 */ + } + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got %llu (%ti).\n", *p, bufferptr - buffer); + bufferptr += len; + p++; + } + } + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() updating row.\n"); + spin_lock_bh(&table->ip_list_lock); + /* update counters, do not overwrite time field */ + memcpy(&table->ip_list.l[ip - table->network], &l, sizeof(struct t_ipt_account_ip_list) - sizeof(unsigned long)); + spin_unlock_bh(&table->ip_list_lock); + } else { + memset(&s, 0, sizeof(struct t_ipt_account_ip_list_short)); + while(*bufferptr) { + if (!isspace(*bufferptr)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); + return length; /* expected space */ + } + bufferptr += 1; + if (!memcmp(bufferptr, "bytes_src", 9)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got bytes_src (%ti).\n", bufferptr - buffer); + p = &s.src.b_all; + bufferptr += 9; + } else if (!memcmp(bufferptr, "bytes_dest", 10)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got bytes_dest (%ti).\n", bufferptr - buffer); + p = &s.dest.b_all; + bufferptr += 10; + } else if (!memcmp(bufferptr, "packets_src", 11)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got packets_src (%ti).\n", bufferptr - buffer); + p = &s.src.p_all; + bufferptr += 11; + } else if (!memcmp(bufferptr, "packets_dest", 12)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got packets_dest (%ti).\n", bufferptr - buffer); + p = &s.dest.p_all; + bufferptr += 12; + } else if (!memcmp(bufferptr, "time", 4)) { + /* time hack, ignore time tokens */ + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got time (%ti).\n", bufferptr - buffer); + bufferptr += 4; + if (!isspace(*bufferptr)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); + return length; /* expected space */ + } + bufferptr += 1; + if (*bufferptr != '=') { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%ti).\n", bufferptr - buffer); + return length; /* expected equal */ + } + bufferptr += 1; + if (!isspace(*bufferptr)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); + return length; /* expected space */ + } + bufferptr += 1; + if (!(len = atoi64(bufferptr, &dummy))) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected int64 (%ti).\n", bufferptr - buffer); + return length; /* expected int64 */ + } + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got %llu (%ti).\n", dummy, bufferptr - buffer); + bufferptr += len; + continue; /* skip time token */ + } else { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected token (%ti).\n", bufferptr - buffer); + return length; /* expected token */ + } + if (!isspace(*bufferptr)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); + return length; /* expected space */ + } + bufferptr += 1; + if (*bufferptr != '=') { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%ti).\n", bufferptr - buffer); + return length; /* expected equal */ + } + bufferptr += 1; + if (!isspace(*bufferptr)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%ti).\n", bufferptr - buffer); + return length; /* expected space */ + } + bufferptr += 1; + if (!(len = atoi64(bufferptr, p))) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected int64 (%ti).\n", bufferptr - buffer); + return length; /* expected int64 */ + } + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got %llu (%ti).\n", *p, bufferptr - buffer); + bufferptr += len; + } + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() updating row.\n"); + spin_lock_bh(&table->ip_list_lock); + /* update counters, do not overwrite time field */ + memcpy(&table->ip_list.s[ip - table->network], &s, sizeof(struct t_ipt_account_ip_list_short) - sizeof(unsigned long)); + spin_unlock_bh(&table->ip_list_lock); + } + } + + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() left.\n"); + return length; +} + + +static int account_seq_show(struct seq_file *s, void *v) +{ + struct proc_dir_entry *pde = s->private; + struct t_ipt_account_table *table = pde->data; + unsigned int *bucket = (unsigned int *)v; + + u_int32_t address = table->network + *bucket; + struct timespec last; + + if (!table->shortlisting) { + jiffies_to_timespec(jiffies - table->ip_list.l[*bucket].time, &last); + seq_printf(s, + "ip = %u.%u.%u.%u bytes_src = %llu %llu %llu %llu %llu packets_src = %llu %llu %llu %llu %llu bytes_dest = %llu %llu %llu %llu %llu packets_dest = %llu %llu %llu %llu %llu time = %lu\n", + HIPQUAD(address), + table->ip_list.l[*bucket].src.b_all, + table->ip_list.l[*bucket].src.b_tcp, + table->ip_list.l[*bucket].src.b_udp, + table->ip_list.l[*bucket].src.b_icmp, + table->ip_list.l[*bucket].src.b_other, + table->ip_list.l[*bucket].src.p_all, + table->ip_list.l[*bucket].src.p_tcp, + table->ip_list.l[*bucket].src.p_udp, + table->ip_list.l[*bucket].src.p_icmp, + table->ip_list.l[*bucket].src.p_other, + table->ip_list.l[*bucket].dest.b_all, + table->ip_list.l[*bucket].dest.b_tcp, + table->ip_list.l[*bucket].dest.b_udp, + table->ip_list.l[*bucket].dest.b_icmp, + table->ip_list.l[*bucket].dest.b_other, + table->ip_list.l[*bucket].dest.p_all, + table->ip_list.l[*bucket].dest.p_tcp, + table->ip_list.l[*bucket].dest.p_udp, + table->ip_list.l[*bucket].dest.p_icmp, + table->ip_list.l[*bucket].dest.p_other, + last.tv_sec + ); + } else { + jiffies_to_timespec(jiffies - table->ip_list.s[*bucket].time, &last); + seq_printf(s, + "ip = %u.%u.%u.%u bytes_src = %llu packets_src = %llu bytes_dest = %llu packets_dest = %llu time = %lu\n", + HIPQUAD(address), + table->ip_list.s[*bucket].src.b_all, + table->ip_list.s[*bucket].src.p_all, + table->ip_list.s[*bucket].dest.b_all, + table->ip_list.s[*bucket].dest.p_all, + last.tv_sec + ); + } + return 0; +} + +static struct seq_operations account_seq_ops = { + .start = account_seq_start, + .next = account_seq_next, + .stop = account_seq_stop, + .show = account_seq_show +}; + +static int account_seq_open(struct inode *inode, struct file *file) +{ + int ret = seq_open(file, &account_seq_ops); + + if (!ret) { + struct seq_file *sf = file->private_data; + sf->private = PDE(inode); + } + return ret; +} + +static struct file_operations account_file_ops = { + .owner = THIS_MODULE, + .open = account_seq_open, + .read = seq_read, + .write = account_seq_write, + .llseek = seq_lseek, + .release = seq_release +}; + +/* do raw accounting */ +static inline void do_account(struct t_ipt_account_stat *stat, const struct sk_buff *skb) { + + /* update packet & bytes counters in *stat structure */ + stat->b_all += skb->len; + stat->p_all++; + + switch (skb->nh.iph->protocol) { + case IPPROTO_TCP: + stat->b_tcp += skb->len; + stat->p_tcp++; + break; + case IPPROTO_UDP: + stat->b_udp += skb->len; + stat->p_udp++; + break; + case IPPROTO_ICMP: + stat->b_icmp += skb->len; + stat->p_icmp++; + break; + default: + stat->b_other += skb->len; + stat->p_other++; + } +} + +static inline void do_account_short(struct t_ipt_account_stat_short *stat, const struct sk_buff *skb) { + + /* update packet & bytes counters in *stat structure */ + stat->b_all += skb->len; + stat->p_all++; +} + +static int match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + + const struct t_ipt_account_info *info = (struct t_ipt_account_info*)matchinfo; + struct t_ipt_account_table *table; + int ret; + unsigned long now; + + u_int32_t address; + + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() entered.\n"); + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() match name = %s.\n", info->name); + + spin_lock_bh(&account_lock); + /* find the right table */ + table = account_tables; + while (table && strncmp(table->name, info->name, IPT_ACCOUNT_NAME_LEN) && (table = table->next)); + spin_unlock_bh(&account_lock); + + if (table == NULL) { + /* ups, no table with that name */ + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() table %s not found. Leaving.\n", info->name); + return 0; + } + + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() table found %s\n", table->name); + + /* lock table while updating statistics */ + spin_lock_bh(&table->ip_list_lock); + + /* default: no match */ + ret = 0; + + /* get current time */ + now = jiffies; + + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() got packet src = %u.%u.%u.%u, dst = %u.%u.%u.%u, proto = %u.\n", NIPQUAD(skb->nh.iph->saddr), NIPQUAD(skb->nh.iph->daddr), skb->nh.iph->protocol); + + /* check whether traffic from source ip address ... */ + address = ntohl(skb->nh.iph->saddr); + /* ... is being accounted by this table */ + if (address && ((u_int32_t)(address & table->netmask) == (u_int32_t)table->network)) { + /* yes, account this packet */ + dprintk(KERN_INFO "ipt_account: match() accounting packet src = %u.%u.%u.%u, proto = %u.\n", HIPQUAD(address), skb->nh.iph->protocol); + /* update counters this host */ + if (!table->shortlisting) { + do_account(&table->ip_list.l[address - table->network].src, skb); + table->ip_list.l[address - table->network].time = now; + /* update also counters for all hosts in this table (network address) */ + if (table->netmask != INADDR_BROADCAST) { + do_account(&table->ip_list.l[0].src, skb); + table->ip_list.l[0].time = now; + } + } else { + do_account_short(&table->ip_list.s[address - table->network].src, skb); + table->ip_list.s[address - table->network].time = now; + /* update also counters for all hosts in this table (network address) */ + if (table->netmask != INADDR_BROADCAST) { + do_account_short(&table->ip_list.s[0].src, skb); + table->ip_list.s[0].time = now; + } + } + /* yes, it's a match */ + ret = 1; + } + + /* do the same thing with destination ip address */ + address = ntohl(skb->nh.iph->daddr); + if (address && ((u_int32_t)(address & table->netmask) == (u_int32_t)table->network)) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() accounting packet dst = %u.%u.%u.%u, proto = %u.\n", HIPQUAD(address), skb->nh.iph->protocol); + if (!table->shortlisting) { + do_account(&table->ip_list.l[address - table->network].dest, skb); + table->ip_list.l[address - table->network].time = now; + if (table->netmask != INADDR_BROADCAST) { + do_account(&table->ip_list.l[0].dest, skb); + table->ip_list.s[0].time = now; + } + } else { + do_account_short(&table->ip_list.s[address - table->network].dest, skb); + table->ip_list.s[address - table->network].time = now; + if (table->netmask != INADDR_BROADCAST) { + do_account_short(&table->ip_list.s[0].dest, skb); + table->ip_list.s[0].time = now; + } + } + ret = 1; + } + spin_unlock_bh(&table->ip_list_lock); + + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() left.\n"); + + return ret; +} + +static int checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchinfosize, + unsigned int hook_mask) +{ + const struct t_ipt_account_info *info = matchinfo; + struct t_ipt_account_table *table, *find_table, *last_table; + int ret = 0; + + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() entered.\n"); + + if (matchinfosize != IPT_ALIGN(sizeof(struct t_ipt_account_info))) return 0; + if (!info->name || !info->name[0]) return 0; + + /* find whether table with this name already exists */ + spin_lock_bh(&account_lock); + find_table = account_tables; + while( (last_table = find_table) && strncmp(info->name,find_table->name,IPT_ACCOUNT_NAME_LEN) && (find_table = find_table->next) ); + if (find_table != NULL) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() table %s found.\n", info->name); + /* if table exists, check whether table network/netmask equals rule network/netmask */ + if (find_table->network != info->network || find_table->netmask != info->netmask || find_table->shortlisting != info->shortlisting) { + spin_unlock_bh(&account_lock); + printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() wrong parameters (not equals existing table parameters).\n"); + ret = 0; + goto failure; + } + /* increment table use count */ + find_table->use_count++; + spin_unlock_bh(&account_lock); + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() incrementing use count.\n"); + ret = 1; + goto failure; + } + spin_unlock_bh(&account_lock); + + /* check netmask first, before allocating memory */ + if (info->netmask < ((1 << netmask) - 1)) { + printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() too big netmask.\n"); + ret = 0; + goto failure; + } + + /* table doesn't exist - create new */ + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() allocating %zu for new table %s.\n", sizeof(struct t_ipt_account_table), info->name); + table = vmalloc(sizeof(struct t_ipt_account_table)); + if (table == NULL) { + printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() failed to allocate %zu for new table %s.\n", sizeof(struct t_ipt_account_table), info->name); + ret = 0; /* was -ENOMEM */ + goto failure; + } + + /* setup table parameters */ + table->ip_list_lock = SPIN_LOCK_UNLOCKED; + table->next = NULL; + table->use_count = 1; + table->network = info->network; + table->netmask = info->netmask; + table->shortlisting = info->shortlisting; + table->count = (~table->netmask) + 1; + strncpy(table->name,info->name,IPT_ACCOUNT_NAME_LEN); + table->name[IPT_ACCOUNT_NAME_LEN - 1] = '\0'; + + /* allocate memory for table->ip_list */ + if (!table->shortlisting) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() allocating %zu for ip_list.\n", sizeof(struct t_ipt_account_ip_list) * table->count); + table->ip_list.l = vmalloc(sizeof(struct t_ipt_account_ip_list) * table->count); + if (table->ip_list.l == NULL) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() failed to allocate %zu for ip_list.\n", sizeof(struct t_ipt_account_ip_list) * table->count); + ret = 0; /* was -ENOMEM */ + goto failure_table; + } + memset(table->ip_list.l, 0, sizeof(struct t_ipt_account_ip_list) * table->count); + } else { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() allocating %zu for ip_list.\n", sizeof(struct t_ipt_account_ip_list_short) * table->count); + table->ip_list.s = vmalloc(sizeof(struct t_ipt_account_ip_list_short) * table->count); + if (table->ip_list.s == NULL) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() failed to allocate %zu for ip_list.\n", sizeof(struct t_ipt_account_ip_list_short) * table->count); + ret = 0; /* was -ENOMEM */ + goto failure_table; + } + memset(table->ip_list.s, 0, sizeof(struct t_ipt_account_ip_list_short) * table->count); + } + + /* put table into chain */ + spin_lock_bh(&account_lock); + find_table = account_tables; + while( (last_table = find_table) && strncmp(info->name, find_table->name, IPT_ACCOUNT_NAME_LEN) && (find_table = find_table->next) ); + if (find_table != NULL) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() table %s found.\n", info->name); + if (find_table->network != info->network || find_table->netmask != info->netmask) { + spin_unlock_bh(&account_lock); + printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() wrong network/netmask.\n"); + ret = 0; + goto failure_ip_list; + } + find_table->use_count++; + spin_unlock_bh(&account_lock); + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() incrementing use count.\n"); + ret = 1; + goto failure_ip_list; + } + if (!last_table) + account_tables = table; + else + last_table->next = table; + spin_unlock_bh(&account_lock); + + /* create procfs status file */ + table->status_file = create_proc_entry(table->name, permissions, proc_net_ipt_account); + if (table->status_file == NULL) { + ret = 0; /* was -ENOMEM */ + goto failure_unlink; + } + table->status_file->owner = THIS_MODULE; + table->status_file->data = table; + wmb(); +// if (!table->shortlisting) + table->status_file->proc_fops = &account_file_ops; +// else +// table->status_file->proc_fops = &account_file_ops_short; + + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() left.\n"); + /* everything went just okey */ + return 1; + + /* do cleanup in case of failure */ +failure_unlink: + /* remove table from list */ + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() removing table.\n"); + spin_lock_bh(&account_lock); + last_table = NULL; + table = account_tables; + if (table == NULL) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() no table found. Leaving.\n"); + spin_unlock_bh(&account_lock); + return 0; /* was -ENOMEM */ + } + while (strncmp(info->name, table->name, IPT_ACCOUNT_NAME_LEN) && (last_table = table) && (table = table->next)); + if (table == NULL) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() table already destroyed. Leaving.\n"); + spin_unlock_bh(&account_lock); + return 0; /* was -ENOMEM */ + } + if (last_table) + last_table->next = table->next; + else + account_tables = table->next; + spin_unlock_bh(&account_lock); +failure_ip_list: + /* free memory allocated for statistics table */ + if (!table->shortlisting) + vfree(table->ip_list.l); + else + vfree(table->ip_list.s); +failure_table: + /* free table */ + vfree(table); +failure: + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() left. Table not created.\n"); + /* failure return */ + return ret; +} + +static void destroy(void *matchinfo, + unsigned int matchinfosize) +{ + const struct t_ipt_account_info *info = matchinfo; + struct t_ipt_account_table *table, *last_table; + + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() entered.\n"); + + if (matchinfosize != IPT_ALIGN(sizeof(struct t_ipt_account_info))) return; + + /* search for table */ + spin_lock_bh(&account_lock); + last_table = NULL; + table = account_tables; + if(table == NULL) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() no tables found. Leaving.\n"); + spin_unlock_bh(&account_lock); + return; + } + while( strncmp(info->name,table->name,IPT_ACCOUNT_NAME_LEN) && (last_table = table) && (table = table->next) ); + if (table == NULL) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() no table %s not found. Leaving.\n", info->name); + spin_unlock_bh(&account_lock); + return; + } + + /* decrement table use-count */ + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() decrementing use count.\n"); + table->use_count--; + if (table->use_count) { + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() table still in use. Leaving.\n"); + spin_unlock_bh(&account_lock); + return; + } + + /* remove table if use-count is zero */ + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() table %s not used. Removing.\n", table->name); + + /* unlink table */ + if(last_table) + last_table->next = table->next; + else + account_tables = table->next; + spin_unlock_bh(&account_lock); + + /* wait while table is still in use */ + spin_lock_bh(&table->ip_list_lock); + spin_unlock_bh(&table->ip_list_lock); + + /* remove proc entries */ + remove_proc_entry(table->name, proc_net_ipt_account); + + /* remove table */ + if (!table->shortlisting) + vfree(table->ip_list.l); + else + vfree(table->ip_list.s); + vfree(table); + + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() left.\n"); + return; +} + +static struct ipt_match account_match = { + .name = "account", + .match = &match, + .checkentry = &checkentry, + .destroy = &destroy, + .me = THIS_MODULE +}; + +static int __init init(void) +{ + int err; + + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": __init() entered.\n"); + printk(version); + /* check params */ + if (netmask > 32 || netmask < 0) { + printk(KERN_INFO "account: Wrong netmask given by netmask parameter (%i). Valid is 32 to 0.\n", netmask); + err = -EINVAL; + goto doexit; + } + + /* create /proc/net/ipt_account directory */ + proc_net_ipt_account = proc_mkdir("ipt_account", proc_net); + if (!proc_net_ipt_account) { + printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() failed to create procfs entry.\n"); + err = -ENOMEM; + goto doexit; + } + proc_net_ipt_account->owner = THIS_MODULE; + + err = ipt_register_match(&account_match); + if (err) { + printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() failed to register match.\n"); + remove_proc_entry("ipt_account", proc_net); + } +doexit: + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": __init() left.\n"); + return err; +} + +static void __exit fini(void) +{ + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": __exit() entered.\n"); + + ipt_unregister_match(&account_match); + /* remove /proc/net/ipt_account/ directory */ + remove_proc_entry("ipt_account", proc_net); + + dprintk(KERN_INFO IPT_ACCOUNT_NAME ": __exit() left.\n"); +} + +module_init(init); +module_exit(fini); + diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_bcount.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_bcount.c new file mode 100644 index 00000000..63f93a14 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_bcount.c @@ -0,0 +1,59 @@ +/* + + bcount match (experimental) + Copyright (C) 2006 Jonathan Zarate + + Licensed under GNU GPL v2 or later. + +*/ +#include <linux/module.h> +#include <linux/skbuff.h> +#include <net/sock.h> +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ip_conntrack.h> +#include <linux/netfilter_ipv4/ipt_bcount.h> + +// #define LOG printk +#define LOG(...) do { } while (0); + + +static int match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, + const void *matchinfo, int offset, const void *hdr, u_int16_t datalen, int *hotdrop) +{ + const struct ipt_bcount_match *info = matchinfo; + struct ip_conntrack *ct; + enum ip_conntrack_info ctinfo; + + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); + if (!ct) return !info->invert; + return ((ct->bcount >= info->min) && (ct->bcount <= info->max)) ^ info->invert; +} + +static int checkentry(const char *tablename, const struct ipt_ip *ip, void *matchinfo, + unsigned int matchsize, unsigned int hook_mask) +{ + return (matchsize == IPT_ALIGN(sizeof(struct ipt_bcount_match))); +} + + +static struct ipt_match bcount_match += { { NULL, NULL }, "bcount", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + LOG(KERN_INFO "ipt_bcount <" __DATE__ " " __TIME__ "> loaded\n"); + return ipt_register_match(&bcount_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&bcount_match); +} + +module_init(init); +module_exit(fini); + + +MODULE_AUTHOR("Jonathan Zarate"); +MODULE_DESCRIPTION("bcount match"); +MODULE_LICENSE("GPL"); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_condition.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_condition.c new file mode 100644 index 00000000..c8ee72d5 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_condition.c @@ -0,0 +1,256 @@ +/*-------------------------------------------*\ +| Netfilter Condition Module | +| | +| Description: This module allows firewall | +| rules to match using condition variables | +| stored in /proc files. | +| | +| Author: Stephane Ouellette 2002-10-22 | +| <ouellettes@videotron.ca> | +| | +| History: | +| 2003-02-10 Second version with improved | +| locking and simplified code. | +| | +| This software is distributed under the | +| terms of the GNU GPL. | +\*-------------------------------------------*/ + +#include<linux/module.h> +#include<linux/proc_fs.h> +#include<linux/spinlock.h> +#include<linux/string.h> +#include<asm/atomic.h> +#include<linux/netfilter_ipv4/ip_tables.h> +#include<linux/netfilter_ipv4/ipt_condition.h> + + +#ifndef CONFIG_PROC_FS +#error "Proc file system support is required for this module" +#endif + + +MODULE_AUTHOR("Stephane Ouellette <ouellettes@videotron.ca>"); +MODULE_DESCRIPTION("Allows rules to match against condition variables"); +MODULE_LICENSE("GPL"); + + +struct condition_variable { + struct condition_variable *next; + struct proc_dir_entry *status_proc; + atomic_t refcount; + int enabled; /* TRUE == 1, FALSE == 0 */ +}; + + +static rwlock_t list_lock; +static struct condition_variable *head = NULL; +static struct proc_dir_entry *proc_net_condition = NULL; + + +static int +ipt_condition_read_info(char *buffer, char **start, off_t offset, + int length, int *eof, void *data) +{ + struct condition_variable *var = + (struct condition_variable *) data; + + if (offset == 0) { + *start = buffer; + buffer[0] = (var->enabled) ? '1' : '0'; + buffer[1] = '\n'; + return 2; + } + + *eof = 1; + return 0; +} + + +static int +ipt_condition_write_info(struct file *file, const char *buffer, + unsigned long length, void *data) +{ + struct condition_variable *var = + (struct condition_variable *) data; + + if (length) { + /* Match only on the first character */ + switch (buffer[0]) { + case '0': + var->enabled = 0; + break; + case '1': + var->enabled = 1; + } + } + + return (int) length; +} + + +static int +match(const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const void *matchinfo, int offset, + const void *hdr, u_int16_t datalen, int *hotdrop) +{ + const struct condition_info *info = + (const struct condition_info *) matchinfo; + struct condition_variable *var; + int condition_status = 0; + + read_lock(&list_lock); + + for (var = head; var; var = var->next) { + if (strcmp(info->name, var->status_proc->name) == 0) { + condition_status = var->enabled; + break; + } + } + + read_unlock(&list_lock); + + return condition_status ^ info->invert; +} + + + +static int +checkentry(const char *tablename, const struct ipt_ip *ip, + void *matchinfo, unsigned int matchsize, unsigned int hook_mask) +{ + struct condition_info *info = (struct condition_info *) matchinfo; + struct condition_variable *var, *newvar; + + if (matchsize != IPT_ALIGN(sizeof(struct condition_info))) + return 0; + + /* The first step is to check if the condition variable already exists. */ + /* Here, a read lock is sufficient because we won't change the list */ + read_lock(&list_lock); + + for (var = head; var; var = var->next) { + if (strcmp(info->name, var->status_proc->name) == 0) { + atomic_inc(&var->refcount); + read_unlock(&list_lock); + return 1; + } + } + + read_unlock(&list_lock); + + /* At this point, we need to allocate a new condition variable */ + newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL); + + if (!newvar) + return -ENOMEM; + + /* Create the condition variable's proc file entry */ + newvar->status_proc = create_proc_entry(info->name, 0644, proc_net_condition); + + if (!newvar->status_proc) { + /* + * There are two possibilities: + * 1- Another condition variable with the same name has been created, which is valid. + * 2- There was a memory allocation error. + */ + kfree(newvar); + read_lock(&list_lock); + + for (var = head; var; var = var->next) { + if (strcmp(info->name, var->status_proc->name) == 0) { + atomic_inc(&var->refcount); + read_unlock(&list_lock); + return 1; + } + } + + read_unlock(&list_lock); + return -ENOMEM; + } + + atomic_set(&newvar->refcount, 1); + newvar->enabled = 0; + newvar->status_proc->owner = THIS_MODULE; + newvar->status_proc->data = newvar; + wmb(); + newvar->status_proc->read_proc = ipt_condition_read_info; + newvar->status_proc->write_proc = ipt_condition_write_info; + + write_lock(&list_lock); + + newvar->next = head; + head = newvar; + + write_unlock(&list_lock); + + return 1; +} + + +static void +destroy(void *matchinfo, unsigned int matchsize) +{ + struct condition_info *info = (struct condition_info *) matchinfo; + struct condition_variable *var, *prev = NULL; + + if (matchsize != IPT_ALIGN(sizeof(struct condition_info))) + return; + + write_lock(&list_lock); + + for (var = head; var && strcmp(info->name, var->status_proc->name); + prev = var, var = var->next); + + if (var && atomic_dec_and_test(&var->refcount)) { + if (prev) + prev->next = var->next; + else + head = var->next; + + write_unlock(&list_lock); + remove_proc_entry(var->status_proc->name, proc_net_condition); + kfree(var); + } else + write_unlock(&list_lock); +} + + +static struct ipt_match condition_match = { + .name = "condition", + .match = &match, + .checkentry = &checkentry, + .destroy = &destroy, + .me = THIS_MODULE +}; + + +static int __init +init(void) +{ + int errorcode; + + rwlock_init(&list_lock); + proc_net_condition = proc_mkdir("ipt_condition", proc_net); + + if (proc_net_condition) { + errorcode = ipt_register_match(&condition_match); + + if (errorcode) + remove_proc_entry("ipt_condition", proc_net); + } else + errorcode = -EACCES; + + return errorcode; +} + + +static void __exit +fini(void) +{ + ipt_unregister_match(&condition_match); + remove_proc_entry("ipt_condition", proc_net); +} + +module_init(init); +module_exit(fini); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_connlimit.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_connlimit.c new file mode 100644 index 00000000..abf8efff --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_connlimit.c @@ -0,0 +1,222 @@ +/* + * netfilter module to limit the number of parallel tcp + * connections per IP address. + * (c) 2000 Gerd Knorr <kraxel@bytesex.org> + * Nov 2002: Martin Bene <martin.bene@icomedias.com>: + * only ignore TIME_WAIT or gone connections + * + * based on ... + * + * Kernel module to match connection tracking information. + * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au). + */ +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/list.h> +#include <linux/version.h> +#include <linux/netfilter_ipv4/ip_conntrack.h> +#include <linux/netfilter_ipv4/ip_conntrack_core.h> +#include <linux/netfilter_ipv4/ip_conntrack_tcp.h> +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ipt_connlimit.h> + +#define DEBUG 0 + +MODULE_LICENSE("GPL"); + +/* we'll save the tuples of all connections we care about */ +struct ipt_connlimit_conn +{ + struct list_head list; + struct ip_conntrack_tuple tuple; +}; + +struct ipt_connlimit_data { + spinlock_t lock; + struct list_head iphash[256]; +}; + +static inline unsigned ipt_iphash(const unsigned addr) +{ + return ((addr ^ (addr >> 8) ^ (addr >> 16) ^ (addr >> 24)) & 0xff); +} + +static int count_them(struct ipt_connlimit_data *data, + u_int32_t addr, u_int32_t mask, + struct ip_conntrack *ct) +{ +#if DEBUG + const static char *tcp[] = { "none", "established", "syn_sent", "syn_recv", + "fin_wait", "time_wait", "close", "close_wait", + "last_ack", "listen" }; +#endif + int addit = 1, matches = 0; + struct ip_conntrack_tuple tuple; + struct ip_conntrack_tuple_hash *found; + struct ipt_connlimit_conn *conn; + struct list_head *hash,*lh; + + spin_lock_bh(&data->lock); + tuple = ct->tuplehash[0].tuple; + hash = &data->iphash[ipt_iphash(addr & mask)]; + + /* check the saved connections */ + for (lh = hash->next; lh != hash; lh = lh->next) { + conn = list_entry(lh,struct ipt_connlimit_conn,list); + found = ip_conntrack_find_get(&conn->tuple,ct); + if (found != NULL && + 0 == memcmp(&conn->tuple,&tuple,sizeof(tuple)) && + found->ctrack->proto.tcp.state != TCP_CONNTRACK_TIME_WAIT) { + /* Just to be sure we have it only once in the list. + We should'nt see tuples twice unless someone hooks this + into a table without "-p tcp --syn" */ + addit = 0; + } +#if DEBUG + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n", + ipt_iphash(addr & mask), + NIPQUAD(conn->tuple.src.ip), ntohs(conn->tuple.src.u.tcp.port), + NIPQUAD(conn->tuple.dst.ip), ntohs(conn->tuple.dst.u.tcp.port), + (NULL != found) ? tcp[found->ctrack->proto.tcp.state] : "gone"); +#endif + if (NULL == found) { + /* this one is gone */ + lh = lh->prev; + list_del(lh->next); + kfree(conn); + continue; + } + if (found->ctrack->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) { + /* we don't care about connections which are + closed already -> ditch it */ + lh = lh->prev; + list_del(lh->next); + kfree(conn); + nf_conntrack_put(&found->ctrack->infos[0]); + continue; + } + if ((addr & mask) == (conn->tuple.src.ip & mask)) { + /* same source IP address -> be counted! */ + matches++; + } + nf_conntrack_put(&found->ctrack->infos[0]); + } + if (addit) { + /* save the new connection in our list */ +#if DEBUG + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d new\n", + ipt_iphash(addr & mask), + NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port), + NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port)); +#endif + conn = kmalloc(sizeof(*conn),GFP_ATOMIC); + if (NULL == conn) + return -1; + memset(conn,0,sizeof(*conn)); + INIT_LIST_HEAD(&conn->list); + conn->tuple = tuple; + list_add(&conn->list,hash); + matches++; + } + spin_unlock_bh(&data->lock); + return matches; +} + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_connlimit_info *info = matchinfo; + int connections, match; + struct ip_conntrack *ct; + enum ip_conntrack_info ctinfo; + + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); + if (NULL == ct) { + printk("ipt_connlimit: Oops: invalid ct state ?\n"); + *hotdrop = 1; + return 0; + } + connections = count_them(info->data,skb->nh.iph->saddr,info->mask,ct); + if (-1 == connections) { + printk("ipt_connlimit: Hmm, kmalloc failed :-(\n"); + *hotdrop = 1; /* let's free some memory :-) */ + return 0; + } + match = (info->inverse) ? (connections <= info->limit) : (connections > info->limit); +#if DEBUG + printk("ipt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u " + "connections=%d limit=%d match=%s\n", + NIPQUAD(skb->nh.iph->saddr), NIPQUAD(info->mask), + connections, info->limit, match ? "yes" : "no"); +#endif + + return match; +} + +static int check(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + struct ipt_connlimit_info *info = matchinfo; + int i; + + /* verify size */ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_connlimit_info))) + return 0; + + /* refuse anything but tcp */ + if (ip->proto != IPPROTO_TCP) + return 0; + + /* init private data */ + info->data = kmalloc(sizeof(struct ipt_connlimit_data),GFP_KERNEL); + spin_lock_init(&(info->data->lock)); + for (i = 0; i < 256; i++) + INIT_LIST_HEAD(&(info->data->iphash[i])); + + return 1; +} + +static void destroy(void *matchinfo, unsigned int matchinfosize) +{ + struct ipt_connlimit_info *info = matchinfo; + struct ipt_connlimit_conn *conn; + struct list_head *hash; + int i; + + /* cleanup */ + for (i = 0; i < 256; i++) { + hash = &(info->data->iphash[i]); + while (hash != hash->next) { + conn = list_entry(hash->next,struct ipt_connlimit_conn,list); + list_del(hash->next); + kfree(conn); + } + } + kfree(info->data); +} + +static struct ipt_match connlimit_match += { { NULL, NULL }, "connlimit", &match, &check, &destroy, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_match(&connlimit_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&connlimit_match); +} + +module_init(init); +module_exit(fini); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_connmark.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_connmark.c new file mode 100644 index 00000000..d795a339 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_connmark.c @@ -0,0 +1,83 @@ +/* This kernel module matches connection mark values set by the + * CONNMARK target + * + * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com> + * by Henrik Nordstrom <hno@marasystems.com> + * + * 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 + */ + +#include <linux/module.h> +#include <linux/skbuff.h> + +MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>"); +MODULE_DESCRIPTION("IP tables connmark match module"); +MODULE_LICENSE("GPL"); + +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ipt_connmark.h> +#include <linux/netfilter_ipv4/ip_conntrack.h> + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_connmark_info *info = matchinfo; + enum ip_conntrack_info ctinfo; + struct ip_conntrack *ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); + if (!ct) + return 0; + + return ((ct->mark & info->mask) == info->mark) ^ info->invert; +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_connmark_info))) + return 0; + + return 1; +} + +static struct ipt_match connmark_match = { + .name = "connmark", + .match = &match, + .checkentry = &checkentry, + .me = THIS_MODULE +}; + +static int __init init(void) +{ + return ipt_register_match(&connmark_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&connmark_match); +} + +module_init(init); +module_exit(fini); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_exp.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_exp.c new file mode 100644 index 00000000..1b682b9c --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_exp.c @@ -0,0 +1,57 @@ +/* + + Experimental Netfilter Crap + Copyright (C) 2006 Jonathan Zarate + +*/ +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/file.h> +#include <net/sock.h> + +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ipt_exp.h> +#include "../../bridge/br_private.h" + + +static int match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, + const void *matchinfo, int offset, const void *hdr, u_int16_t datalen, int *hotdrop) +{ +// const struct ipt_exp_info *info = matchinfo; + + if ((skb->mac.raw >= skb->head) && ((skb->mac.raw + ETH_HLEN) <= skb->data)) { + printk(KERN_INFO "exp src=%02X:%02X:%02X:%02X:%02X:%02X dst=%02X:%02X:%02X:%02X:%02X:%02X\n", + skb->mac.ethernet->h_source[0], skb->mac.ethernet->h_source[1], skb->mac.ethernet->h_source[2], + skb->mac.ethernet->h_source[3], skb->mac.ethernet->h_source[4], skb->mac.ethernet->h_source[5], + skb->mac.ethernet->h_dest[0], skb->mac.ethernet->h_dest[1], skb->mac.ethernet->h_dest[2], + skb->mac.ethernet->h_dest[3], skb->mac.ethernet->h_dest[4], skb->mac.ethernet->h_dest[5]); + return 1; + } + printk(KERN_INFO "exp mac=%p head=%p in=%p\n", skb->mac.raw, skb->head, in); + return 0; +} + +static int checkentry(const char *tablename, const struct ipt_ip *ip, void *matchinfo, + unsigned int matchsize, unsigned int hook_mask) +{ + return (matchsize == IPT_ALIGN(sizeof(struct ipt_exp_info))); +} + +static struct ipt_match exp_match + = { { NULL, NULL }, "exp", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + printk(KERN_INFO "exp init " __DATE__ " " __TIME__ "\n"); + return ipt_register_match(&exp_match); +} + +static void __exit fini(void) +{ + printk(KERN_INFO "exp fini\n"); + ipt_unregister_match(&exp_match); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_geoip.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_geoip.c new file mode 100644 index 00000000..fbd1a95c --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_geoip.c @@ -0,0 +1,272 @@ +/* netfilter's kernel module for the geoip match + * + * 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. + * + * Copyright (c) 2004 Cookinglinux + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <asm/uaccess.h> +#include <asm/atomic.h> + +#include <linux/netfilter_ipv4/ipt_geoip.h> +#include <linux/netfilter_ipv4/ip_tables.h> + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Samuel Jean, Nicolas Bouliane"); +MODULE_DESCRIPTION("iptables/netfilter's geoip match"); + +struct geoip_info *head = NULL; +static spinlock_t geoip_lock = SPIN_LOCK_UNLOCKED; + +static struct geoip_info *add_node(struct geoip_info *memcpy) +{ + struct geoip_info *p = + (struct geoip_info *)kmalloc(sizeof(struct geoip_info), GFP_KERNEL); + + struct geoip_subnet *s; + + if ((p == NULL) || (copy_from_user(p, memcpy, sizeof(struct geoip_info)) != 0)) + return NULL; + + s = (struct geoip_subnet *)kmalloc(p->count * sizeof(struct geoip_subnet), GFP_KERNEL); + if ((s == NULL) || (copy_from_user(s, p->subnets, p->count * sizeof(struct geoip_subnet)) != 0)) + return NULL; + + spin_lock_bh(&geoip_lock); + + p->subnets = s; + p->ref = 1; + p->next = head; + p->prev = NULL; + if (p->next) p->next->prev = p; + head = p; + + spin_unlock_bh(&geoip_lock); + return p; +} + +static void remove_node(struct geoip_info *p) + { + spin_lock_bh(&geoip_lock); + + if (p->next) { /* Am I following a node ? */ + p->next->prev = p->prev; + if (p->prev) p->prev->next = p->next; /* Is there a node behind me ? */ + else head = p->next; /* No? Then I was the head */ + } + + else + if (p->prev) /* Is there a node behind me ? */ + p->prev->next = NULL; + else + head = NULL; /* No, we're alone */ + + /* So now am unlinked or the only one alive, right ? + * What are you waiting ? Free up some memory! + */ + + kfree(p->subnets); + kfree(p); + + spin_unlock_bh(&geoip_lock); + return; +} + +static struct geoip_info *find_node(u_int16_t cc) +{ + struct geoip_info *p = head; + spin_lock_bh(&geoip_lock); + + while (p) { + if (p->cc == cc) { + spin_unlock_bh(&geoip_lock); + return p; + } + p = p->next; + } + spin_unlock_bh(&geoip_lock); + return NULL; +} + +static int match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_geoip_info *info = matchinfo; + const struct geoip_info *node; /* This keeps the code sexy */ + const struct iphdr *iph = skb->nh.iph; + u_int32_t ip, j; + u_int8_t i; + + if (info->flags & IPT_GEOIP_SRC) + ip = ntohl(iph->saddr); + else + ip = ntohl(iph->daddr); + + spin_lock_bh(&geoip_lock); + for (i = 0; i < info->count; i++) { + if ((node = info->mem[i]) == NULL) { + printk(KERN_ERR "ipt_geoip: what the hell ?? '%c%c' isn't loaded into memory... skip it!\n", + COUNTRY(info->cc[i])); + + continue; + } + + for (j = 0; j < node->count; j++) + if ((ip > node->subnets[j].begin) && (ip < node->subnets[j].end)) { + spin_unlock_bh(&geoip_lock); + return (info->flags & IPT_GEOIP_INV) ? 0 : 1; + } + } + + spin_unlock_bh(&geoip_lock); + return (info->flags & IPT_GEOIP_INV) ? 1 : 0; +} + +static int geoip_checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + struct ipt_geoip_info *info = matchinfo; + struct geoip_info *node; + u_int8_t i; + + /* FIXME: Call a function to free userspace allocated memory. + * As Martin J. said; this match might eat lot of memory + * if commited with iptables-restore --noflush + void (*gfree)(struct geoip_info *oldmem); + gfree = info->fini; + */ + + if (matchsize != IPT_ALIGN(sizeof(struct ipt_geoip_info))) { + printk(KERN_ERR "ipt_geoip: matchsize differ, you may have forgotten to recompile me\n"); + return 0; + } + + /* If info->refcount isn't NULL, then + * it means that checkentry() already + * initialized this entry. Increase a + * refcount to prevent destroy() of + * this entry. */ + if (info->refcount != NULL) { + atomic_inc((atomic_t *)info->refcount); + return 1; + } + + + for (i = 0; i < info->count; i++) { + + if ((node = find_node(info->cc[i])) != NULL) + atomic_inc((atomic_t *)&node->ref); //increase the reference + else + if ((node = add_node(info->mem[i])) == NULL) { + printk(KERN_ERR + "ipt_geoip: unable to load '%c%c' into memory\n", + COUNTRY(info->cc[i])); + return 0; + } + + /* Free userspace allocated memory for that country. + * FIXME: It's a bit odd to call this function everytime + * we process a country. Would be nice to call + * it once after all countries've been processed. + * - SJ + * *not implemented for now* + gfree(info->mem[i]); + */ + + /* Overwrite the now-useless pointer info->mem[i] with + * a pointer to the node's kernelspace structure. + * This avoids searching for a node in the match() and + * destroy() functions. + */ + info->mem[i] = node; + } + + /* We allocate some memory and give info->refcount a pointer + * to this memory. This prevents checkentry() from increasing a refcount + * different from the one used by destroy(). + * For explanation, see http://www.mail-archive.com/netfilter-devel@lists.samba.org/msg00625.html + */ + info->refcount = kmalloc(sizeof(u_int8_t), GFP_KERNEL); + if (info->refcount == NULL) { + printk(KERN_ERR "ipt_geoip: failed to allocate `refcount' memory\n"); + return 0; + } + *(info->refcount) = 1; + + return 1; +} + +static void geoip_destroy(void *matchinfo, unsigned int matchsize) +{ + struct ipt_geoip_info *info = matchinfo; + struct geoip_info *node; /* this keeps the code sexy */ + u_int8_t i; + + /* Decrease the previously increased refcount in checkentry() + * If it's equal to 1, we know this entry is just moving + * but not removed. We simply return to avoid useless destroy() + * processing. + */ + atomic_dec((atomic_t *)info->refcount); + if (*info->refcount) + return; + + /* Don't leak my memory, you idiot. + * Bug found with nfsim.. the netfilter's best + * friend. --peejix */ + kfree(info->refcount); + + /* This entry has been removed from the table so + * decrease the refcount of all countries it is + * using. + */ + + for (i = 0; i < info->count; i++) + if ((node = info->mem[i]) != NULL) { + atomic_dec((atomic_t *)&node->ref); + + /* Free up some memory if that node isn't used + * anymore. */ + if (node->ref < 1) + remove_node(node); + } + else + /* Something strange happened. There's no memory allocated for this + * country. Please send this bug to the mailing list. */ + printk(KERN_ERR + "ipt_geoip: What happened peejix ? What happened acidmen ?\n" + "ipt_geoip: please report this bug to the maintainers\n"); + return; +} + +static struct ipt_match geoip_match += { { NULL, NULL }, "geoip", &match, &geoip_checkentry, &geoip_destroy, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_match(&geoip_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&geoip_match); + return; +} + +module_init(init); +module_exit(fini); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_ipp2p.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_ipp2p.c new file mode 100644 index 00000000..c36b2005 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_ipp2p.c @@ -0,0 +1,868 @@ +#if defined(MODVERSIONS) +#include <linux/modversions.h> +#endif +#include <linux/module.h> +#include <linux/version.h> +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ipt_ipp2p.h> +#include <net/tcp.h> +#include <net/udp.h> + +#define get_u8(X,O) (*(__u8 *)(X + O)) +#define get_u16(X,O) (*(__u16 *)(X + O)) +#define get_u32(X,O) (*(__u32 *)(X + O)) + +MODULE_AUTHOR("Eicke Friedrich/Klaus Degner <ipp2p@ipp2p.org>"); +MODULE_DESCRIPTION("An extension to iptables to identify P2P traffic."); +MODULE_LICENSE("GPL"); + + +/*Search for UDP eDonkey/eMule/Kad commands*/ +int +udp_search_edk (unsigned char *haystack, int packet_len) +{ + unsigned char *t = haystack; + t += 8; + + switch (t[0]) { + case 0xe3: + { /*edonkey*/ + switch (t[1]) + { + /* client -> server status request */ + case 0x96: + if (packet_len == 14) return ((IPP2P_EDK * 100) + 50); + break; + /* server -> client status request */ + case 0x97: if (packet_len == 42) return ((IPP2P_EDK * 100) + 51); + break; + /* server description request */ + /* e3 2a ff f0 .. | size == 6 */ + case 0xa2: if ( (packet_len == 14) && ( get_u16(t,2) == __constant_htons(0xfff0) ) ) return ((IPP2P_EDK * 100) + 52); + break; + /* server description response */ + /* e3 a3 ff f0 .. | size > 40 && size < 200 */ + //case 0xa3: return ((IPP2P_EDK * 100) + 53); + // break; + case 0x9a: if (packet_len==26) return ((IPP2P_EDK * 100) + 54); + break; + + case 0x92: if (packet_len==18) return ((IPP2P_EDK * 100) + 55); + break; + } + break; + } + case 0xe4: + { + switch (t[1]) + { + /* e4 20 .. | size == 43 */ + case 0x20: if ((packet_len == 43) && (t[2] != 0x00) && (t[34] != 0x00)) return ((IPP2P_EDK * 100) + 60); + break; + /* e4 00 .. 00 | size == 35 ? */ + case 0x00: if ((packet_len == 35) && (t[26] == 0x00)) return ((IPP2P_EDK * 100) + 61); + break; + /* e4 10 .. 00 | size == 35 ? */ + case 0x10: if ((packet_len == 35) && (t[26] == 0x00)) return ((IPP2P_EDK * 100) + 62); + break; + /* e4 18 .. 00 | size == 35 ? */ + case 0x18: if ((packet_len == 35) && (t[26] == 0x00)) return ((IPP2P_EDK * 100) + 63); + break; + /* e4 52 .. | size = 44 */ + case 0x52: if (packet_len == 44 ) return ((IPP2P_EDK * 100) + 64); + break; + /* e4 58 .. | size == 6 */ + case 0x58: if (packet_len == 14 ) return ((IPP2P_EDK * 100) + 65); + break; + /* e4 59 .. | size == 2 */ + case 0x59: if (packet_len == 10 )return ((IPP2P_EDK * 100) + 66); + break; + /* e4 28 .. | packet_len == 52,77,102,127... */ + case 0x28: if (((packet_len-52) % 25) == 0) return ((IPP2P_EDK * 100) + 67); + break; + /* e4 50 xx xx | size == 4 */ + case 0x50: if (packet_len == 12) return ((IPP2P_EDK * 100) + 68); + break; + /* e4 40 xx xx | size == 48 */ + case 0x40: if (packet_len == 56) return ((IPP2P_EDK * 100) + 69); + break; + } + break; + } + } /* end of switch (t[0]) */ + return 0; +}/*udp_search_edk*/ + + +/*Search for UDP Gnutella commands*/ +int +udp_search_gnu (unsigned char *haystack, int packet_len) +{ + unsigned char *t = haystack; + t += 8; + + if (memcmp(t, "GND", 3) == 0) return ((IPP2P_GNU * 100) + 51); + if (memcmp(t, "GNUTELLA ", 9) == 0) return ((IPP2P_GNU * 100) + 52); + return 0; +}/*udp_search_gnu*/ + + +/*Search for UDP KaZaA commands*/ +int +udp_search_kazaa (unsigned char *haystack, int packet_len) +{ + unsigned char *t = haystack; + + if (t[packet_len-1] == 0x00){ + t += (packet_len - 6); + if (memcmp(t, "KaZaA", 5) == 0) return (IPP2P_KAZAA * 100 +50); + } + + return 0; +}/*udp_search_kazaa*/ + +/*Search for UDP DirectConnect commands*/ +int +udp_search_directconnect (unsigned char *haystack, int packet_len) +{ + unsigned char *t = haystack; + if ((*(t + 8) == 0x24) && (*(t + packet_len - 1) == 0x7c)) { + t+=8; + if (memcmp(t, "SR ", 3) == 0) return ((IPP2P_DC * 100) + 60); + if (memcmp(t, "Ping ", 5) == 0) return ((IPP2P_DC * 100) + 61); + } + return 0; +}/*udp_search_directconnect*/ + + + +/*Search for UDP BitTorrent commands*/ +int +udp_search_bit (unsigned char *haystack, int packet_len) +{ + switch(packet_len) + { + case 24: + /* ^ 00 00 04 17 27 10 19 80 */ + if ((ntohl(get_u32(haystack, 8)) == 0x00000417) && (ntohl(get_u32(haystack, 12)) == 0x27101980)) + return (IPP2P_BIT * 100 + 50); + break; + case 44: + if (get_u32(haystack, 16) == __constant_htonl(0x00000400) && get_u32(haystack, 36) == __constant_htonl(0x00000104)) + return (IPP2P_BIT * 100 + 51); + if (get_u32(haystack, 16) == __constant_htonl(0x00000400)) + return (IPP2P_BIT * 100 + 61); + break; + case 65: + if (get_u32(haystack, 16) == __constant_htonl(0x00000404) && get_u32(haystack, 36) == __constant_htonl(0x00000104)) + return (IPP2P_BIT * 100 + 52); + if (get_u32(haystack, 16) == __constant_htonl(0x00000404)) + return (IPP2P_BIT * 100 + 62); + break; + case 67: + if (get_u32(haystack, 16) == __constant_htonl(0x00000406) && get_u32(haystack, 36) == __constant_htonl(0x00000104)) + return (IPP2P_BIT * 100 + 53); + if (get_u32(haystack, 16) == __constant_htonl(0x00000406)) + return (IPP2P_BIT * 100 + 63); + break; + case 211: + if (get_u32(haystack, 8) == __constant_htonl(0x00000405)) + return (IPP2P_BIT * 100 + 54); + break; + case 29: + if ((get_u32(haystack, 8) == __constant_htonl(0x00000401))) + return (IPP2P_BIT * 100 + 55); + break; + case 52: + if (get_u32(haystack,8) == __constant_htonl(0x00000827) && + get_u32(haystack,12) == __constant_htonl(0x37502950)) + return (IPP2P_BIT * 100 + 80); + break; + default: + /* this packet does not have a constant size */ + if (packet_len >= 40 && get_u32(haystack, 16) == __constant_htonl(0x00000402) && get_u32(haystack, 36) == __constant_htonl(0x00000104)) + return (IPP2P_BIT * 100 + 56); + break; + } + + /* some extra-bitcomet rules: + * "d1:" [a|r] "d2:id20:" + */ + if (packet_len > 30 && get_u8(haystack, 8) == 'd' && get_u8(haystack, 9) == '1' && get_u8(haystack, 10) == ':' ) + { + if (get_u8(haystack, 11) == 'a' || get_u8(haystack, 11) == 'r') + { + if (memcmp(haystack+12,"d2:id20:",8)==0) + return (IPP2P_BIT * 100 + 57); + } + } + +#if 0 + /* bitlord rules */ + /* packetlen must be bigger than 40 */ + /* first 4 bytes are zero */ + if (packet_len > 40 && get_u32(haystack, 8) == 0x00000000) + { + /* first rule: 00 00 00 00 01 00 00 xx xx xx xx 00 00 00 00*/ + if (get_u32(haystack, 12) == 0x00000000 && + get_u32(haystack, 16) == 0x00010000 && + get_u32(haystack, 24) == 0x00000000 ) + return (IPP2P_BIT * 100 + 71); + + /* 00 01 00 00 0d 00 00 xx xx xx xx 00 00 00 00*/ + if (get_u32(haystack, 12) == 0x00000001 && + get_u32(haystack, 16) == 0x000d0000 && + get_u32(haystack, 24) == 0x00000000 ) + return (IPP2P_BIT * 100 + 71); + + + } +#endif + + return 0; +}/*udp_search_bit*/ + + + +/*Search for Ares commands*/ +//#define IPP2P_DEBUG_ARES +int +search_ares (const unsigned char *payload, const u16 plen) +//int search_ares (unsigned char *haystack, int packet_len, int head_len) +{ +// const unsigned char *t = haystack + head_len; + + /* all ares packets start with */ + if (payload[1] == 0 && (plen - payload[0]) == 3) + { + switch (payload[2]) + { + case 0x5a: + /* ares connect */ + if ( plen == 6 && payload[5] == 0x05 ) return ((IPP2P_ARES * 100) + 1); + break; + case 0x09: + /* ares search, min 3 chars --> 14 bytes + * lets define a search can be up to 30 chars --> max 34 bytes + */ + if ( plen >= 14 && plen <= 34 ) return ((IPP2P_ARES * 100) + 1); + break; +#ifdef IPP2P_DEBUG_ARES + default: + printk(KERN_DEBUG "Unknown Ares command %x recognized, len: %u \n", (unsigned int) payload[2],plen); +#endif /* IPP2P_DEBUG_ARES */ + } + } + +#if 0 + /* found connect packet: 03 00 5a 04 03 05 */ + /* new version ares 1.8: 03 00 5a xx xx 05 */ + if ((plen) == 6){ /* possible connect command*/ + if ((payload[0] == 0x03) && (payload[1] == 0x00) && (payload[2] == 0x5a) && (payload[5] == 0x05)) + return ((IPP2P_ARES * 100) + 1); + } + if ((plen) == 60){ /* possible download command*/ + if ((payload[59] == 0x0a) && (payload[58] == 0x0a)){ + if (memcmp(t, "PUSH SHA1:", 10) == 0) /* found download command */ + return ((IPP2P_ARES * 100) + 2); + } + } +#endif + + return 0; +} /*search_ares*/ + +/*Search for SoulSeek commands*/ +int +search_soul (const unsigned char *payload, const u16 plen) +{ +//#define IPP2P_DEBUG_SOUL + /* match: xx xx xx xx | xx = sizeof(payload) - 4 */ + if (get_u32(payload, 0) == (plen - 4)){ + const __u32 m=get_u32(payload, 4); + /* match 00 yy yy 00, yy can be everything */ + if ( get_u8(payload, 4) == 0x00 && get_u8(payload, 7) == 0x00 ) + { +#ifdef IPP2P_DEBUG_SOUL + printk(KERN_DEBUG "0: Soulseek command 0x%x recognized\n",get_u32(payload, 4)); +#endif /* IPP2P_DEBUG_SOUL */ + return ((IPP2P_SOUL * 100) + 1); + } + + /* next match: 01 yy 00 00 | yy can be everything */ + if ( get_u8(payload, 4) == 0x01 && get_u16(payload, 6) == 0x0000 ) + { +#ifdef IPP2P_DEBUG_SOUL + printk(KERN_DEBUG "1: Soulseek command 0x%x recognized\n",get_u16(payload, 4)); +#endif /* IPP2P_DEBUG_SOUL */ + return ((IPP2P_SOUL * 100) + 2); + } + + /* other soulseek commandos are: 1-5,7,9,13-18,22,23,26,28,35-37,40-46,50,51,60,62-69,91,92,1001 */ + /* try to do this in an intelligent way */ + /* get all small commandos */ + switch(m) + { + case 7: + case 9: + case 22: + case 23: + case 26: + case 28: + case 50: + case 51: + case 60: + case 91: + case 92: + case 1001: +#ifdef IPP2P_DEBUG_SOUL + printk(KERN_DEBUG "2: Soulseek command 0x%x recognized\n",get_u16(payload, 4)); +#endif /* IPP2P_DEBUG_SOUL */ + return ((IPP2P_SOUL * 100) + 3); + } + + if (m > 0 && m < 6 ) + { +#ifdef IPP2P_DEBUG_SOUL + printk(KERN_DEBUG "3: Soulseek command 0x%x recognized\n",get_u16(payload, 4)); +#endif /* IPP2P_DEBUG_SOUL */ + return ((IPP2P_SOUL * 100) + 4); + } + if (m > 12 && m < 19 ) + { +#ifdef IPP2P_DEBUG_SOUL + printk(KERN_DEBUG "4: Soulseek command 0x%x recognized\n",get_u16(payload, 4)); +#endif /* IPP2P_DEBUG_SOUL */ + return ((IPP2P_SOUL * 100) + 5); + } + + if (m > 34 && m < 38 ) + { +#ifdef IPP2P_DEBUG_SOUL + printk(KERN_DEBUG "5: Soulseek command 0x%x recognized\n",get_u16(payload, 4)); +#endif /* IPP2P_DEBUG_SOUL */ + return ((IPP2P_SOUL * 100) + 6); + } + + if (m > 39 && m < 47 ) + { +#ifdef IPP2P_DEBUG_SOUL + printk(KERN_DEBUG "6: Soulseek command 0x%x recognized\n",get_u16(payload, 4)); +#endif /* IPP2P_DEBUG_SOUL */ + return ((IPP2P_SOUL * 100) + 7); + } + + if (m > 61 && m < 70 ) + { +#ifdef IPP2P_DEBUG_SOUL + printk(KERN_DEBUG "7: Soulseek command 0x%x recognized\n",get_u16(payload, 4)); +#endif /* IPP2P_DEBUG_SOUL */ + return ((IPP2P_SOUL * 100) + 8); + } + +#ifdef IPP2P_DEBUG_SOUL + printk(KERN_DEBUG "unknown SOULSEEK command: 0x%x, first 16 bit: 0x%x, first 8 bit: 0x%x ,soulseek ???\n",get_u32(payload, 4),get_u16(payload, 4) >> 16,get_u8(payload, 4) >> 24); +#endif /* IPP2P_DEBUG_SOUL */ + } + + /* match 14 00 00 00 01 yy 00 00 00 STRING(YY) 01 00 00 00 00 46|50 00 00 00 00 */ + /* without size at the beginning !!! */ + if ( get_u32(payload, 0) == 0x14 && get_u8(payload, 4) == 0x01 ) + { + __u32 y=get_u32(payload, 5); + /* we need 19 chars + string */ + if ( (y + 19) <= (plen) ) + { + const unsigned char *w=payload+9+y; + if (get_u32(w, 0) == 0x01 && ( get_u16(w, 4) == 0x4600 || get_u16(w, 4) == 0x5000) && get_u32(w, 6) == 0x00); +#ifdef IPP2P_DEBUG_SOUL + printk(KERN_DEBUG "Soulssek special client command recognized\n"); +#endif /* IPP2P_DEBUG_SOUL */ + return ((IPP2P_SOUL * 100) + 9); + } + } + return 0; +} + + +/*Search for WinMX commands*/ +int +search_winmx (const unsigned char *payload, const u16 plen) +{ +//#define IPP2P_DEBUG_WINMX + if (((plen) == 4) && (memcmp(payload, "SEND", 4) == 0)) return ((IPP2P_WINMX * 100) + 1); + if (((plen) == 3) && (memcmp(payload, "GET", 3) == 0)) return ((IPP2P_WINMX * 100) + 2); + //if (packet_len < (head_len + 10)) return 0; + if (plen < 10) return 0; + + if ((memcmp(payload, "SEND", 4) == 0) || (memcmp(payload, "GET", 3) == 0)){ + u16 c=4; + const u16 end=plen-2; + u8 count=0; + while (c < end) + { + if (payload[c]== 0x20 && payload[c+1] == 0x22) + { + c++; + count++; + if (count>=2) return ((IPP2P_WINMX * 100) + 3); + } + c++; + } + } + + if ( plen == 149 && payload[0] == '8' ) + { +#ifdef IPP2P_DEBUG_WINMX + printk(KERN_INFO "maybe WinMX\n"); +#endif + if (get_u32(payload,17) == 0 && get_u32(payload,21) == 0 && get_u32(payload,25) == 0 && +// get_u32(payload,33) == __constant_htonl(0x71182b1a) && get_u32(payload,37) == __constant_htonl(0x05050000) && +// get_u32(payload,133) == __constant_htonl(0x31097edf) && get_u32(payload,145) == __constant_htonl(0xdcb8f792)) + get_u16(payload,39) == 0 && get_u16(payload,135) == __constant_htons(0x7edf) && get_u16(payload,147) == __constant_htons(0xf792)) + + { +#ifdef IPP2P_DEBUG_WINMX + printk(KERN_INFO "got WinMX\n"); +#endif + return ((IPP2P_WINMX * 100) + 4); + } + } + return 0; +} /*search_winmx*/ + + +/*Search for appleJuice commands*/ +int +search_apple (const unsigned char *payload, const u16 plen) +{ + if ( (plen > 7) && (payload[6] == 0x0d) && (payload[7] == 0x0a) && (memcmp(payload, "ajprot", 6) == 0)) return (IPP2P_APPLE * 100); + + return 0; +} + + +/*Search for BitTorrent commands*/ +int +search_bittorrent (const unsigned char *payload, const u16 plen) +{ + if (plen > 20) + { + /* test for match 0x13+"BitTorrent protocol" */ + if (payload[0] == 0x13) + { + if (memcmp(payload+1, "BitTorrent protocol", 19) == 0) return (IPP2P_BIT * 100); + } + + /* get tracker commandos, all starts with GET / + * then it can follow: scrape| announce + * and then ?hash_info= + */ + if (memcmp(payload,"GET /",5) == 0) + { + /* message scrape */ + if ( memcmp(payload+5,"scrape?info_hash=",17)==0 ) return (IPP2P_BIT * 100 + 1); + /* message announce */ + if ( memcmp(payload+5,"announce?info_hash=",19)==0 ) return (IPP2P_BIT * 100 + 2); + } + } + else + { + /* bitcomet encryptes the first packet, so we have to detect another + * one later in the flow */ + /* first try failed, too many missdetections */ + //if ( size == 5 && get_u32(t,0) == __constant_htonl(1) && t[4] < 3) return (IPP2P_BIT * 100 + 3); + + /* second try: block request packets */ + if ( plen == 17 && get_u32(payload,0) == __constant_htonl(0x0d) && payload[4] == 0x06 && get_u32(payload,13) == __constant_htonl(0x4000) ) return (IPP2P_BIT * 100 + 3); + } + + return 0; +} + + + +/*check for Kazaa get command*/ +int +search_kazaa (const unsigned char *payload, const u16 plen) + +{ + if ((payload[plen-2] == 0x0d) && (payload[plen-1] == 0x0a) && memcmp(payload, "GET /.hash=", 11) == 0) + return (IPP2P_DATA_KAZAA * 100); + + return 0; +} + + +/*check for gnutella get command*/ +int +search_gnu (const unsigned char *payload, const u16 plen) +{ + if ((payload[plen-2] == 0x0d) && (payload[plen-1] == 0x0a)) + { + if (memcmp(payload, "GET /get/", 9) == 0) return ((IPP2P_DATA_GNU * 100) + 1); + if (memcmp(payload, "GET /uri-res/", 13) == 0) return ((IPP2P_DATA_GNU * 100) + 2); + } + return 0; +} + + +/*check for gnutella get commands and other typical data*/ +int +search_all_gnu (const unsigned char *payload, const u16 plen) +{ + + if ((payload[plen-2] == 0x0d) && (payload[plen-1] == 0x0a)) + { + + if (memcmp(payload, "GNUTELLA CONNECT/", 17) == 0) return ((IPP2P_GNU * 100) + 1); + if (memcmp(payload, "GNUTELLA/", 9) == 0) return ((IPP2P_GNU * 100) + 2); + + + if ((memcmp(payload, "GET /get/", 9) == 0) || (memcmp(payload, "GET /uri-res/", 13) == 0)) + { + u16 c=8; + const u16 end=plen-22; + while (c < end) { + if ( payload[c] == 0x0a && payload[c+1] == 0x0d && ((memcmp(&payload[c+2], "X-Gnutella-", 11) == 0) || (memcmp(&payload[c+2], "X-Queue:", 8) == 0))) + return ((IPP2P_GNU * 100) + 3); + c++; + } + } + } + return 0; +} + + +/*check for KaZaA download commands and other typical data*/ +int +search_all_kazaa (const unsigned char *payload, const u16 plen) +{ + if ((payload[plen-2] == 0x0d) && (payload[plen-1] == 0x0a)) + { + + if (memcmp(payload, "GIVE ", 5) == 0) return ((IPP2P_KAZAA * 100) + 1); + + if (memcmp(payload, "GET /", 5) == 0) { + u16 c = 8; + const u16 end=plen-22; + while (c < end) { + if ( payload[c] == 0x0a && payload[c+1] == 0x0d && ((memcmp(&payload[c+2], "X-Kazaa-Username: ", 18) == 0) || (memcmp(&payload[c+2], "User-Agent: PeerEnabler/", 24) == 0))) + return ((IPP2P_KAZAA * 100) + 2); + c++; + } + } + } + return 0; +} + +/*fast check for edonkey file segment transfer command*/ +int +search_edk (const unsigned char *payload, const u16 plen) +{ + if (payload[0] != 0xe3) + return 0; + else { + if (payload[5] == 0x47) + return (IPP2P_DATA_EDK * 100); + else + return 0; + } +} + + + +/*intensive but slower search for some edonkey packets including size-check*/ +int +search_all_edk (const unsigned char *payload, const u16 plen) +{ + if (payload[0] != 0xe3) + return 0; + else { + //t += head_len; + const u16 cmd = get_u16(payload, 1); + if (cmd == (plen - 5)) { + switch (payload[5]) { + case 0x01: return ((IPP2P_EDK * 100) + 1); /*Client: hello or Server:hello*/ + case 0x4c: return ((IPP2P_EDK * 100) + 9); /*Client: Hello-Answer*/ + } + } + return 0; + } +} + + +/*fast check for Direct Connect send command*/ +int +search_dc (const unsigned char *payload, const u16 plen) +{ + + if (payload[0] != 0x24 ) + return 0; + else { + if (memcmp(&payload[1], "Send|", 5) == 0) + return (IPP2P_DATA_DC * 100); + else + return 0; + } + +} + + +/*intensive but slower check for all direct connect packets*/ +int +search_all_dc (const unsigned char *payload, const u16 plen) +{ +// unsigned char *t = haystack; + + if (payload[0] == 0x24 && payload[plen-1] == 0x7c) + { + const unsigned char *t=&payload[1]; + /* Client-Hub-Protocol */ + if (memcmp(t, "Lock ", 5) == 0) return ((IPP2P_DC * 100) + 1); + /* Client-Client-Protocol, some are already recognized by client-hub (like lock) */ + if (memcmp(t, "MyNick ", 7) == 0) return ((IPP2P_DC * 100) + 38); + } + return 0; +} + +/*check for mute*/ +int +search_mute (const unsigned char *payload, const u16 plen) +{ + if ( plen == 209 || plen == 345 || plen == 473 || plen == 609 || plen == 1121 ) + { + //printk(KERN_DEBUG "size hit: %u",size); + if (memcmp(payload,"PublicKey: ",11) == 0 ) + { + return ((IPP2P_MUTE * 100) + 0); + +/* if (memcmp(t+size-14,"\x0aEndPublicKey\x0a",14) == 0) + { + printk(KERN_DEBUG "end pubic key hit: %u",size); + + }*/ + } + } + return 0; +} + + +/* check for xdcc */ +int +search_xdcc (const unsigned char *payload, const u16 plen) +{ + /* search in small packets only */ + if (plen > 20 && plen < 200 && payload[plen-1] == 0x0a && payload[plen-2] == 0x0d && memcmp(payload,"PRIVMSG ",8) == 0) + { + + u16 x=10; + const u16 end=plen - 13; + + /* is seems to be a irc private massage, chedck for xdcc command */ + while (x < end) + { + if (payload[x] == ':') + { + if ( memcmp(&payload[x+1],"xdcc send #",11) == 0 ) + return ((IPP2P_XDCC * 100) + 0); + } + x++; + } + } + return 0; +} + +/* search for waste */ +int search_waste(const unsigned char *payload, const u16 plen) +{ + if ( plen >= 8 && memcmp(payload,"GET.sha1:",9) == 0) + return ((IPP2P_WASTE * 100) + 0); + + return 0; +} + + +static struct { + int command; + __u8 short_hand; /*for fucntions included in short hands*/ + int packet_len; + int (*function_name) (const unsigned char *, const u16); +} matchlist[] = { + {IPP2P_EDK,SHORT_HAND_IPP2P,20, &search_all_edk}, +// {IPP2P_DATA_KAZAA,SHORT_HAND_DATA,200, &search_kazaa}, +// {IPP2P_DATA_EDK,SHORT_HAND_DATA,60, &search_edk}, +// {IPP2P_DATA_DC,SHORT_HAND_DATA,26, &search_dc}, + {IPP2P_DC,SHORT_HAND_IPP2P,5, search_all_dc}, +// {IPP2P_DATA_GNU,SHORT_HAND_DATA,40, &search_gnu}, + {IPP2P_GNU,SHORT_HAND_IPP2P,5, &search_all_gnu}, + {IPP2P_KAZAA,SHORT_HAND_IPP2P,5, &search_all_kazaa}, + {IPP2P_BIT,SHORT_HAND_IPP2P,20, &search_bittorrent}, + {IPP2P_APPLE,SHORT_HAND_IPP2P,5, &search_apple}, + {IPP2P_SOUL,SHORT_HAND_IPP2P,5, &search_soul}, + {IPP2P_WINMX,SHORT_HAND_IPP2P,2, &search_winmx}, + {IPP2P_ARES,SHORT_HAND_IPP2P,5, &search_ares}, + {IPP2P_MUTE,SHORT_HAND_NONE,200, &search_mute}, + {IPP2P_WASTE,SHORT_HAND_NONE,5, &search_waste}, + {IPP2P_XDCC,SHORT_HAND_NONE,5, &search_xdcc}, + {0,0,0,NULL} +}; + + +static struct { + int command; + __u8 short_hand; /*for fucntions included in short hands*/ + int packet_len; + int (*function_name) (unsigned char *, int); +} udp_list[] = { + {IPP2P_KAZAA,SHORT_HAND_IPP2P,14, &udp_search_kazaa}, + {IPP2P_BIT,SHORT_HAND_IPP2P,23, &udp_search_bit}, + {IPP2P_GNU,SHORT_HAND_IPP2P,11, &udp_search_gnu}, + {IPP2P_EDK,SHORT_HAND_IPP2P,9, &udp_search_edk}, + {IPP2P_DC,SHORT_HAND_IPP2P,12, &udp_search_directconnect}, + {0,0,0,NULL} +}; + + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + const void *hdr, + u_int16_t datalen, +#endif + + int *hotdrop) +{ + const struct ipt_p2p_info *info = matchinfo; + unsigned char *haystack; + struct iphdr *ip = skb->nh.iph; + int p2p_result = 0, i = 0; +// int head_len; + int hlen = ntohs(ip->tot_len)-(ip->ihl*4); /*hlen = packet-data length*/ + + /*must not be a fragment*/ + if (offset) { + if (info->debug) printk("IPP2P.match: offset found %i \n",offset); + return 0; + } + + /*make sure that skb is linear*/ + if(skb_is_nonlinear(skb)){ + if (info->debug) printk("IPP2P.match: nonlinear skb found\n"); + return 0; + } + + + haystack=(char *)ip+(ip->ihl*4); /*haystack = packet data*/ + + switch (ip->protocol){ + case IPPROTO_TCP: /*what to do with a TCP packet*/ + { + struct tcphdr *tcph = (void *) ip + ip->ihl * 4; + + if (tcph->fin) return 0; /*if FIN bit is set bail out*/ + if (tcph->syn) return 0; /*if SYN bit is set bail out*/ + if (tcph->rst) return 0; /*if RST bit is set bail out*/ + + haystack += tcph->doff * 4; /*get TCP-Header-Size*/ + hlen -= tcph->doff * 4; + while (matchlist[i].command) { + if ((((info->cmd & matchlist[i].command) == matchlist[i].command) || + ((info->cmd & matchlist[i].short_hand) == matchlist[i].short_hand)) && + (hlen > matchlist[i].packet_len)) { + p2p_result = matchlist[i].function_name(haystack, hlen); + if (p2p_result) + { + if (info->debug) printk("IPP2P.debug:TCP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n", + p2p_result, NIPQUAD(ip->saddr),ntohs(tcph->source), NIPQUAD(ip->daddr),ntohs(tcph->dest),hlen); + return p2p_result; + } + } + i++; + } + return p2p_result; + } + + case IPPROTO_UDP: /*what to do with an UDP packet*/ + { + struct udphdr *udph = (void *) ip + ip->ihl * 4; + + while (udp_list[i].command){ + if ((((info->cmd & udp_list[i].command) == udp_list[i].command) || + ((info->cmd & udp_list[i].short_hand) == udp_list[i].short_hand)) && + (hlen > udp_list[i].packet_len)) { + p2p_result = udp_list[i].function_name(haystack, hlen); + if (p2p_result){ + if (info->debug) printk("IPP2P.debug:UDP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n", + p2p_result, NIPQUAD(ip->saddr),ntohs(udph->source), NIPQUAD(ip->daddr),ntohs(udph->dest),hlen); + return p2p_result; + } + } + i++; + } + return p2p_result; + } + + default: return 0; + } +} + + + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + /* Must specify -p tcp */ +/* if (ip->proto != IPPROTO_TCP || (ip->invflags & IPT_INV_PROTO)) { + * printk("ipp2p: Only works on TCP packets, use -p tcp\n"); + * return 0; + * }*/ + return 1; +} + + + + +static struct ipt_match ipp2p_match = { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + { NULL, NULL }, + "ipp2p", + &match, + &checkentry, + NULL, + THIS_MODULE +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + .name = "ipp2p", + .match = &match, + .checkentry = &checkentry, + .me = THIS_MODULE, +#endif +}; + + +static int __init init(void) +{ + printk(KERN_INFO "IPP2P v%s loading\n", IPP2P_VERSION); + return ipt_register_match(&ipp2p_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&ipp2p_match); + printk(KERN_INFO "IPP2P v%s unloaded\n", IPP2P_VERSION); +} + +module_init(init); +module_exit(fini); + + diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_iprange.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_iprange.c new file mode 100644 index 00000000..38902524 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_iprange.c @@ -0,0 +1,101 @@ +/* + * iptables module to match IP address ranges + * (c) 2003 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> + * + * Released under the terms of GNU GPLv2. + * + */ +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/ip.h> +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ipt_iprange.h> + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); +MODULE_DESCRIPTION("iptables arbitrary IP range match module"); + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_iprange_info *info = matchinfo; + const struct iphdr *iph = skb->nh.iph; + + + if (info->flags & IPRANGE_SRC) { + if (((ntohl(iph->saddr) < ntohl(info->src.min_ip)) + || (ntohl(iph->saddr) > ntohl(info->src.max_ip))) + ^ !!(info->flags & IPRANGE_SRC_INV)) { + DEBUGP("src IP %u.%u.%u.%u NOT in range %s" + "%u.%u.%u.%u-%u.%u.%u.%u\n", + NIPQUAD(iph->saddr), + info->flags & IPRANGE_SRC_INV ? "(INV) " : "", + NIPQUAD(info->src.min_ip), + NIPQUAD(info->src.max_ip)); + return 0; + } + } + if (info->flags & IPRANGE_DST) { + if (((ntohl(iph->daddr) < ntohl(info->dst.min_ip)) + || (ntohl(iph->daddr) > ntohl(info->dst.max_ip))) + ^ !!(info->flags & IPRANGE_DST_INV)) { + DEBUGP("dst IP %u.%u.%u.%u NOT in range %s" + "%u.%u.%u.%u-%u.%u.%u.%u\n", + NIPQUAD(iph->daddr), + info->flags & IPRANGE_DST_INV ? "(INV) " : "", + NIPQUAD(info->dst.min_ip), + NIPQUAD(info->dst.max_ip)); + return 0; + } + } + return 1; +} + +static int check(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + /* verify size */ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_iprange_info))) + return 0; + + return 1; +} + +static struct ipt_match iprange_match = +{ + .list = { NULL, NULL }, + .name = "iprange", + .match = &match, + .checkentry = &check, + .destroy = NULL, + .me = THIS_MODULE +}; + +static int __init init(void) +{ + return ipt_register_match(&iprange_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&iprange_match); +} + +module_init(init); +module_exit(fini); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_layer7.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_layer7.c new file mode 100644 index 00000000..567e3847 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_layer7.c @@ -0,0 +1,570 @@ +/* + Kernel module to match application layer (OSI layer 7) + data in connections. + + http://l7-filter.sf.net + + By Matthew Strait and Ethan Sommer, 2003-2005. + + 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. + http://www.gnu.org/licenses/gpl.txt + + Based on ipt_string.c (C) 2000 Emmanuel Roger <winfield@freegates.be> + and cls_layer7.c (C) 2003 Matthew Strait, Ethan Sommer, Justin Levandoski +*/ + +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/netfilter_ipv4/ip_conntrack.h> +#include <linux/proc_fs.h> +#include <linux/ctype.h> +#include <net/ip.h> +#include <net/tcp.h> +#include <linux/netfilter_ipv4/lockhelp.h> + +#include "regexp/regexp.c" + +#include <linux/netfilter_ipv4/ipt_layer7.h> +#include <linux/netfilter_ipv4/ip_tables.h> + +MODULE_AUTHOR("Matthew Strait <quadong@users.sf.net>, Ethan Sommer <sommere@users.sf.net>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("iptables application layer match module"); + +static int maxdatalen = 2048; // this is the default +MODULE_PARM(maxdatalen,"i"); +MODULE_PARM_DESC(maxdatalen,"maximum bytes of data looked at by l7-filter"); + +#if defined(CONFIG_IP_NF_MATCH_LAYER7_DEBUG) + #define DPRINTK(format,args...) printk(format,##args) +#else + #define DPRINTK(format,args...) +#endif + +#define TOTAL_PACKETS master_conntrack->layer7.numpackets + +/* Number of packets whose data we look at. +This can be modified through /proc/net/layer7_numpackets */ +static int num_packets = 10; + +static struct pattern_cache { + char * regex_string; + regexp * pattern; + struct pattern_cache * next; +} * first_pattern_cache = NULL; + +/* I'm new to locking. Here are my assumptions: + +- No one will write to /proc/net/layer7_numpackets over and over very fast; + if they did, nothing awful would happen. + +- This code will never be processing the same packet twice at the same time, + because iptables rules are traversed in order. + +- It doesn't matter if two packets from different connections are in here at + the same time, because they don't share any data. + +- It _does_ matter if two packets from the same connection are here at the same + time. In this case, we have to protect the conntracks and the list of + compiled patterns. +*/ +DECLARE_RWLOCK(ct_lock); +DECLARE_LOCK(list_lock); + +#if CONFIG_IP_NF_MATCH_LAYER7_DEBUG +/* Converts an unfriendly string into a friendly one by +replacing unprintables with periods and all whitespace with " ". */ +static char * friendly_print(unsigned char * s) +{ + char * f = kmalloc(strlen(s) + 1, GFP_ATOMIC); + int i; + + if(!f) { + if (net_ratelimit()) + printk(KERN_ERR "layer7: out of memory in friendly_print, bailing.\n"); + return NULL; + } + + for(i = 0; i < strlen(s); i++){ + if(isprint(s[i]) && s[i] < 128) f[i] = s[i]; + else if(isspace(s[i])) f[i] = ' '; + else f[i] = '.'; + } + f[i] = '\0'; + return f; +} + +static char dec2hex(int i) +{ + switch (i) { + case 0 ... 9: + return (char)(i + '0'); + break; + case 10 ... 15: + return (char)(i - 10 + 'a'); + break; + default: + if (net_ratelimit()) + printk("Problem in dec2hex\n"); + return '\0'; + } +} + +static char * hex_print(unsigned char * s) +{ + char * g = kmalloc(strlen(s)*3 + 1, GFP_ATOMIC); + int i; + + if(!g) { + if (net_ratelimit()) + printk(KERN_ERR "layer7: out of memory in hex_print, bailing.\n"); + return NULL; + } + + for(i = 0; i < strlen(s); i++) { + g[i*3 ] = dec2hex(s[i]/16); + g[i*3 + 1] = dec2hex(s[i]%16); + g[i*3 + 2] = ' '; + } + g[i*3] = '\0'; + + return g; +} +#endif // DEBUG + +/* Use instead of regcomp. As we expect to be seeing the same regexps over and +over again, it make sense to cache the results. */ +static regexp * compile_and_cache(char * regex_string, char * protocol) +{ + struct pattern_cache * node = first_pattern_cache; + struct pattern_cache * last_pattern_cache = first_pattern_cache; + struct pattern_cache * tmp; + unsigned int len; + + while (node != NULL) { + if (!strcmp(node->regex_string, regex_string)) + return node->pattern; + + last_pattern_cache = node;/* points at the last non-NULL node */ + node = node->next; + } + + /* If we reach the end of the list, then we have not yet cached + the pattern for this regex. Let's do that now. + Be paranoid about running out of memory to avoid list corruption. */ + tmp = kmalloc(sizeof(struct pattern_cache), GFP_ATOMIC); + + if(!tmp) { + if (net_ratelimit()) + printk(KERN_ERR "layer7: out of memory in compile_and_cache, bailing.\n"); + return NULL; + } + + tmp->regex_string = kmalloc(strlen(regex_string) + 1, GFP_ATOMIC); + tmp->pattern = kmalloc(sizeof(struct regexp), GFP_ATOMIC); + tmp->next = NULL; + + if(!tmp->regex_string || !tmp->pattern) { + if (net_ratelimit()) + printk(KERN_ERR "layer7: out of memory in compile_and_cache, bailing.\n"); + kfree(tmp->regex_string); + kfree(tmp->pattern); + kfree(tmp); + return NULL; + } + + /* Ok. The new node is all ready now. */ + node = tmp; + + if(first_pattern_cache == NULL) /* list is empty */ + first_pattern_cache = node; /* make node the beginning */ + else + last_pattern_cache->next = node; /* attach node to the end */ + + /* copy the string and compile the regex */ + len = strlen(regex_string); + DPRINTK("About to compile this: \"%s\"\n", regex_string); + node->pattern = regcomp(regex_string, &len); + if ( !node->pattern ) { + if (net_ratelimit()) + printk(KERN_ERR "layer7: Error compiling regexp \"%s\" (%s)\n", regex_string, protocol); + /* pattern is now cached as NULL, so we won't try again. */ + } + + strcpy(node->regex_string, regex_string); + return node->pattern; +} + +static int can_handle(const struct sk_buff *skb) +{ + if(!skb->nh.iph) /* not IP */ + return 0; + if(skb->nh.iph->protocol != IPPROTO_TCP && + skb->nh.iph->protocol != IPPROTO_UDP && + skb->nh.iph->protocol != IPPROTO_ICMP) + return 0; + return 1; +} + +/* Returns offset the into the skb->data that the application data starts */ +static int app_data_offset(const struct sk_buff *skb) +{ + /* In case we are ported somewhere (ebtables?) where skb->nh.iph + isn't set, this can be gotten from 4*(skb->data[0] & 0x0f) as well. */ + int ip_hl = 4*skb->nh.iph->ihl; + + if( skb->nh.iph->protocol == IPPROTO_TCP ) { + /* 12 == offset into TCP header for the header length field. + Can't get this with skb->h.th->doff because the tcphdr + struct doesn't get set when routing (this is confirmed to be + true in Netfilter as well as QoS.) */ + int tcp_hl = 4*(skb->data[ip_hl + 12] >> 4); + + return ip_hl + tcp_hl; + } else if( skb->nh.iph->protocol == IPPROTO_UDP ) { + return ip_hl + 8; /* UDP header is always 8 bytes */ + } else if( skb->nh.iph->protocol == IPPROTO_ICMP ) { + return ip_hl + 8; /* ICMP header is 8 bytes */ + } else { + if (net_ratelimit()) + printk(KERN_ERR "layer7: tried to handle unknown protocol!\n"); + return ip_hl + 8; /* something reasonable */ + } +} + +/* handles whether there's a match when we aren't appending data anymore */ +static int match_no_append(struct ip_conntrack * conntrack, struct ip_conntrack * master_conntrack, + enum ip_conntrack_info ctinfo, enum ip_conntrack_info master_ctinfo, + struct ipt_layer7_info * info) +{ + /* If we're in here, throw the app data away */ + WRITE_LOCK(&ct_lock); + if(master_conntrack->layer7.app_data != NULL) { + + #ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG + if(!master_conntrack->layer7.app_proto) { + char * f = friendly_print(master_conntrack->layer7.app_data); + char * g = hex_print(master_conntrack->layer7.app_data); + DPRINTK("\nl7-filter gave up after %d bytes (%d packets):\n%s\n", + strlen(f), + TOTAL_PACKETS, f); + kfree(f); + DPRINTK("In hex: %s\n", g); + kfree(g); + } + #endif + + kfree(master_conntrack->layer7.app_data); + master_conntrack->layer7.app_data = NULL; /* don't free again */ + } + WRITE_UNLOCK(&ct_lock); + + if(master_conntrack->layer7.app_proto){ + /* Here child connections set their .app_proto (for /proc/net/ip_conntrack) */ + WRITE_LOCK(&ct_lock); + if(!conntrack->layer7.app_proto) { + conntrack->layer7.app_proto = kmalloc(strlen(master_conntrack->layer7.app_proto)+1, GFP_ATOMIC); + if(!conntrack->layer7.app_proto){ + if (net_ratelimit()) + printk(KERN_ERR "layer7: out of memory in match_no_append, bailing.\n"); + WRITE_UNLOCK(&ct_lock); + return 1; + } + strcpy(conntrack->layer7.app_proto, master_conntrack->layer7.app_proto); + } + WRITE_UNLOCK(&ct_lock); + + return (!strcmp(master_conntrack->layer7.app_proto, info->protocol)); + } + else { + /* If not classified, set to "unknown" to distinguish from + connections that are still being tested. */ + WRITE_LOCK(&ct_lock); + master_conntrack->layer7.app_proto = kmalloc(strlen("unknown")+1, GFP_ATOMIC); + if(!master_conntrack->layer7.app_proto){ + if (net_ratelimit()) + printk(KERN_ERR "layer7: out of memory in match_no_append, bailing.\n"); + WRITE_UNLOCK(&ct_lock); + return 1; + } + strcpy(master_conntrack->layer7.app_proto, "unknown"); + WRITE_UNLOCK(&ct_lock); + return 0; + } +} + +/* add the new app data to the conntrack. Return number of bytes added. */ +static int add_data(struct ip_conntrack * master_conntrack, + char * app_data, int appdatalen) +{ + int length = 0, i; + int oldlength = master_conntrack->layer7.app_data_len; + + /* Strip nulls. Make everything lower case (our regex lib doesn't + do case insensitivity). Add it to the end of the current data. */ + for(i = 0; i < maxdatalen-oldlength-1 && i < appdatalen; i++) { + if(app_data[i] != '\0') { + master_conntrack->layer7.app_data[length+oldlength] = + /* the kernel version of tolower mungs 'upper ascii' */ + isascii(app_data[i])? tolower(app_data[i]) : app_data[i]; + length++; + } + } + + master_conntrack->layer7.app_data[length+oldlength] = '\0'; + master_conntrack->layer7.app_data_len = length + oldlength; + + return length; +} + +/* Returns true on match and false otherwise. */ +static int match(/* const */struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const void *matchinfo, + int offset, int *hotdrop) +{ + struct ipt_layer7_info * info = (struct ipt_layer7_info *)matchinfo; + enum ip_conntrack_info master_ctinfo, ctinfo; + struct ip_conntrack *master_conntrack, *conntrack; + unsigned char * app_data; + unsigned int pattern_result, appdatalen; + regexp * comppattern; + + if(!can_handle(skb)){ + DPRINTK("layer7: This is some protocol I can't handle.\n"); + return info->invert; + } + + /* Treat the parent and all its children together as one connection, + except for the purpose of setting conntrack->layer7.app_proto in the + actual connection. This makes /proc/net/ip_conntrack somewhat more + satisfying. */ + if(!(conntrack = ip_conntrack_get((struct sk_buff *)skb, &ctinfo)) || + !(master_conntrack = ip_conntrack_get((struct sk_buff *)skb, &master_ctinfo))) { + DPRINTK("layer7: packet is not from a known connection, giving up.\n"); + return info->invert; + } + + /* Try to get a master conntrack (and its master etc) for FTP, etc. */ + while (master_ct(master_conntrack) != NULL) + master_conntrack = master_ct(master_conntrack); + + if(!skb->cb[0]){ + WRITE_LOCK(&ct_lock); + master_conntrack->layer7.numpackets++;/*starts at 0 via memset*/ + WRITE_UNLOCK(&ct_lock); + } + + /* if we've classified it or seen too many packets */ + if(TOTAL_PACKETS > num_packets || + master_conntrack->layer7.app_proto) { + + pattern_result = match_no_append(conntrack, master_conntrack, ctinfo, master_ctinfo, info); + + /* skb->cb[0] == seen. Avoid doing things twice if there are two l7 + rules. I'm not sure that using cb for this purpose is correct, although + it says "put your private variables there". But it doesn't look like it + is being used for anything else in the skbs that make it here. How can + I write to cb without making the compiler angry? */ + skb->cb[0] = 1; /* marking it seen here is probably irrelevant, but consistant */ + + return (pattern_result ^ info->invert); + } + + if(skb_is_nonlinear(skb)){ + if(skb_linearize(skb, GFP_ATOMIC) != 0){ + if (net_ratelimit()) + printk(KERN_ERR "layer7: failed to linearize packet, bailing.\n"); + return info->invert; + } + } + + /* now that the skb is linearized, it's safe to set these. */ + app_data = skb->data + app_data_offset(skb); + appdatalen = skb->tail - app_data; + + LOCK_BH(&list_lock); + /* the return value gets checked later, when we're ready to use it */ + comppattern = compile_and_cache(info->pattern, info->protocol); + UNLOCK_BH(&list_lock); + + /* On the first packet of a connection, allocate space for app data */ + WRITE_LOCK(&ct_lock); + if(TOTAL_PACKETS == 1 && !skb->cb[0] && !master_conntrack->layer7.app_data) { + master_conntrack->layer7.app_data = kmalloc(maxdatalen, GFP_ATOMIC); + if(!master_conntrack->layer7.app_data){ + if (net_ratelimit()) + printk(KERN_ERR "layer7: out of memory in match, bailing.\n"); + WRITE_UNLOCK(&ct_lock); + return info->invert; + } + + master_conntrack->layer7.app_data[0] = '\0'; + } + WRITE_UNLOCK(&ct_lock); + + /* Can be here, but unallocated, if numpackets is increased near + the beginning of a connection */ + if(master_conntrack->layer7.app_data == NULL) + return (info->invert); /* unmatched */ + + if(!skb->cb[0]){ + int newbytes; + WRITE_LOCK(&ct_lock); + newbytes = add_data(master_conntrack, app_data, appdatalen); + WRITE_UNLOCK(&ct_lock); + + if(newbytes == 0) { /* didn't add any data */ + skb->cb[0] = 1; + /* Didn't match before, not going to match now */ + return info->invert; + } + } + + /* If looking for "unknown", then never match. "Unknown" means that + we've given up; we're still trying with these packets. */ + if(!strcmp(info->protocol, "unknown")) { + pattern_result = 0; + /* If the regexp failed to compile, don't bother running it */ + } else if(comppattern && regexec(comppattern, master_conntrack->layer7.app_data)) { + DPRINTK("layer7: regexec positive: %s!\n", info->protocol); + pattern_result = 1; + } else pattern_result = 0; + + if(pattern_result) { + WRITE_LOCK(&ct_lock); + master_conntrack->layer7.app_proto = kmalloc(strlen(info->protocol)+1, GFP_ATOMIC); + if(!master_conntrack->layer7.app_proto){ + if (net_ratelimit()) + printk(KERN_ERR "layer7: out of memory in match, bailing.\n"); + WRITE_UNLOCK(&ct_lock); + return (pattern_result ^ info->invert); + } + strcpy(master_conntrack->layer7.app_proto, info->protocol); + WRITE_UNLOCK(&ct_lock); + } + + /* mark the packet seen */ + skb->cb[0] = 1; + + return (pattern_result ^ info->invert); +} + +static int checkentry(const char *tablename, const struct ipt_ip *ip, + void *matchinfo, unsigned int matchsize, unsigned int hook_mask) +{ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_layer7_info))) + return 0; + return 1; +} + +static struct ipt_match layer7_match = { + .name = "layer7", + .match = &match, + .checkentry = &checkentry, + .me = THIS_MODULE +}; + +/* taken from drivers/video/modedb.c */ +static int my_atoi(const char *s) +{ + int val = 0; + + for (;; s++) { + switch (*s) { + case '0'...'9': + val = 10*val+(*s-'0'); + break; + default: + return val; + } + } +} + +/* write out num_packets to userland. */ +static int layer7_read_proc(char* page, char ** start, off_t off, int count, + int* eof, void * data) +{ + if(num_packets > 99 && net_ratelimit()) + printk(KERN_ERR "layer7: NOT REACHED. num_packets too big\n"); + + page[0] = num_packets/10 + '0'; + page[1] = num_packets%10 + '0'; + page[2] = '\n'; + page[3] = '\0'; + + *eof=1; + + return 3; +} + +/* Read in num_packets from userland */ +static int layer7_write_proc(struct file* file, const char* buffer, + unsigned long count, void *data) +{ + char * foo = kmalloc(count, GFP_ATOMIC); + + if(!foo){ + if (net_ratelimit()) + printk(KERN_ERR "layer7: out of memory, bailing. num_packets unchanged.\n"); + return count; + } + + copy_from_user(foo, buffer, count); + + num_packets = my_atoi(foo); + kfree (foo); + + /* This has an arbitrary limit to make the math easier. I'm lazy. + But anyway, 99 is a LOT! If you want more, you're doing it wrong! */ + if(num_packets > 99) { + printk(KERN_WARNING "layer7: num_packets can't be > 99.\n"); + num_packets = 99; + } else if(num_packets < 1) { + printk(KERN_WARNING "layer7: num_packets can't be < 1.\n"); + num_packets = 1; + } + + return count; +} + +/* register the proc file */ +static void layer7_init_proc(void) +{ + struct proc_dir_entry* entry; + entry = create_proc_entry("layer7_numpackets", 0644, proc_net); + entry->read_proc = layer7_read_proc; + entry->write_proc = layer7_write_proc; +} + +static void layer7_cleanup_proc(void) +{ + remove_proc_entry("layer7_numpackets", proc_net); +} + +static int __init init(void) +{ + layer7_init_proc(); + if(maxdatalen < 1) { + printk(KERN_WARNING "layer7: maxdatalen can't be < 1, using 1\n"); + maxdatalen = 1; + } + /* This is not a hard limit. It's just here to prevent people from + bringing their slow machines to a grinding halt. */ + else if(maxdatalen > 65536) { + printk(KERN_WARNING "layer7: maxdatalen can't be > 65536, using 65536\n"); + maxdatalen = 65536; + } + return ipt_register_match(&layer7_match); +} + +static void __exit fini(void) +{ + layer7_cleanup_proc(); + ipt_unregister_match(&layer7_match); +} + +module_init(init); +module_exit(fini); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_mac.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_mac.c index b320e29b..d0475155 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ipt_mac.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_mac.c @@ -19,7 +19,8 @@ match(const struct sk_buff *skb, const struct ipt_mac_info *info = matchinfo; /* Is mac pointer valid? */ - return (skb->mac.raw >= skb->head + return (in != NULL // added for OUTPUT experiment -- zzz + && skb->mac.raw >= skb->head && (skb->mac.raw + ETH_HLEN) <= skb->data /* If so, compare... */ && ((memcmp(skb->mac.ethernet->h_source, info->srcaddr, ETH_ALEN) @@ -33,6 +34,7 @@ ipt_mac_checkentry(const char *tablename, unsigned int matchsize, unsigned int hook_mask) { +#if 0 // removed for OUTPUT experiment --jz /* FORWARD isn't always valid, but it's nice to be able to do --RR */ if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) @@ -40,7 +42,7 @@ ipt_mac_checkentry(const char *tablename, printk("ipt_mac: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n"); return 0; } - +#endif if (matchsize != IPT_ALIGN(sizeof(struct ipt_mac_info))) return 0; diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_macsave.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_macsave.c new file mode 100644 index 00000000..25fa26a4 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_macsave.c @@ -0,0 +1,62 @@ +/* + + macsave match + Copyright (C) 2006 Jonathan Zarate + + Licensed under GNU GPL v2 or later. + +*/ + +#include <linux/module.h> +#include <linux/skbuff.h> +#include <net/sock.h> + +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ip_conntrack.h> +#include <linux/netfilter_ipv4/ipt_macsave.h> + +#define DEBUG 1 + +#ifdef DEBUG +#define DLOG printk +#else +#define DLOG(...) do { } while (0); +#endif + + +static int match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, + const void *matchinfo, int offset, const void *hdr, u_int16_t datalen, int *hotdrop) +{ + const struct ipt_macsave_match_info *info = matchinfo; + struct ip_conntrack *ct; + enum ip_conntrack_info ctinfo; + + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); // note about cast: ip_conntrack_get() will not modify skb + if (ct) return (memcmp(ct->macsave, info->mac, sizeof(ct->macsave)) == 0) ^ info->invert; + return info->invert; +} + +static int checkentry(const char *tablename, const struct ipt_ip *ip, void *matchinfo, + unsigned int matchsize, unsigned int hook_mask) +{ + return (matchsize == IPT_ALIGN(sizeof(struct ipt_macsave_match_info))); +} + + +static struct ipt_match macsave_match += { { NULL, NULL }, "macsave", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + DLOG(KERN_INFO "macsave match init " __DATE__ " " __TIME__ "\n"); + return ipt_register_match(&macsave_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&macsave_match); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_mport.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_mport.c index ca99b764..836d3f2f 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ipt_mport.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_mport.c @@ -10,7 +10,11 @@ MODULE_LICENSE("GPL"); +#if 0 +#define duprintf(format, args...) printk(format , ## args) +#else #define duprintf(format, args...) +#endif /* Returns 1 if the port is matched by the test, 0 otherwise. */ static inline int diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_quota.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_quota.c new file mode 100644 index 00000000..d7ab39cf --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_quota.c @@ -0,0 +1,88 @@ +/* + * netfilter module to enforce network quotas + * + * Sam Johnston <samj@samj.net> + * + * 30/01/05: Fixed on SMP --Pablo Neira <pablo@eurodev.net> + */ +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> + +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ipt_quota.h> + +MODULE_LICENSE("GPL"); + +static spinlock_t quota_lock = SPIN_LOCK_UNLOCKED; + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, const void *hdr, u_int16_t datalen, int *hotdrop) +{ + struct ipt_quota_info *q = + ((struct ipt_quota_info *) matchinfo)->master; + + spin_lock_bh("a_lock); + + if (q->quota >= datalen) { + /* we can afford this one */ + q->quota -= datalen; + spin_unlock_bh("a_lock); + +#ifdef DEBUG_IPT_QUOTA + printk("IPT Quota OK: %llu datlen %d \n", q->quota, datalen); +#endif + return 1; + } + + /* so we do not allow even small packets from now on */ + q->quota = 0; + +#ifdef DEBUG_IPT_QUOTA + printk("IPT Quota Failed: %llu datlen %d \n", q->quota, datalen); +#endif + + spin_unlock_bh("a_lock); + return 0; +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, unsigned int matchsize, unsigned int hook_mask) +{ + /* TODO: spinlocks? sanity checks? */ + struct ipt_quota_info *q = (struct ipt_quota_info *) matchinfo; + + if (matchsize != IPT_ALIGN(sizeof (struct ipt_quota_info))) + return 0; + + /* For SMP, we only want to use one set of counters. */ + q->master = q; + + return 1; +} + +static struct ipt_match quota_match + = { {NULL, NULL}, "quota", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init +init(void) +{ + return ipt_register_match("a_match); +} + +static void __exit +fini(void) +{ + ipt_unregister_match("a_match); +} + +module_init(init); +module_exit(fini); + diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_recent.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_recent.c new file mode 100644 index 00000000..808ae78f --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_recent.c @@ -0,0 +1,998 @@ +/* Kernel module to check if the source address has been seen recently. */ +/* Copyright 2002-2003, Stephen Frost */ +/* Author: Stephen Frost <sfrost@snowman.net> */ +/* Project Page: http://snowman.net/projects/ipt_recent/ */ +/* This software is distributed under the terms of the GPL, Version 2 */ +/* This copyright does not cover user programs that use kernel services + * by normal system calls. */ + +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/proc_fs.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <asm/uaccess.h> +#include <linux/ctype.h> +#include <linux/ip.h> +#include <linux/vmalloc.h> + +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ipt_recent.h> + +#undef DEBUG +#define HASH_LOG 9 + +/* Defaults, these can be overridden on the module command-line. */ +static int ip_list_tot = 100; +static int ip_pkt_list_tot = 20; +static int ip_list_hash_size = 0; +static int ip_list_perms = 0644; +#ifdef DEBUG +static int debug = 1; +#endif + +static char version[] = +KERN_INFO RECENT_NAME " " RECENT_VER ": Stephen Frost <sfrost@snowman.net>. http://snowman.net/projects/ipt_recent/\n"; + +MODULE_AUTHOR("Stephen Frost <sfrost@snowman.net>"); +MODULE_DESCRIPTION("IP tables recently seen matching module " RECENT_VER); +MODULE_LICENSE("GPL"); +MODULE_PARM(ip_list_tot,"i"); +MODULE_PARM(ip_pkt_list_tot,"i"); +MODULE_PARM(ip_list_hash_size,"i"); +MODULE_PARM(ip_list_perms,"i"); +#ifdef DEBUG +MODULE_PARM(debug,"i"); +MODULE_PARM_DESC(debug,"debugging level, defaults to 1"); +#endif +MODULE_PARM_DESC(ip_list_tot,"number of IPs to remember per list"); +MODULE_PARM_DESC(ip_pkt_list_tot,"number of packets per IP to remember"); +MODULE_PARM_DESC(ip_list_hash_size,"size of hash table used to look up IPs"); +MODULE_PARM_DESC(ip_list_perms,"permissions on /proc/net/ipt_recent/* files"); + +/* Structure of our list of recently seen addresses. */ +struct recent_ip_list { + u_int32_t addr; + u_int8_t ttl; + u_int32_t last_seen; + u_int32_t *last_pkts; + u_int32_t oldest_pkt; + u_int32_t hash_entry; + u_int32_t time_pos; +}; + +struct time_info_list { + u_int32_t position; + u_int32_t time; +}; + +/* Structure of our linked list of tables of recent lists. */ +struct recent_ip_tables { + char name[IPT_RECENT_NAME_LEN]; + int count; + int time_pos; + struct recent_ip_list *table; + struct recent_ip_tables *next; + spinlock_t list_lock; + int *hash_table; + struct time_info_list *time_info; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *status_proc; +#endif /* CONFIG_PROC_FS */ +}; + +/* Our current list of addresses we have recently seen. + * Only added to on a --set, and only updated on --set || --update + */ +static struct recent_ip_tables *r_tables = NULL; + +/* We protect r_list with this spinlock so two processors are not modifying + * the list at the same time. + */ +static spinlock_t recent_lock = SPIN_LOCK_UNLOCKED; + +/* Our /proc/net/ipt_recent entry */ +static struct proc_dir_entry *proc_net_ipt_recent = NULL; + +/* Function declaration for later. */ +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop); + +/* Function to hash a given address into the hash table of table_size size */ +int hash_func(unsigned int addr, int table_size) +{ + int result = 0; + unsigned int value = addr; + do { result ^= value; } while((value >>= HASH_LOG)); + +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": %d = hash_func(%u,%d)\n", + result & (table_size - 1), + addr, + table_size); +#endif + + return(result & (table_size - 1)); +} + +#ifdef CONFIG_PROC_FS +/* This is the function which produces the output for our /proc output + * interface which lists each IP address, the last seen time and the + * other recent times the address was seen. + */ + +static int ip_recent_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) +{ + int len = 0, count, last_len = 0, pkt_count; + off_t pos = 0; + off_t begin = 0; + struct recent_ip_tables *curr_table; + + curr_table = (struct recent_ip_tables*) data; + + spin_lock_bh(&curr_table->list_lock); + for(count = 0; count < ip_list_tot; count++) { + if(!curr_table->table[count].addr) continue; + last_len = len; + len += sprintf(buffer+len,"src=%u.%u.%u.%u ",NIPQUAD(curr_table->table[count].addr)); + len += sprintf(buffer+len,"ttl: %u ",curr_table->table[count].ttl); + len += sprintf(buffer+len,"last_seen: %u ",curr_table->table[count].last_seen); + len += sprintf(buffer+len,"oldest_pkt: %u ",curr_table->table[count].oldest_pkt); + len += sprintf(buffer+len,"last_pkts: %u",curr_table->table[count].last_pkts[0]); + for(pkt_count = 1; pkt_count < ip_pkt_list_tot; pkt_count++) { + if(!curr_table->table[count].last_pkts[pkt_count]) break; + len += sprintf(buffer+len,", %u",curr_table->table[count].last_pkts[pkt_count]); + } + len += sprintf(buffer+len,"\n"); + pos = begin + len; + if(pos < offset) { len = 0; begin = pos; } + if(pos > offset + length) { len = last_len; break; } + } + + *start = buffer + (offset - begin); + len -= (offset - begin); + if(len > length) len = length; + + spin_unlock_bh(&curr_table->list_lock); + return len; +} + +/* ip_recent_ctrl provides an interface for users to modify the table + * directly. This allows adding entries, removing entries, and + * flushing the entire table. + * This is done by opening up the appropriate table for writing and + * sending one of: + * xx.xx.xx.xx -- Add entry to table with current time + * +xx.xx.xx.xx -- Add entry to table with current time + * -xx.xx.xx.xx -- Remove entry from table + * clear -- Flush table, remove all entries + */ + +static int ip_recent_ctrl(struct file *file, const char *input, unsigned long size, void *data) +{ + static const u_int32_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff }; + u_int32_t val; + int base, used = 0; + char c, *cp; + union iaddr { + uint8_t bytes[4]; + uint32_t word; + } res; + uint8_t *pp = res.bytes; + int digit; + + char buffer[20]; + int len, check_set = 0, count; + u_int32_t addr = 0; + struct sk_buff *skb; + struct ipt_recent_info *info; + struct recent_ip_tables *curr_table; + + curr_table = (struct recent_ip_tables*) data; + + if(size > 20) len = 20; else len = size; + + if(copy_from_user(buffer,input,len)) return -EFAULT; + + if(len < 20) buffer[len] = '\0'; + +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": ip_recent_ctrl len: %d, input: `%.20s'\n",len,buffer); +#endif + + cp = buffer; + while(isspace(*cp)) { cp++; used++; if(used >= len-5) return used; } + + /* Check if we are asked to flush the entire table */ + if(!memcmp(cp,"clear",5)) { + used += 5; + spin_lock_bh(&curr_table->list_lock); + curr_table->time_pos = 0; + for(count = 0; count < ip_list_hash_size; count++) { + curr_table->hash_table[count] = -1; + } + for(count = 0; count < ip_list_tot; count++) { + curr_table->table[count].last_seen = 0; + curr_table->table[count].addr = 0; + curr_table->table[count].ttl = 0; + memset(curr_table->table[count].last_pkts,0,ip_pkt_list_tot*sizeof(u_int32_t)); + curr_table->table[count].oldest_pkt = 0; + curr_table->table[count].time_pos = 0; + curr_table->time_info[count].position = count; + curr_table->time_info[count].time = 0; + } + spin_unlock_bh(&curr_table->list_lock); + return used; + } + + check_set = IPT_RECENT_SET; + switch(*cp) { + case '+': check_set = IPT_RECENT_SET; cp++; used++; break; + case '-': check_set = IPT_RECENT_REMOVE; cp++; used++; break; + default: if(!isdigit(*cp)) return (used+1); break; + } + +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": ip_recent_ctrl cp: `%c', check_set: %d\n",*cp,check_set); +#endif + /* Get addr (effectively inet_aton()) */ + /* Shamelessly stolen from libc, a function in the kernel for doing + * this would, of course, be greatly preferred, but our options appear + * to be rather limited, so we will just do it ourselves here. + */ + res.word = 0; + + c = *cp; + for(;;) { + if(!isdigit(c)) return used; + val = 0; base = 10; digit = 0; + if(c == '0') { + c = *++cp; + if(c == 'x' || c == 'X') base = 16, c = *++cp; + else { base = 8; digit = 1; } + } + for(;;) { + if(isascii(c) && isdigit(c)) { + if(base == 8 && (c == '8' || c == '0')) return used; + val = (val * base) + (c - '0'); + c = *++cp; + digit = 1; + } else if(base == 16 && isascii(c) && isxdigit(c)) { + val = (val << 4) | (c + 10 - (islower(c) ? 'a' : 'A')); + c = *++cp; + digit = 1; + } else break; + } + if(c == '.') { + if(pp > res.bytes + 2 || val > 0xff) return used; + *pp++ = val; + c = *++cp; + } else break; + } + used = cp - buffer; + if(c != '\0' && (!isascii(c) || !isspace(c))) return used; + if(c == '\n') used++; + if(!digit) return used; + + if(val > max[pp - res.bytes]) return used; + addr = res.word | htonl(val); + + if(!addr && check_set == IPT_RECENT_SET) return used; + +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": ip_recent_ctrl c: %c, addr: %u used: %d\n",c,addr,used); +#endif + + /* Set up and just call match */ + info = kmalloc(sizeof(struct ipt_recent_info),GFP_KERNEL); + if(!info) { return -ENOMEM; } + info->seconds = 0; + info->hit_count = 0; + info->check_set = check_set; + info->invert = 0; + info->side = IPT_RECENT_SOURCE; + strncpy(info->name,curr_table->name,IPT_RECENT_NAME_LEN); + info->name[IPT_RECENT_NAME_LEN-1] = '\0'; + + skb = kmalloc(sizeof(struct sk_buff),GFP_KERNEL); + if (!skb) { + used = -ENOMEM; + goto out_free_info; + } + skb->nh.iph = kmalloc(sizeof(struct iphdr),GFP_KERNEL); + if (!skb->nh.iph) { + used = -ENOMEM; + goto out_free_skb; + } + + skb->nh.iph->saddr = addr; + skb->nh.iph->daddr = 0; + /* Clear ttl since we have no way of knowing it */ + skb->nh.iph->ttl = 0; + match(skb,NULL,NULL,info,0,NULL,sizeof(struct ipt_recent_info),NULL); + + kfree(skb->nh.iph); +out_free_skb: + kfree(skb); +out_free_info: + kfree(info); + +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": Leaving ip_recent_ctrl addr: %u used: %d\n",addr,used); +#endif + return used; +} + +#endif /* CONFIG_PROC_FS */ + +/* 'match' is our primary function, called by the kernel whenever a rule is + * hit with our module as an option to it. + * What this function does depends on what was specifically asked of it by + * the user: + * --set -- Add or update last seen time of the source address of the packet + * -- matchinfo->check_set == IPT_RECENT_SET + * --rcheck -- Just check if the source address is in the list + * -- matchinfo->check_set == IPT_RECENT_CHECK + * --update -- If the source address is in the list, update last_seen + * -- matchinfo->check_set == IPT_RECENT_UPDATE + * --remove -- If the source address is in the list, remove it + * -- matchinfo->check_set == IPT_RECENT_REMOVE + * --seconds -- Option to --rcheck/--update, only match if last_seen within seconds + * -- matchinfo->seconds + * --hitcount -- Option to --rcheck/--update, only match if seen hitcount times + * -- matchinfo->hit_count + * --seconds and --hitcount can be combined + */ +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + int pkt_count, hits_found, ans; + unsigned long now; + const struct ipt_recent_info *info = matchinfo; + u_int32_t addr = 0, time_temp; + u_int8_t ttl = skb->nh.iph->ttl; + int *hash_table; + int orig_hash_result, hash_result, temp, location = 0, time_loc, end_collision_chain = -1; + struct time_info_list *time_info; + struct recent_ip_tables *curr_table; + struct recent_ip_tables *last_table; + struct recent_ip_list *r_list; + +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": match() called\n"); +#endif + + /* Default is false ^ info->invert */ + ans = info->invert; + +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": match(): name = '%s'\n",info->name); +#endif + + /* if out != NULL then routing has been done and TTL changed. + * We change it back here internally for match what came in before routing. */ + if(out) ttl++; + + /* Find the right table */ + spin_lock_bh(&recent_lock); + curr_table = r_tables; + while( (last_table = curr_table) && strncmp(info->name,curr_table->name,IPT_RECENT_NAME_LEN) && (curr_table = curr_table->next) ); + +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": match(): table found('%s')\n",info->name); +#endif + + spin_unlock_bh(&recent_lock); + + /* Table with this name not found, match impossible */ + if(!curr_table) { return ans; } + + /* Make sure no one is changing the list while we work with it */ + spin_lock_bh(&curr_table->list_lock); + + r_list = curr_table->table; + if(info->side == IPT_RECENT_DEST) addr = skb->nh.iph->daddr; else addr = skb->nh.iph->saddr; + + if(!addr) { +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": match() address (%u) invalid, leaving.\n",addr); +#endif + spin_unlock_bh(&curr_table->list_lock); + return ans; + } + +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": match(): checking table, addr: %u, ttl: %u, orig_ttl: %u\n",addr,ttl,skb->nh.iph->ttl); +#endif + + /* Get jiffies now in case they changed while we were waiting for a lock */ + now = jiffies; + hash_table = curr_table->hash_table; + time_info = curr_table->time_info; + + orig_hash_result = hash_result = hash_func(addr,ip_list_hash_size); + /* Hash entry at this result used */ + /* Check for TTL match if requested. If TTL is zero then a match would never + * happen, so match regardless of existing TTL in that case. Zero means the + * entry was added via the /proc interface anyway, so we will just use the + * first TTL we get for that IP address. */ + if(info->check_set & IPT_RECENT_TTL) { + while(hash_table[hash_result] != -1 && !(r_list[hash_table[hash_result]].addr == addr && + (!r_list[hash_table[hash_result]].ttl || r_list[hash_table[hash_result]].ttl == ttl))) { + /* Collision in hash table */ + hash_result = (hash_result + 1) % ip_list_hash_size; + } + } else { + while(hash_table[hash_result] != -1 && r_list[hash_table[hash_result]].addr != addr) { + /* Collision in hash table */ + hash_result = (hash_result + 1) % ip_list_hash_size; + } + } + + if(hash_table[hash_result] == -1 && !(info->check_set & IPT_RECENT_SET)) { + /* IP not in list and not asked to SET */ + spin_unlock_bh(&curr_table->list_lock); + return ans; + } + + /* Check if we need to handle the collision, do not need to on REMOVE */ + if(orig_hash_result != hash_result && !(info->check_set & IPT_RECENT_REMOVE)) { +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": match(): Collision in hash table. (or: %d,hr: %d,oa: %u,ha: %u)\n", + orig_hash_result, + hash_result, + r_list[hash_table[orig_hash_result]].addr, + addr); +#endif + + /* We had a collision. + * orig_hash_result is where we started, hash_result is where we ended up. + * So, swap them because we are likely to see the same guy again sooner */ +#ifdef DEBUG + if(debug) { + printk(KERN_INFO RECENT_NAME ": match(): Collision; hash_table[orig_hash_result] = %d\n",hash_table[orig_hash_result]); + printk(KERN_INFO RECENT_NAME ": match(): Collision; r_list[hash_table[orig_hash_result]].hash_entry = %d\n", + r_list[hash_table[orig_hash_result]].hash_entry); + } +#endif + + r_list[hash_table[orig_hash_result]].hash_entry = hash_result; + + + temp = hash_table[orig_hash_result]; +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": match(): Collision; hash_table[hash_result] = %d\n",hash_table[hash_result]); +#endif + hash_table[orig_hash_result] = hash_table[hash_result]; + hash_table[hash_result] = temp; + temp = hash_result; + hash_result = orig_hash_result; + orig_hash_result = temp; + time_info[r_list[hash_table[orig_hash_result]].time_pos].position = hash_table[orig_hash_result]; + if(hash_table[hash_result] != -1) { + r_list[hash_table[hash_result]].hash_entry = hash_result; + time_info[r_list[hash_table[hash_result]].time_pos].position = hash_table[hash_result]; + } + +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": match(): Collision handled.\n"); +#endif + } + + if(hash_table[hash_result] == -1) { +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": match(): New table entry. (hr: %d,ha: %u)\n", + hash_result, addr); +#endif + + /* New item found and IPT_RECENT_SET, so we need to add it */ + location = time_info[curr_table->time_pos].position; + hash_table[r_list[location].hash_entry] = -1; + hash_table[hash_result] = location; + memset(r_list[location].last_pkts,0,ip_pkt_list_tot*sizeof(u_int32_t)); + r_list[location].time_pos = curr_table->time_pos; + r_list[location].addr = addr; + r_list[location].ttl = ttl; + r_list[location].last_seen = now; + r_list[location].oldest_pkt = 1; + r_list[location].last_pkts[0] = now; + r_list[location].hash_entry = hash_result; + time_info[curr_table->time_pos].time = r_list[location].last_seen; + curr_table->time_pos = (curr_table->time_pos + 1) % ip_list_tot; + + ans = !info->invert; + } else { +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": match(): Existing table entry. (hr: %d,ha: %u)\n", + hash_result, + addr); +#endif + + /* Existing item found */ + location = hash_table[hash_result]; + /* We have a match on address, now to make sure it meets all requirements for a + * full match. */ + if(info->check_set & IPT_RECENT_CHECK || info->check_set & IPT_RECENT_UPDATE) { + if(!info->seconds && !info->hit_count) ans = !info->invert; else ans = info->invert; + if(info->seconds && !info->hit_count) { + if(time_before_eq(now,r_list[location].last_seen+info->seconds*HZ)) ans = !info->invert; else ans = info->invert; + } + if(info->seconds && info->hit_count) { + for(pkt_count = 0, hits_found = 0; pkt_count < ip_pkt_list_tot; pkt_count++) { + if(time_before_eq(now,r_list[location].last_pkts[pkt_count]+info->seconds*HZ)) hits_found++; + } + if(hits_found >= info->hit_count) ans = !info->invert; else ans = info->invert; + } + if(info->hit_count && !info->seconds) { + for(pkt_count = 0, hits_found = 0; pkt_count < ip_pkt_list_tot; pkt_count++) { + if(r_list[location].last_pkts[pkt_count] == 0) break; + hits_found++; + } + if(hits_found >= info->hit_count) ans = !info->invert; else ans = info->invert; + } + } +#ifdef DEBUG + if(debug) { + if(ans) + printk(KERN_INFO RECENT_NAME ": match(): match addr: %u\n",addr); + else + printk(KERN_INFO RECENT_NAME ": match(): no match addr: %u\n",addr); + } +#endif + + /* If and only if we have been asked to SET, or to UPDATE (on match) do we add the + * current timestamp to the last_seen. */ + if((info->check_set & IPT_RECENT_SET && (ans = !info->invert)) || (info->check_set & IPT_RECENT_UPDATE && ans)) { +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": match(): SET or UPDATE; updating time info.\n"); +#endif + /* Have to update our time info */ + time_loc = r_list[location].time_pos; + time_info[time_loc].time = now; + time_info[time_loc].position = location; + while((time_info[(time_loc+1) % ip_list_tot].time < time_info[time_loc].time) && ((time_loc+1) % ip_list_tot) != curr_table->time_pos) { + time_temp = time_info[time_loc].time; + time_info[time_loc].time = time_info[(time_loc+1)%ip_list_tot].time; + time_info[(time_loc+1)%ip_list_tot].time = time_temp; + time_temp = time_info[time_loc].position; + time_info[time_loc].position = time_info[(time_loc+1)%ip_list_tot].position; + time_info[(time_loc+1)%ip_list_tot].position = time_temp; + r_list[time_info[time_loc].position].time_pos = time_loc; + r_list[time_info[(time_loc+1)%ip_list_tot].position].time_pos = (time_loc+1)%ip_list_tot; + time_loc = (time_loc+1) % ip_list_tot; + } + r_list[location].time_pos = time_loc; + r_list[location].ttl = ttl; + r_list[location].last_pkts[r_list[location].oldest_pkt] = now; + r_list[location].oldest_pkt = ++r_list[location].oldest_pkt % ip_pkt_list_tot; + r_list[location].last_seen = now; + } + /* If we have been asked to remove the entry from the list, just set it to 0 */ + if(info->check_set & IPT_RECENT_REMOVE) { +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": match(): REMOVE; clearing entry (or: %d, hr: %d).\n",orig_hash_result,hash_result); +#endif + /* Check if this is part of a collision chain */ + while(hash_table[(orig_hash_result+1) % ip_list_hash_size] != -1) { + orig_hash_result++; + if(hash_func(r_list[hash_table[orig_hash_result]].addr,ip_list_hash_size) == hash_result) { + /* Found collision chain, how deep does this rabbit hole go? */ +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": match(): REMOVE; found collision chain.\n"); +#endif + end_collision_chain = orig_hash_result; + } + } + if(end_collision_chain != -1) { +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": match(): REMOVE; part of collision chain, moving to end.\n"); +#endif + /* Part of a collision chain, swap it with the end of the chain + * before removing. */ + r_list[hash_table[end_collision_chain]].hash_entry = hash_result; + temp = hash_table[end_collision_chain]; + hash_table[end_collision_chain] = hash_table[hash_result]; + hash_table[hash_result] = temp; + time_info[r_list[hash_table[hash_result]].time_pos].position = hash_table[hash_result]; + hash_result = end_collision_chain; + r_list[hash_table[hash_result]].hash_entry = hash_result; + time_info[r_list[hash_table[hash_result]].time_pos].position = hash_table[hash_result]; + } + location = hash_table[hash_result]; + hash_table[r_list[location].hash_entry] = -1; + time_loc = r_list[location].time_pos; + time_info[time_loc].time = 0; + time_info[time_loc].position = location; + while((time_info[(time_loc+1) % ip_list_tot].time < time_info[time_loc].time) && ((time_loc+1) % ip_list_tot) != curr_table->time_pos) { + time_temp = time_info[time_loc].time; + time_info[time_loc].time = time_info[(time_loc+1)%ip_list_tot].time; + time_info[(time_loc+1)%ip_list_tot].time = time_temp; + time_temp = time_info[time_loc].position; + time_info[time_loc].position = time_info[(time_loc+1)%ip_list_tot].position; + time_info[(time_loc+1)%ip_list_tot].position = time_temp; + r_list[time_info[time_loc].position].time_pos = time_loc; + r_list[time_info[(time_loc+1)%ip_list_tot].position].time_pos = (time_loc+1)%ip_list_tot; + time_loc = (time_loc+1) % ip_list_tot; + } + r_list[location].time_pos = time_loc; + r_list[location].last_seen = 0; + r_list[location].addr = 0; + r_list[location].ttl = 0; + memset(r_list[location].last_pkts,0,ip_pkt_list_tot*sizeof(u_int32_t)); + r_list[location].oldest_pkt = 0; + ans = !info->invert; + } + spin_unlock_bh(&curr_table->list_lock); + return ans; + } + + spin_unlock_bh(&curr_table->list_lock); +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": match() left.\n"); +#endif + return ans; +} + +/* This function is to verify that the rule given during the userspace iptables + * command is correct. + * If the command is valid then we check if the table name referred to by the + * rule exists, if not it is created. + */ +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + int flag = 0, c; + u_int32_t *hold; + const struct ipt_recent_info *info = matchinfo; + struct recent_ip_tables *curr_table, *find_table, *last_table; + +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() entered.\n"); +#endif + + if (matchsize != IPT_ALIGN(sizeof(struct ipt_recent_info))) return 0; + + /* seconds and hit_count only valid for CHECK/UPDATE */ + if(info->check_set & IPT_RECENT_SET) { flag++; if(info->seconds || info->hit_count) return 0; } + if(info->check_set & IPT_RECENT_REMOVE) { flag++; if(info->seconds || info->hit_count) return 0; } + if(info->check_set & IPT_RECENT_CHECK) flag++; + if(info->check_set & IPT_RECENT_UPDATE) flag++; + + /* One and only one of these should ever be set */ + if(flag != 1) return 0; + + /* Name must be set to something */ + if(!info->name || !info->name[0]) return 0; + + /* Things look good, create a list for this if it does not exist */ + /* Lock the linked list while we play with it */ + spin_lock_bh(&recent_lock); + + /* Look for an entry with this name already created */ + /* Finds the end of the list and the entry before the end if current name does not exist */ + find_table = r_tables; + while( (last_table = find_table) && strncmp(info->name,find_table->name,IPT_RECENT_NAME_LEN) && (find_table = find_table->next) ); + + /* If a table already exists just increment the count on that table and return */ + if(find_table) { +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: table found (%s), incrementing count.\n",info->name); +#endif + find_table->count++; + spin_unlock_bh(&recent_lock); + return 1; + } + + spin_unlock_bh(&recent_lock); + + /* Table with this name not found */ + /* Allocate memory for new linked list item */ + +#ifdef DEBUG + if(debug) { + printk(KERN_INFO RECENT_NAME ": checkentry: no table found (%s)\n",info->name); + printk(KERN_INFO RECENT_NAME ": checkentry: Allocationg %d for link-list entry.\n",sizeof(struct recent_ip_tables)); + } +#endif + + curr_table = vmalloc(sizeof(struct recent_ip_tables)); + if(curr_table == NULL) return -ENOMEM; + + curr_table->list_lock = SPIN_LOCK_UNLOCKED; + curr_table->next = NULL; + curr_table->count = 1; + curr_table->time_pos = 0; + strncpy(curr_table->name,info->name,IPT_RECENT_NAME_LEN); + curr_table->name[IPT_RECENT_NAME_LEN-1] = '\0'; + + /* Allocate memory for this table and the list of packets in each entry. */ +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: Allocating %d for table (%s).\n", + sizeof(struct recent_ip_list)*ip_list_tot, + info->name); +#endif + + curr_table->table = vmalloc(sizeof(struct recent_ip_list)*ip_list_tot); + if(curr_table->table == NULL) { vfree(curr_table); return -ENOMEM; } + memset(curr_table->table,0,sizeof(struct recent_ip_list)*ip_list_tot); +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: Allocating %d for pkt_list.\n", + sizeof(u_int32_t)*ip_pkt_list_tot*ip_list_tot); +#endif + + hold = vmalloc(sizeof(u_int32_t)*ip_pkt_list_tot*ip_list_tot); +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: After pkt_list allocation.\n"); +#endif + if(hold == NULL) { + printk(KERN_INFO RECENT_NAME ": checkentry: unable to allocate for pkt_list.\n"); + vfree(curr_table->table); + vfree(curr_table); + return -ENOMEM; + } + for(c = 0; c < ip_list_tot; c++) { + curr_table->table[c].last_pkts = hold + c*ip_pkt_list_tot; + } + + /* Allocate memory for the hash table */ +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: Allocating %d for hash_table.\n", + sizeof(int)*ip_list_hash_size); +#endif + + curr_table->hash_table = vmalloc(sizeof(int)*ip_list_hash_size); + if(!curr_table->hash_table) { + printk(KERN_INFO RECENT_NAME ": checkentry: unable to allocate for hash_table.\n"); + vfree(hold); + vfree(curr_table->table); + vfree(curr_table); + return -ENOMEM; + } + + for(c = 0; c < ip_list_hash_size; c++) { + curr_table->hash_table[c] = -1; + } + + /* Allocate memory for the time info */ +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: Allocating %d for time_info.\n", + sizeof(struct time_info_list)*ip_list_tot); +#endif + + curr_table->time_info = vmalloc(sizeof(struct time_info_list)*ip_list_tot); + if(!curr_table->time_info) { + printk(KERN_INFO RECENT_NAME ": checkentry: unable to allocate for time_info.\n"); + vfree(curr_table->hash_table); + vfree(hold); + vfree(curr_table->table); + vfree(curr_table); + return -ENOMEM; + } + for(c = 0; c < ip_list_tot; c++) { + curr_table->time_info[c].position = c; + curr_table->time_info[c].time = 0; + } + + /* Put the new table in place */ + spin_lock_bh(&recent_lock); + find_table = r_tables; + while( (last_table = find_table) && strncmp(info->name,find_table->name,IPT_RECENT_NAME_LEN) && (find_table = find_table->next) ); + + /* If a table already exists just increment the count on that table and return */ + if(find_table) { + find_table->count++; + spin_unlock_bh(&recent_lock); +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": checkentry: table found (%s), created by other process.\n",info->name); +#endif + vfree(curr_table->time_info); + vfree(curr_table->hash_table); + vfree(hold); + vfree(curr_table->table); + vfree(curr_table); + return 1; + } + if(!last_table) r_tables = curr_table; else last_table->next = curr_table; + + spin_unlock_bh(&recent_lock); + +#ifdef CONFIG_PROC_FS + /* Create our proc 'status' entry. */ + curr_table->status_proc = create_proc_entry(curr_table->name, ip_list_perms, proc_net_ipt_recent); + if (!curr_table->status_proc) { + printk(KERN_INFO RECENT_NAME ": checkentry: unable to allocate for /proc entry.\n"); + /* Destroy the created table */ + spin_lock_bh(&recent_lock); + last_table = NULL; + curr_table = r_tables; + if(!curr_table) { +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() create_proc failed, no tables.\n"); +#endif + spin_unlock_bh(&recent_lock); + return -ENOMEM; + } + while( strncmp(info->name,curr_table->name,IPT_RECENT_NAME_LEN) && (last_table = curr_table) && (curr_table = curr_table->next) ); + if(!curr_table) { +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() create_proc failed, table already destroyed.\n"); +#endif + spin_unlock_bh(&recent_lock); + return -ENOMEM; + } + if(last_table) last_table->next = curr_table->next; else r_tables = curr_table->next; + spin_unlock_bh(&recent_lock); + vfree(curr_table->time_info); + vfree(curr_table->hash_table); + vfree(hold); + vfree(curr_table->table); + vfree(curr_table); + return -ENOMEM; + } + + curr_table->status_proc->owner = THIS_MODULE; + curr_table->status_proc->data = curr_table; + wmb(); + curr_table->status_proc->read_proc = ip_recent_get_info; + curr_table->status_proc->write_proc = ip_recent_ctrl; +#endif /* CONFIG_PROC_FS */ + +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() left.\n"); +#endif + + return 1; +} + +/* This function is called in the event that a rule matching this module is + * removed. + * When this happens we need to check if there are no other rules matching + * the table given. If that is the case then we remove the table and clean + * up its memory. + */ +static void +destroy(void *matchinfo, unsigned int matchsize) +{ + const struct ipt_recent_info *info = matchinfo; + struct recent_ip_tables *curr_table, *last_table; + +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": destroy() entered.\n"); +#endif + + if(matchsize != IPT_ALIGN(sizeof(struct ipt_recent_info))) return; + + /* Lock the linked list while we play with it */ + spin_lock_bh(&recent_lock); + + /* Look for an entry with this name already created */ + /* Finds the end of the list and the entry before the end if current name does not exist */ + last_table = NULL; + curr_table = r_tables; + if(!curr_table) { +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": destroy() No tables found, leaving.\n"); +#endif + spin_unlock_bh(&recent_lock); + return; + } + while( strncmp(info->name,curr_table->name,IPT_RECENT_NAME_LEN) && (last_table = curr_table) && (curr_table = curr_table->next) ); + + /* If a table does not exist then do nothing and return */ + if(!curr_table) { +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": destroy() table not found, leaving.\n"); +#endif + spin_unlock_bh(&recent_lock); + return; + } + + curr_table->count--; + + /* If count is still non-zero then there are still rules referenceing it so we do nothing */ + if(curr_table->count) { +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": destroy() table found, non-zero count, leaving.\n"); +#endif + spin_unlock_bh(&recent_lock); + return; + } + +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": destroy() table found, zero count, removing.\n"); +#endif + + /* Count must be zero so we remove this table from the list */ + if(last_table) last_table->next = curr_table->next; else r_tables = curr_table->next; + + spin_unlock_bh(&recent_lock); + + /* lock to make sure any late-runners still using this after we removed it from + * the list finish up then remove everything */ + spin_lock_bh(&curr_table->list_lock); + spin_unlock_bh(&curr_table->list_lock); + +#ifdef CONFIG_PROC_FS + if(curr_table->status_proc) remove_proc_entry(curr_table->name,proc_net_ipt_recent); +#endif /* CONFIG_PROC_FS */ + vfree(curr_table->table[0].last_pkts); + vfree(curr_table->table); + vfree(curr_table->hash_table); + vfree(curr_table->time_info); + vfree(curr_table); + +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": destroy() left.\n"); +#endif + + return; +} + +/* This is the structure we pass to ipt_register to register our + * module with iptables. + */ +static struct ipt_match recent_match = { + .name = "recent", + .match = &match, + .checkentry = &checkentry, + .destroy = &destroy, + .me = THIS_MODULE +}; + +/* Kernel module initialization. */ +static int __init init(void) +{ + int count; + + printk(version); + proc_net_ipt_recent = proc_mkdir("ipt_recent",proc_net); + if(!proc_net_ipt_recent) return -ENOMEM; + + if(ip_list_hash_size && ip_list_hash_size <= ip_list_tot) { + printk(KERN_WARNING RECENT_NAME ": ip_list_hash_size too small, resetting to default.\n"); + ip_list_hash_size = 0; + } + + if(!ip_list_hash_size) { + ip_list_hash_size = ip_list_tot*3; + count = 2*2; + while(ip_list_hash_size > count) count = count*2; + ip_list_hash_size = count; + } + +#ifdef DEBUG + if(debug) printk(KERN_INFO RECENT_NAME ": ip_list_hash_size: %d\n",ip_list_hash_size); +#endif + + return ipt_register_match(&recent_match); +} + +/* Kernel module destruction. */ +static void __exit fini(void) +{ + ipt_unregister_match(&recent_match); + + remove_proc_entry("ipt_recent",proc_net); +} + +/* Register our module with the kernel. */ +module_init(init); +module_exit(fini); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_string.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_string.c new file mode 100644 index 00000000..a18b89d0 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_string.c @@ -0,0 +1,218 @@ +/* Kernel module to match a string into a packet. + * + * Copyright (C) 2000 Emmanuel Roger <winfield@freegates.be> + * + * ChangeLog + * 19.02.2002: Gianni Tedesco <gianni@ecsc.co.uk> + * Fixed SMP re-entrancy problem using per-cpu data areas + * for the skip/shift tables. + * 02.05.2001: Gianni Tedesco <gianni@ecsc.co.uk> + * Fixed kernel panic, due to overrunning boyer moore string + * tables. Also slightly tweaked heuristic for deciding what + * search algo to use. + * 27.01.2001: Gianni Tedesco <gianni@ecsc.co.uk> + * Implemented Boyer Moore Sublinear search algorithm + * alongside the existing linear search based on memcmp(). + * Also a quick check to decide which method to use on a per + * packet basis. + */ + +#include <linux/smp.h> +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/file.h> +#include <net/sock.h> + +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ipt_string.h> + +MODULE_LICENSE("GPL"); + +struct string_per_cpu { + int *skip; + int *shift; + int *len; +}; + +struct string_per_cpu *bm_string_data=NULL; + +/* Boyer Moore Sublinear string search - VERY FAST */ +char *search_sublinear (char *needle, char *haystack, int needle_len, int haystack_len) +{ + int M1, right_end, sk, sh; + int ended, j, i; + + int *skip, *shift, *len; + + /* use data suitable for this CPU */ + shift=bm_string_data[smp_processor_id()].shift; + skip=bm_string_data[smp_processor_id()].skip; + len=bm_string_data[smp_processor_id()].len; + + /* Setup skip/shift tables */ + M1 = right_end = needle_len-1; + for (i = 0; i < BM_MAX_HLEN; i++) skip[i] = needle_len; + for (i = 0; needle[i]; i++) skip[needle[i]] = M1 - i; + + for (i = 1; i < needle_len; i++) { + for (j = 0; j < needle_len && needle[M1 - j] == needle[M1 - i - j]; j++); + len[i] = j; + } + + shift[0] = 1; + for (i = 1; i < needle_len; i++) shift[i] = needle_len; + for (i = M1; i > 0; i--) shift[len[i]] = i; + ended = 0; + + for (i = 0; i < needle_len; i++) { + if (len[i] == M1 - i) ended = i; + if (ended) shift[i] = ended; + } + + /* Do the search*/ + while (right_end < haystack_len) + { + for (i = 0; i < needle_len && haystack[right_end - i] == needle[M1 - i]; i++); + if (i == needle_len) { + return haystack+(right_end - M1); + } + + sk = skip[haystack[right_end - i]]; + sh = shift[i]; + right_end = max(right_end - i + sk, right_end + sh); + } + + return NULL; +} + +/* Linear string search based on memcmp() */ +char *search_linear (char *needle, char *haystack, int needle_len, int haystack_len) +{ + char *k = haystack + (haystack_len-needle_len); + char *t = haystack; + + while ( t <= k ) { + if (memcmp(t, needle, needle_len) == 0) + return t; + t++; + } + + return NULL; +} + + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_string_info *info = matchinfo; + struct iphdr *ip = skb->nh.iph; + int hlen, nlen; + char *needle, *haystack; + proc_ipt_search search=search_linear; + + if ( !ip ) return 0; + + /* get lenghts, and validate them */ + nlen=info->len; + hlen=ntohs(ip->tot_len)-(ip->ihl*4); + if ( nlen > hlen ) return 0; + + needle=(char *)&info->string; + haystack=(char *)ip+(ip->ihl*4); + + /* The sublinear search comes in to its own + * on the larger packets */ + if ( (hlen>IPT_STRING_HAYSTACK_THRESH) && + (nlen>IPT_STRING_NEEDLE_THRESH) ) { + if ( hlen < BM_MAX_HLEN ) { + search=search_sublinear; + }else{ + if (net_ratelimit()) + printk(KERN_INFO "ipt_string: Packet too big " + "to attempt sublinear string search " + "(%d bytes)\n", hlen ); + } + } + + return ((search(needle, haystack, nlen, hlen)!=NULL) ^ info->invert); +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + + if (matchsize != IPT_ALIGN(sizeof(struct ipt_string_info))) + return 0; + + return 1; +} + +void string_freeup_data(void) +{ + int c; + + if ( bm_string_data ) { + for(c=0; c<smp_num_cpus; c++) { + if ( bm_string_data[c].shift ) kfree(bm_string_data[c].shift); + if ( bm_string_data[c].skip ) kfree(bm_string_data[c].skip); + if ( bm_string_data[c].len ) kfree(bm_string_data[c].len); + } + kfree(bm_string_data); + } +} + +static struct ipt_match string_match += { { NULL, NULL }, "string", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + int c; + size_t tlen; + size_t alen; + + tlen=sizeof(struct string_per_cpu)*smp_num_cpus; + alen=sizeof(int)*BM_MAX_HLEN; + + /* allocate array of structures */ + if ( !(bm_string_data=kmalloc(tlen,GFP_KERNEL)) ) { + return 0; + } + + memset(bm_string_data, 0, tlen); + + /* allocate our skip/shift tables */ + for(c=0; c<smp_num_cpus; c++) { + if ( !(bm_string_data[c].shift=kmalloc(alen, GFP_KERNEL)) ) + goto alloc_fail; + if ( !(bm_string_data[c].skip=kmalloc(alen, GFP_KERNEL)) ) + goto alloc_fail; + if ( !(bm_string_data[c].len=kmalloc(alen, GFP_KERNEL)) ) + goto alloc_fail; + } + + return ipt_register_match(&string_match); + +alloc_fail: + string_freeup_data(); + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_match(&string_match); + string_freeup_data(); +} + +module_init(init); +module_exit(fini); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_time.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_time.c index 216098fc..d3484bd9 100644 --- a/release/src/linux/linux/net/ipv4/netfilter/ipt_time.c +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_time.c @@ -10,6 +10,7 @@ 2001-26-09 Fabrice MARIE <fabrice@netfilter.org> : force the match to be in LOCAL_IN or PRE_ROUTING only. 2001-30-11 Fabrice : added the possibility to use the match in FORWARD/OUTPUT with a little hack, added Nguyen Dang Phuoc Dong <dongnd@tlnet.com.vn> patch to support timezones. + 2004-05-02 Fabrice : added support for date matching, from an idea of Fabien COELHO. */ #include <linux/module.h> @@ -19,7 +20,7 @@ #include <linux/time.h> MODULE_AUTHOR("Fabrice MARIE <fabrice@netfilter.org>"); -MODULE_DESCRIPTION("Match arrival timestamp"); +MODULE_DESCRIPTION("Match arrival timestamp/date"); MODULE_LICENSE("GPL"); struct tm @@ -53,7 +54,8 @@ match(const struct sk_buff *skb, { const struct ipt_time_info *info = matchinfo; /* match info for rule */ struct tm currenttime; /* time human readable */ - unsigned int packet_time; + u_int8_t days_of_week[7] = {64, 32, 16, 8, 4, 2, 1}; + u_int16_t packet_time; struct timeval kerneltimeval; time_t packet_local_time; @@ -66,22 +68,21 @@ match(const struct sk_buff *skb, else packet_local_time = skb->stamp.tv_sec; + /* First we make sure we are in the date start-stop boundaries */ + if ((packet_local_time < info->date_start) || (packet_local_time > info->date_stop)) + return 0; /* We are outside the date boundaries */ + /* Transform the timestamp of the packet, in a human readable form */ localtime(&packet_local_time, ¤ttime); /* check if we match this timestamp, we start by the days... */ - if (!((1 << currenttime.tm_wday) & info->days_match)) + if ((days_of_week[currenttime.tm_wday] & info->days_match) != days_of_week[currenttime.tm_wday]) return 0; /* the day doesn't match */ /* ... check the time now */ - packet_time = (currenttime.tm_hour * 60 * 60) + (currenttime.tm_min * 60) + currenttime.tm_sec; - if (info->time_start < info->time_stop) { - if ((packet_time < info->time_start) || (packet_time > info->time_stop)) - return 0; - } else { - if ((packet_time < info->time_start) && (packet_time > info->time_stop)) - return 0; - } + packet_time = (currenttime.tm_hour * 60) + currenttime.tm_min; + if ((packet_time < info->time_start) || (packet_time > info->time_stop)) + return 0; /* here we match ! */ return 1; @@ -96,24 +97,25 @@ checkentry(const char *tablename, { struct ipt_time_info *info = matchinfo; /* match info for rule */ - /* First, check that we are in the correct hook */ - /* PRE_ROUTING, LOCAL_IN or FROWARD */ + /* First, check that we are in the correct hooks */ if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT))) { printk("ipt_time: error, only valid for PRE_ROUTING, LOCAL_IN, FORWARD and OUTPUT)\n"); return 0; } - - /* always use kerneltime */ + /* we use the kerneltime if we are in forward or output */ info->kerneltime = 1; + if (hook_mask & ~((1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT))) + /* we use the skb time */ + info->kerneltime = 0; /* Check the size */ - if (matchsize < IPT_ALIGN(sizeof(struct ipt_time_info))) + if (matchsize != IPT_ALIGN(sizeof(struct ipt_time_info))) return 0; /* Now check the coherence of the data ... */ - if ((info->time_start > 86399) || /* 24*60*60-1 = 86399*/ - (info->time_stop > 86399)) + if ((info->time_start > 1439) || /* 23*60+59 = 1439*/ + (info->time_stop > 1439)) { printk(KERN_WARNING "ipt_time: invalid argument\n"); return 0; @@ -122,8 +124,12 @@ checkentry(const char *tablename, return 1; } -static struct ipt_match time_match -= { { NULL, NULL }, "time", &match, &checkentry, NULL, THIS_MODULE }; +static struct ipt_match time_match = { + .name = "time", + .match = match, + .checkentry = checkentry, + .me = THIS_MODULE, +}; static int __init init(void) { diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_u32.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_u32.c new file mode 100644 index 00000000..0c749563 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_u32.c @@ -0,0 +1,211 @@ +/* Kernel module to match u32 packet content. */ + +/* +U32 tests whether quantities of up to 4 bytes extracted from a packet +have specified values. The specification of what to extract is general +enough to find data at given offsets from tcp headers or payloads. + + --u32 tests + The argument amounts to a program in a small language described below. + tests := location = value | tests && location = value + value := range | value , range + range := number | number : number + a single number, n, is interpreted the same as n:n + n:m is interpreted as the range of numbers >=n and <=m + location := number | location operator number + operator := & | << | >> | @ + + The operators &, <<, >>, && mean the same as in c. The = is really a set + membership operator and the value syntax describes a set. The @ operator + is what allows moving to the next header and is described further below. + + *** Until I can find out how to avoid it, there are some artificial limits + on the size of the tests: + - no more than 10 ='s (and 9 &&'s) in the u32 argument + - no more than 10 ranges (and 9 commas) per value + - no more than 10 numbers (and 9 operators) per location + + To describe the meaning of location, imagine the following machine that + interprets it. There are three registers: + A is of type char*, initially the address of the IP header + B and C are unsigned 32 bit integers, initially zero + + The instructions are: + number B = number; + C = (*(A+B)<<24)+(*(A+B+1)<<16)+(*(A+B+2)<<8)+*(A+B+3) + &number C = C&number + <<number C = C<<number + >>number C = C>>number + @number A = A+C; then do the instruction number + Any access of memory outside [skb->head,skb->end] causes the match to fail. + Otherwise the result of the computation is the final value of C. + + Whitespace is allowed but not required in the tests. + However the characters that do occur there are likely to require + shell quoting, so it's a good idea to enclose the arguments in quotes. + +Example: + match IP packets with total length >= 256 + The IP header contains a total length field in bytes 2-3. + --u32 "0&0xFFFF=0x100:0xFFFF" + read bytes 0-3 + AND that with FFFF (giving bytes 2-3), + and test whether that's in the range [0x100:0xFFFF] + +Example: (more realistic, hence more complicated) + match icmp packets with icmp type 0 + First test that it's an icmp packet, true iff byte 9 (protocol) = 1 + --u32 "6&0xFF=1 && ... + read bytes 6-9, use & to throw away bytes 6-8 and compare the result to 1 + Next test that it's not a fragment. + (If so it might be part of such a packet but we can't always tell.) + n.b. This test is generally needed if you want to match anything + beyond the IP header. + The last 6 bits of byte 6 and all of byte 7 are 0 iff this is a complete + packet (not a fragment). Alternatively, you can allow first fragments + by only testing the last 5 bits of byte 6. + ... 4&0x3FFF=0 && ... + Last test: the first byte past the IP header (the type) is 0 + This is where we have to use the @syntax. The length of the IP header + (IHL) in 32 bit words is stored in the right half of byte 0 of the + IP header itself. + ... 0>>22&0x3C@0>>24=0" + The first 0 means read bytes 0-3, + >>22 means shift that 22 bits to the right. Shifting 24 bits would give + the first byte, so only 22 bits is four times that plus a few more bits. + &3C then eliminates the two extra bits on the right and the first four + bits of the first byte. + For instance, if IHL=5 then the IP header is 20 (4 x 5) bytes long. + In this case bytes 0-1 are (in binary) xxxx0101 yyzzzzzz, + >>22 gives the 10 bit value xxxx0101yy and &3C gives 010100. + @ means to use this number as a new offset into the packet, and read + four bytes starting from there. This is the first 4 bytes of the icmp + payload, of which byte 0 is the icmp type. Therefore we simply shift + the value 24 to the right to throw out all but the first byte and compare + the result with 0. + +Example: + tcp payload bytes 8-12 is any of 1, 2, 5 or 8 + First we test that the packet is a tcp packet (similar to icmp). + --u32 "6&0xFF=6 && ... + Next, test that it's not a fragment (same as above). + ... 0>>22&0x3C@12>>26&0x3C@8=1,2,5,8" + 0>>22&3C as above computes the number of bytes in the IP header. + @ makes this the new offset into the packet, which is the start of the + tcp header. The length of the tcp header (again in 32 bit words) is + the left half of byte 12 of the tcp header. The 12>>26&3C + computes this length in bytes (similar to the IP header before). + @ makes this the new offset, which is the start of the tcp payload. + Finally 8 reads bytes 8-12 of the payload and = checks whether the + result is any of 1, 2, 5 or 8 +*/ + +#include <linux/module.h> +#include <linux/skbuff.h> + +#include <linux/netfilter_ipv4/ipt_u32.h> +#include <linux/netfilter_ipv4/ip_tables.h> + +/* #include <asm-i386/timex.h> for timing */ + +MODULE_AUTHOR("Don Cohen <don@isis.cs3-inc.com>"); +MODULE_DESCRIPTION("IP tables u32 matching module"); +MODULE_LICENSE("GPL"); + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_u32 *data = matchinfo; + int testind, i; + unsigned char* origbase = (char*)skb->nh.iph; + unsigned char* base = origbase; + unsigned char* head = skb->head; + unsigned char* end = skb->end; + int nnums, nvals; + u_int32_t pos, val; + /* unsigned long long cycles1, cycles2, cycles3, cycles4; + cycles1 = get_cycles(); */ + + for (testind=0; testind < data->ntests; testind++) { + base = origbase; /* reset for each test */ + pos = data->tests[testind].location[0].number; + if (base+pos+3 > end || base+pos < head) + return 0; + val = (base[pos]<<24) + (base[pos+1]<<16) + + (base[pos+2]<<8) + base[pos+3]; + nnums = data->tests[testind].nnums; + for (i=1; i < nnums; i++) { + u_int32_t number = data->tests[testind].location[i].number; + switch (data->tests[testind].location[i].nextop) { + case IPT_U32_AND: + val = val & number; + break; + case IPT_U32_LEFTSH: + val = val << number; + break; + case IPT_U32_RIGHTSH: + val = val >> number; + break; + case IPT_U32_AT: + base = base + val; + pos = number; + if (base+pos+3 > end || base+pos < head) + return 0; + val = (base[pos]<<24) + (base[pos+1]<<16) + + (base[pos+2]<<8) + base[pos+3]; + break; + } + } + nvals = data->tests[testind].nvalues; + for (i=0; i < nvals; i++) { + if ((data->tests[testind].value[i].min <= val) && + (val <= data->tests[testind].value[i].max)) { + break; + } + } + if (i >= data->tests[testind].nvalues) { + /* cycles2 = get_cycles(); + printk("failed %d in %d cycles\n", testind, + cycles2-cycles1); */ + return 0; + } + } + /* cycles2 = get_cycles(); + printk("succeeded in %d cycles\n", cycles2-cycles1); */ + return 1; +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_u32))) + return 0; + return 1; +} + +static struct ipt_match u32_match += { { NULL, NULL }, "u32", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_match(&u32_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&u32_match); +} + +module_init(init); +module_exit(fini); diff --git a/release/src/linux/linux/net/ipv4/netfilter/ipt_web.c b/release/src/linux/linux/net/ipv4/netfilter/ipt_web.c new file mode 100644 index 00000000..c32a860a --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ipt_web.c @@ -0,0 +1,246 @@ +/* + + web (experimental) + HTTP client request match + Copyright (C) 2006 Jonathan Zarate + + Licensed under GNU GPL v2 or later. + +*/ +#include <linux/module.h> +#include <linux/skbuff.h> +#include <net/sock.h> +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ipt_web.h> + +MODULE_AUTHOR("Jonathan Zarate"); +MODULE_DESCRIPTION("HTTP client request match (experimental)"); +MODULE_LICENSE("GPL"); + + +// #define LOG printk +#define LOG(...) do { } while (0); + + +static int find(const char *data, const char *tail, const char *text) +{ + int n, o; + int dlen; + const char *p, *e; + + while ((data < tail) && (*data == ' ')) ++data; + while ((tail > data) && (*(tail - 1) == ' ')) --tail; + + dlen = tail - data; + +#if 0 + { + char tmp[128]; + int z; + z = sizeof(tmp) - 1; + if (z > dlen) z = dlen; + memcpy(tmp, data, z); + tmp[z] = 0; + LOG(KERN_INFO "find in '%s'\n", tmp); + } +#endif + + // 012345 + // text + // ^text + // text$ + // ^text$ + // 012345 + + while (*text) { + n = o = strlen(text); + if (*text == '^') { + --n; + if (*(text + n) == '$') { + // exact + --n; + if ((dlen == n) && (memcmp(data, text + 1, n) == 0)) { + LOG(KERN_INFO "matched %s\n", text); + return 1; + } + } + else { + // begins with + if ((dlen >= n) && (memcmp(data, text + 1, n) == 0)) { + LOG(KERN_INFO "matched %s\n", text); + return 1; + } + } + } + else if (*(text + n - 1) == '$') { + // ends with + --n; + if (memcmp(tail - n, text, n) == 0) { + LOG(KERN_INFO "matched %s\n", text); + return 1; + } + } + else { + // contains + p = data; + e = tail - n; + while (p <= e) { + if (memcmp(p, text, n) == 0) { + LOG(KERN_INFO "matched %s\n", text); + return 1; + } + ++p; + } + } + + text += o + 1; + } + return 0; +} + +static inline const char *findend(const char *data, const char *tail, int min) +{ + int n = tail - data; + if (n >= min) { + while (data < tail) { + if (*data == '\r') return data; + ++data; + } + } + return NULL; +} + +static int match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, + const void *matchinfo, int offset, const void *hdr, u_int16_t datalen, int *hotdrop) +{ + const struct ipt_web_info *info; + const struct tcphdr *tcph; + const char *data; + const char *tail; + const char *p, *q; + int doff, dlen; + + info = matchinfo; + + if (offset != 0) return info->invert; + + tcph = hdr; + doff = (tcph->doff * 4); + data = (char *)tcph + doff; + dlen = datalen - doff; + +#if 0 + printk(KERN_INFO "datalen=%u dlen=%d doff=%d\n", datalen, dlen, doff); + char tmp[16]; + memcpy(tmp, data, sizeof(tmp)); + tmp[sizeof(tmp) - 1] = 0; + printk(KERN_INFO "[%s]\n", tmp); +#endif + + // POST / HTTP/1.0$$$$ + // GET / HTTP/1.0$$$$ + // 1234567890123456789 + if (dlen < 18) return info->invert; + + // "GET " or "POST" + __u32 sig = *(__u32 *)data; + if ((sig != __constant_htonl(0x47455420)) && (sig != __constant_htonl(0x504f5354))) { + return info->invert; + } + + tail = data + dlen; + if (dlen > 1024) { + dlen = 1024; + tail = data + 1024; + } + + + // POST / HTTP/1.0$$$$ + // GET / HTTP/1.0$$$$ -- minimum + // 0123456789012345678 + // 9876543210 + if (((p = findend(data + 14, tail, 18)) == NULL) || (memcmp(p - 9, " HTTP/", 6) != 0)) + return info->invert; + +#if 0 + { + const char *qq = info->text; + while (*qq) { + printk(KERN_INFO "text=%s\n", qq); + qq += strlen(qq) + 1; + } + } +#endif + + switch (info->mode) { + case IPT_WEB_HTTP: + return !info->invert; + case IPT_WEB_HORE: + // entire request line, else host line + if (find(data + 4, p - 9, info->text)) return !info->invert; + break; + case IPT_WEB_PATH: + // left side of '?' or entire line + q = data += 4; + p -= 9; + while ((q < p) && (*q != '?')) ++q; + return find(data, q, info->text) ^ info->invert; + case IPT_WEB_QUERY: + // right side of '?' or none + q = data + 4; + p -= 9; + while ((q < p) && (*q != '?')) ++q; + if (q >= p) return info->invert; + return find(q + 1, p, info->text) ^ info->invert; + case IPT_WEB_RURI: + // entire request line + return find(data + 4, p - 9, info->text) ^ info->invert; + default: + // shutup compiler + break; + } + + // else, IPT_WEB_HOST + + while (1) { + data = p + 2; // skip previous \r\n + p = findend(data, tail, 8); // p = current line's \r + if (p == NULL) return 0; + +#if 0 + char tmp[64]; + memcpy(tmp, data, 32); + tmp[32] = 0; + printk(KERN_INFO "data=[%s]\n", tmp); +#endif + + if (memcmp(data, "Host: ", 6) == 0) + return find(data + 6, p, info->text) ^ info->invert; + } + + return !info->invert; +} + +static int checkentry(const char *tablename, const struct ipt_ip *ip, void *matchinfo, + unsigned int matchsize, unsigned int hook_mask) +{ + return (matchsize == IPT_ALIGN(sizeof(struct ipt_web_info))); +} + + +static struct ipt_match web_match += { { NULL, NULL }, "web", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ +// LOG(KERN_INFO "ipt_web <" __DATE__ " " __TIME__ "> loaded\n"); + return ipt_register_match(&web_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&web_match); +} + +module_init(init); +module_exit(fini); diff --git a/release/src/linux/linux/net/ipv4/netfilter/regexp/regexp.c b/release/src/linux/linux/net/ipv4/netfilter/regexp/regexp.c new file mode 100644 index 00000000..31ef35b9 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/regexp/regexp.c @@ -0,0 +1,1195 @@ +/* + * regcomp and regexec -- regsub and regerror are elsewhere + * @(#)regexp.c 1.3 of 18 April 87 + * + * Copyright (c) 1986 by University of Toronto. + * Written by Henry Spencer. Not derived from licensed software. + * + * Permission is granted to anyone to use this software for any + * purpose on any computer system, and to redistribute it freely, + * subject to the following restrictions: + * + * 1. The author is not responsible for the consequences of use of + * this software, no matter how awful, even if they arise + * from defects in it. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. + * + * 3. Altered versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * Beware that some of this code is subtly aware of the way operator + * precedence is structured in regular expressions. Serious changes in + * regular-expression syntax might require a total rethink. + * + * This code was modified by Ethan Sommer to work within the kernel + * (it now uses kmalloc etc..) + * + * Modified slightly by Matthew Strait to use more modern C. + */ + +#include "regexp.h" +#include "regmagic.h" + +/* added by ethan and matt. Lets it work in both kernel and user space. +(So iptables can use it, for instance.) Yea, it goes both ways... */ +#if __KERNEL__ + #define malloc(foo) kmalloc(foo,GFP_ATOMIC) +#else + #define printk(format,args...) printf(format,##args) +#endif + +void regerror(char * s) +{ + printk("<3>Regexp: %s\n", s); + /* NOTREACHED */ +} + +/* + * The "internal use only" fields in regexp.h are present to pass info from + * compile to execute that permits the execute phase to run lots faster on + * simple cases. They are: + * + * regstart char that must begin a match; '\0' if none obvious + * reganch is the match anchored (at beginning-of-line only)? + * regmust string (pointer into program) that match must include, or NULL + * regmlen length of regmust string + * + * Regstart and reganch permit very fast decisions on suitable starting points + * for a match, cutting down the work a lot. Regmust permits fast rejection + * of lines that cannot possibly match. The regmust tests are costly enough + * that regcomp() supplies a regmust only if the r.e. contains something + * potentially expensive (at present, the only such thing detected is * or + + * at the start of the r.e., which can involve a lot of backup). Regmlen is + * supplied because the test in regexec() needs it and regcomp() is computing + * it anyway. + */ + +/* + * Structure for regexp "program". This is essentially a linear encoding + * of a nondeterministic finite-state machine (aka syntax charts or + * "railroad normal form" in parsing technology). Each node is an opcode + * plus a "next" pointer, possibly plus an operand. "Next" pointers of + * all nodes except BRANCH implement concatenation; a "next" pointer with + * a BRANCH on both ends of it is connecting two alternatives. (Here we + * have one of the subtle syntax dependencies: an individual BRANCH (as + * opposed to a collection of them) is never concatenated with anything + * because of operator precedence.) The operand of some types of node is + * a literal string; for others, it is a node leading into a sub-FSM. In + * particular, the operand of a BRANCH node is the first node of the branch. + * (NB this is *not* a tree structure: the tail of the branch connects + * to the thing following the set of BRANCHes.) The opcodes are: + */ + +/* definition number opnd? meaning */ +#define END 0 /* no End of program. */ +#define BOL 1 /* no Match "" at beginning of line. */ +#define EOL 2 /* no Match "" at end of line. */ +#define ANY 3 /* no Match any one character. */ +#define ANYOF 4 /* str Match any character in this string. */ +#define ANYBUT 5 /* str Match any character not in this string. */ +#define BRANCH 6 /* node Match this alternative, or the next... */ +#define BACK 7 /* no Match "", "next" ptr points backward. */ +#define EXACTLY 8 /* str Match this string. */ +#define NOTHING 9 /* no Match empty string. */ +#define STAR 10 /* node Match this (simple) thing 0 or more times. */ +#define PLUS 11 /* node Match this (simple) thing 1 or more times. */ +#define OPEN 20 /* no Mark this point in input as start of #n. */ + /* OPEN+1 is number 1, etc. */ +#define CLOSE 30 /* no Analogous to OPEN. */ + +/* + * Opcode notes: + * + * BRANCH The set of branches constituting a single choice are hooked + * together with their "next" pointers, since precedence prevents + * anything being concatenated to any individual branch. The + * "next" pointer of the last BRANCH in a choice points to the + * thing following the whole choice. This is also where the + * final "next" pointer of each individual branch points; each + * branch starts with the operand node of a BRANCH node. + * + * BACK Normal "next" pointers all implicitly point forward; BACK + * exists to make loop structures possible. + * + * STAR,PLUS '?', and complex '*' and '+', are implemented as circular + * BRANCH structures using BACK. Simple cases (one character + * per match) are implemented with STAR and PLUS for speed + * and to minimize recursive plunges. + * + * OPEN,CLOSE ...are numbered at compile time. + */ + +/* + * A node is one char of opcode followed by two chars of "next" pointer. + * "Next" pointers are stored as two 8-bit pieces, high order first. The + * value is a positive offset from the opcode of the node containing it. + * An operand, if any, simply follows the node. (Note that much of the + * code generation knows about this implicit relationship.) + * + * Using two bytes for the "next" pointer is vast overkill for most things, + * but allows patterns to get big without disasters. + */ +#define OP(p) (*(p)) +#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377)) +#define OPERAND(p) ((p) + 3) + +/* + * See regmagic.h for one further detail of program structure. + */ + + +/* + * Utility definitions. + */ +#ifndef CHARBITS +#define UCHARAT(p) ((int)*(unsigned char *)(p)) +#else +#define UCHARAT(p) ((int)*(p)&CHARBITS) +#endif + +#define FAIL(m) { regerror(m); return(NULL); } +#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?') +#define META "^$.[()|?+*\\" + +/* + * Flags to be passed up and down. + */ +#define HASWIDTH 01 /* Known never to match null string. */ +#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */ +#define SPSTART 04 /* Starts with * or +. */ +#define WORST 0 /* Worst case. */ + +/* + * Global work variables for regcomp(). + */ +static char *regparse; /* Input-scan pointer. */ +static int regnpar; /* () count. */ +static char regdummy; +static char *regcode; /* Code-emit pointer; ®dummy = don't. */ +static long regsize; /* Code size. */ + +/* + * Forward declarations for regcomp()'s friends. + */ +#ifndef STATIC +#define STATIC static +#endif +STATIC char *reg(int paren,int *flagp); +STATIC char *regbranch(int *flagp); +STATIC char *regpiece(int *flagp); +STATIC char *regatom(int *flagp); +STATIC char *regnode(char op); +STATIC char *regnext(char *p); +STATIC void regc(char b); +STATIC void reginsert(char op, char *opnd); +STATIC void regtail(char *p, char *val); +STATIC void regoptail(char *p, char *val); + + +__kernel_size_t my_strcspn(const char *s1,const char *s2) +{ + char *scan1; + char *scan2; + int count; + + count = 0; + for (scan1 = (char *)s1; *scan1 != '\0'; scan1++) { + for (scan2 = (char *)s2; *scan2 != '\0';) /* ++ moved down. */ + if (*scan1 == *scan2++) + return(count); + count++; + } + return(count); +} + +/* + - regcomp - compile a regular expression into internal code + * + * We can't allocate space until we know how big the compiled form will be, + * but we can't compile it (and thus know how big it is) until we've got a + * place to put the code. So we cheat: we compile it twice, once with code + * generation turned off and size counting turned on, and once "for real". + * This also means that we don't allocate space until we are sure that the + * thing really will compile successfully, and we never have to move the + * code and thus invalidate pointers into it. (Note that it has to be in + * one piece because free() must be able to free it all.) + * + * Beware that the optimization-preparation code in here knows about some + * of the structure of the compiled regexp. + */ +regexp * +regcomp(char *exp,int *patternsize) +{ + register regexp *r; + register char *scan; + register char *longest; + register int len; + int flags; + /* commented out by ethan + extern char *malloc(); + */ + + if (exp == NULL) + FAIL("NULL argument"); + + /* First pass: determine size, legality. */ + regparse = exp; + regnpar = 1; + regsize = 0L; + regcode = ®dummy; + regc(MAGIC); + if (reg(0, &flags) == NULL) + return(NULL); + + /* Small enough for pointer-storage convention? */ + if (regsize >= 32767L) /* Probably could be 65535L. */ + FAIL("regexp too big"); + + /* Allocate space. */ + *patternsize=sizeof(regexp) + (unsigned)regsize; + r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize); + if (r == NULL) + FAIL("out of space"); + + /* Second pass: emit code. */ + regparse = exp; + regnpar = 1; + regcode = r->program; + regc(MAGIC); + if (reg(0, &flags) == NULL) + return(NULL); + + /* Dig out information for optimizations. */ + r->regstart = '\0'; /* Worst-case defaults. */ + r->reganch = 0; + r->regmust = NULL; + r->regmlen = 0; + scan = r->program+1; /* First BRANCH. */ + if (OP(regnext(scan)) == END) { /* Only one top-level choice. */ + scan = OPERAND(scan); + + /* Starting-point info. */ + if (OP(scan) == EXACTLY) + r->regstart = *OPERAND(scan); + else if (OP(scan) == BOL) + r->reganch++; + + /* + * If there's something expensive in the r.e., find the + * longest literal string that must appear and make it the + * regmust. Resolve ties in favor of later strings, since + * the regstart check works with the beginning of the r.e. + * and avoiding duplication strengthens checking. Not a + * strong reason, but sufficient in the absence of others. + */ + if (flags&SPSTART) { + longest = NULL; + len = 0; + for (; scan != NULL; scan = regnext(scan)) + if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) { + longest = OPERAND(scan); + len = strlen(OPERAND(scan)); + } + r->regmust = longest; + r->regmlen = len; + } + } + + return(r); +} + +/* + - reg - regular expression, i.e. main body or parenthesized thing + * + * Caller must absorb opening parenthesis. + * + * Combining parenthesis handling with the base level of regular expression + * is a trifle forced, but the need to tie the tails of the branches to what + * follows makes it hard to avoid. + */ +static char * +reg(int paren, int *flagp /* Parenthesized? */ ) +{ + register char *ret; + register char *br; + register char *ender; + register int parno = 0; /* 0 makes gcc happy */ + int flags; + + *flagp = HASWIDTH; /* Tentatively. */ + + /* Make an OPEN node, if parenthesized. */ + if (paren) { + if (regnpar >= NSUBEXP) + FAIL("too many ()"); + parno = regnpar; + regnpar++; + ret = regnode(OPEN+parno); + } else + ret = NULL; + + /* Pick up the branches, linking them together. */ + br = regbranch(&flags); + if (br == NULL) + return(NULL); + if (ret != NULL) + regtail(ret, br); /* OPEN -> first. */ + else + ret = br; + if (!(flags&HASWIDTH)) + *flagp &= ~HASWIDTH; + *flagp |= flags&SPSTART; + while (*regparse == '|') { + regparse++; + br = regbranch(&flags); + if (br == NULL) + return(NULL); + regtail(ret, br); /* BRANCH -> BRANCH. */ + if (!(flags&HASWIDTH)) + *flagp &= ~HASWIDTH; + *flagp |= flags&SPSTART; + } + + /* Make a closing node, and hook it on the end. */ + ender = regnode((paren) ? CLOSE+parno : END); + regtail(ret, ender); + + /* Hook the tails of the branches to the closing node. */ + for (br = ret; br != NULL; br = regnext(br)) + regoptail(br, ender); + + /* Check for proper termination. */ + if (paren && *regparse++ != ')') { + FAIL("unmatched ()"); + } else if (!paren && *regparse != '\0') { + if (*regparse == ')') { + FAIL("unmatched ()"); + } else + FAIL("junk on end"); /* "Can't happen". */ + /* NOTREACHED */ + } + + return(ret); +} + +/* + - regbranch - one alternative of an | operator + * + * Implements the concatenation operator. + */ +static char * +regbranch(int *flagp) +{ + register char *ret; + register char *chain; + register char *latest; + int flags; + + *flagp = WORST; /* Tentatively. */ + + ret = regnode(BRANCH); + chain = NULL; + while (*regparse != '\0' && *regparse != '|' && *regparse != ')') { + latest = regpiece(&flags); + if (latest == NULL) + return(NULL); + *flagp |= flags&HASWIDTH; + if (chain == NULL) /* First piece. */ + *flagp |= flags&SPSTART; + else + regtail(chain, latest); + chain = latest; + } + if (chain == NULL) /* Loop ran zero times. */ + (void) regnode(NOTHING); + + return(ret); +} + +/* + - regpiece - something followed by possible [*+?] + * + * Note that the branching code sequences used for ? and the general cases + * of * and + are somewhat optimized: they use the same NOTHING node as + * both the endmarker for their branch list and the body of the last branch. + * It might seem that this node could be dispensed with entirely, but the + * endmarker role is not redundant. + */ +static char * +regpiece(int *flagp) +{ + register char *ret; + register char op; + register char *next; + int flags; + + ret = regatom(&flags); + if (ret == NULL) + return(NULL); + + op = *regparse; + if (!ISMULT(op)) { + *flagp = flags; + return(ret); + } + + if (!(flags&HASWIDTH) && op != '?') + FAIL("*+ operand could be empty"); + *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH); + + if (op == '*' && (flags&SIMPLE)) + reginsert(STAR, ret); + else if (op == '*') { + /* Emit x* as (x&|), where & means "self". */ + reginsert(BRANCH, ret); /* Either x */ + regoptail(ret, regnode(BACK)); /* and loop */ + regoptail(ret, ret); /* back */ + regtail(ret, regnode(BRANCH)); /* or */ + regtail(ret, regnode(NOTHING)); /* null. */ + } else if (op == '+' && (flags&SIMPLE)) + reginsert(PLUS, ret); + else if (op == '+') { + /* Emit x+ as x(&|), where & means "self". */ + next = regnode(BRANCH); /* Either */ + regtail(ret, next); + regtail(regnode(BACK), ret); /* loop back */ + regtail(next, regnode(BRANCH)); /* or */ + regtail(ret, regnode(NOTHING)); /* null. */ + } else if (op == '?') { + /* Emit x? as (x|) */ + reginsert(BRANCH, ret); /* Either x */ + regtail(ret, regnode(BRANCH)); /* or */ + next = regnode(NOTHING); /* null. */ + regtail(ret, next); + regoptail(ret, next); + } + regparse++; + if (ISMULT(*regparse)) + FAIL("nested *?+"); + + return(ret); +} + +/* + - regatom - the lowest level + * + * Optimization: gobbles an entire sequence of ordinary characters so that + * it can turn them into a single node, which is smaller to store and + * faster to run. Backslashed characters are exceptions, each becoming a + * separate node; the code is simpler that way and it's not worth fixing. + */ +static char * +regatom(int *flagp) +{ + register char *ret; + int flags; + + *flagp = WORST; /* Tentatively. */ + + switch (*regparse++) { + case '^': + ret = regnode(BOL); + break; + case '$': + ret = regnode(EOL); + break; + case '.': + ret = regnode(ANY); + *flagp |= HASWIDTH|SIMPLE; + break; + case '[': { + register int class; + register int classend; + + if (*regparse == '^') { /* Complement of range. */ + ret = regnode(ANYBUT); + regparse++; + } else + ret = regnode(ANYOF); + if (*regparse == ']' || *regparse == '-') + regc(*regparse++); + while (*regparse != '\0' && *regparse != ']') { + if (*regparse == '-') { + regparse++; + if (*regparse == ']' || *regparse == '\0') + regc('-'); + else { + class = UCHARAT(regparse-2)+1; + classend = UCHARAT(regparse); + if (class > classend+1) + FAIL("invalid [] range"); + for (; class <= classend; class++) + regc(class); + regparse++; + } + } else + regc(*regparse++); + } + regc('\0'); + if (*regparse != ']') + FAIL("unmatched []"); + regparse++; + *flagp |= HASWIDTH|SIMPLE; + } + break; + case '(': + ret = reg(1, &flags); + if (ret == NULL) + return(NULL); + *flagp |= flags&(HASWIDTH|SPSTART); + break; + case '\0': + case '|': + case ')': + FAIL("internal urp"); /* Supposed to be caught earlier. */ + break; + case '?': + case '+': + case '*': + FAIL("?+* follows nothing"); + break; + case '\\': + if (*regparse == '\0') + FAIL("trailing \\"); + ret = regnode(EXACTLY); + regc(*regparse++); + regc('\0'); + *flagp |= HASWIDTH|SIMPLE; + break; + default: { + register int len; + register char ender; + + regparse--; + len = my_strcspn((const char *)regparse, (const char *)META); + if (len <= 0) + FAIL("internal disaster"); + ender = *(regparse+len); + if (len > 1 && ISMULT(ender)) + len--; /* Back off clear of ?+* operand. */ + *flagp |= HASWIDTH; + if (len == 1) + *flagp |= SIMPLE; + ret = regnode(EXACTLY); + while (len > 0) { + regc(*regparse++); + len--; + } + regc('\0'); + } + break; + } + + return(ret); +} + +/* + - regnode - emit a node + */ +static char * /* Location. */ +regnode(char op) +{ + register char *ret; + register char *ptr; + + ret = regcode; + if (ret == ®dummy) { + regsize += 3; + return(ret); + } + + ptr = ret; + *ptr++ = op; + *ptr++ = '\0'; /* Null "next" pointer. */ + *ptr++ = '\0'; + regcode = ptr; + + return(ret); +} + +/* + - regc - emit (if appropriate) a byte of code + */ +static void +regc(char b) +{ + if (regcode != ®dummy) + *regcode++ = b; + else + regsize++; +} + +/* + - reginsert - insert an operator in front of already-emitted operand + * + * Means relocating the operand. + */ +static void +reginsert(char op, char* opnd) +{ + register char *src; + register char *dst; + register char *place; + + if (regcode == ®dummy) { + regsize += 3; + return; + } + + src = regcode; + regcode += 3; + dst = regcode; + while (src > opnd) + *--dst = *--src; + + place = opnd; /* Op node, where operand used to be. */ + *place++ = op; + *place++ = '\0'; + *place++ = '\0'; +} + +/* + - regtail - set the next-pointer at the end of a node chain + */ +static void +regtail(char *p, char *val) +{ + register char *scan; + register char *temp; + register int offset; + + if (p == ®dummy) + return; + + /* Find last node. */ + scan = p; + for (;;) { + temp = regnext(scan); + if (temp == NULL) + break; + scan = temp; + } + + if (OP(scan) == BACK) + offset = scan - val; + else + offset = val - scan; + *(scan+1) = (offset>>8)&0377; + *(scan+2) = offset&0377; +} + +/* + - regoptail - regtail on operand of first argument; nop if operandless + */ +static void +regoptail(char *p, char *val) +{ + /* "Operandless" and "op != BRANCH" are synonymous in practice. */ + if (p == NULL || p == ®dummy || OP(p) != BRANCH) + return; + regtail(OPERAND(p), val); +} + +/* + * regexec and friends + */ + +/* + * Global work variables for regexec(). + */ +static char *reginput; /* String-input pointer. */ +static char *regbol; /* Beginning of input, for ^ check. */ +static char **regstartp; /* Pointer to startp array. */ +static char **regendp; /* Ditto for endp. */ + +/* + * Forwards. + */ +STATIC int regtry(regexp *prog, char *string); +STATIC int regmatch(char *prog); +STATIC int regrepeat(char *p); + +#ifdef DEBUG +int regnarrate = 0; +void regdump(); +STATIC char *regprop(char *op); +#endif + +/* + - regexec - match a regexp against a string + */ +int +regexec(regexp *prog, char *string) +{ + register char *s; + + /* Be paranoid... */ + if (prog == NULL || string == NULL) { + printk("<3>Regexp: NULL parameter\n"); + return(0); + } + + /* Check validity of program. */ + if (UCHARAT(prog->program) != MAGIC) { + printk("<3>Regexp: corrupted program\n"); + return(0); + } + + /* If there is a "must appear" string, look for it. */ + if (prog->regmust != NULL) { + s = string; + while ((s = strchr(s, prog->regmust[0])) != NULL) { + if (strncmp(s, prog->regmust, prog->regmlen) == 0) + break; /* Found it. */ + s++; + } + if (s == NULL) /* Not present. */ + return(0); + } + + /* Mark beginning of line for ^ . */ + regbol = string; + + /* Simplest case: anchored match need be tried only once. */ + if (prog->reganch) + return(regtry(prog, string)); + + /* Messy cases: unanchored match. */ + s = string; + if (prog->regstart != '\0') + /* We know what char it must start with. */ + while ((s = strchr(s, prog->regstart)) != NULL) { + if (regtry(prog, s)) + return(1); + s++; + } + else + /* We don't -- general case. */ + do { + if (regtry(prog, s)) + return(1); + } while (*s++ != '\0'); + + /* Failure. */ + return(0); +} + +/* + - regtry - try match at specific point + */ +static int /* 0 failure, 1 success */ +regtry(regexp *prog, char *string) +{ + register int i; + register char **sp; + register char **ep; + + reginput = string; + regstartp = prog->startp; + regendp = prog->endp; + + sp = prog->startp; + ep = prog->endp; + for (i = NSUBEXP; i > 0; i--) { + *sp++ = NULL; + *ep++ = NULL; + } + if (regmatch(prog->program + 1)) { + prog->startp[0] = string; + prog->endp[0] = reginput; + return(1); + } else + return(0); +} + +/* + - regmatch - main matching routine + * + * Conceptually the strategy is simple: check to see whether the current + * node matches, call self recursively to see whether the rest matches, + * and then act accordingly. In practice we make some effort to avoid + * recursion, in particular by going through "ordinary" nodes (that don't + * need to know whether the rest of the match failed) by a loop instead of + * by recursion. + */ +static int /* 0 failure, 1 success */ +regmatch(char *prog) +{ + register char *scan = prog; /* Current node. */ + char *next; /* Next node. */ + +#ifdef DEBUG + if (scan != NULL && regnarrate) + fprintf(stderr, "%s(\n", regprop(scan)); +#endif + while (scan != NULL) { +#ifdef DEBUG + if (regnarrate) + fprintf(stderr, "%s...\n", regprop(scan)); +#endif + next = regnext(scan); + + switch (OP(scan)) { + case BOL: + if (reginput != regbol) + return(0); + break; + case EOL: + if (*reginput != '\0') + return(0); + break; + case ANY: + if (*reginput == '\0') + return(0); + reginput++; + break; + case EXACTLY: { + register int len; + register char *opnd; + + opnd = OPERAND(scan); + /* Inline the first character, for speed. */ + if (*opnd != *reginput) + return(0); + len = strlen(opnd); + if (len > 1 && strncmp(opnd, reginput, len) != 0) + return(0); + reginput += len; + } + break; + case ANYOF: + if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL) + return(0); + reginput++; + break; + case ANYBUT: + if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL) + return(0); + reginput++; + break; + case NOTHING: + case BACK: + break; + case OPEN+1: + case OPEN+2: + case OPEN+3: + case OPEN+4: + case OPEN+5: + case OPEN+6: + case OPEN+7: + case OPEN+8: + case OPEN+9: { + register int no; + register char *save; + + no = OP(scan) - OPEN; + save = reginput; + + if (regmatch(next)) { + /* + * Don't set startp if some later + * invocation of the same parentheses + * already has. + */ + if (regstartp[no] == NULL) + regstartp[no] = save; + return(1); + } else + return(0); + } + break; + case CLOSE+1: + case CLOSE+2: + case CLOSE+3: + case CLOSE+4: + case CLOSE+5: + case CLOSE+6: + case CLOSE+7: + case CLOSE+8: + case CLOSE+9: + { + register int no; + register char *save; + + no = OP(scan) - CLOSE; + save = reginput; + + if (regmatch(next)) { + /* + * Don't set endp if some later + * invocation of the same parentheses + * already has. + */ + if (regendp[no] == NULL) + regendp[no] = save; + return(1); + } else + return(0); + } + break; + case BRANCH: { + register char *save; + + if (OP(next) != BRANCH) /* No choice. */ + next = OPERAND(scan); /* Avoid recursion. */ + else { + do { + save = reginput; + if (regmatch(OPERAND(scan))) + return(1); + reginput = save; + scan = regnext(scan); + } while (scan != NULL && OP(scan) == BRANCH); + return(0); + /* NOTREACHED */ + } + } + break; + case STAR: + case PLUS: { + register char nextch; + register int no; + register char *save; + register int min; + + /* + * Lookahead to avoid useless match attempts + * when we know what character comes next. + */ + nextch = '\0'; + if (OP(next) == EXACTLY) + nextch = *OPERAND(next); + min = (OP(scan) == STAR) ? 0 : 1; + save = reginput; + no = regrepeat(OPERAND(scan)); + while (no >= min) { + /* If it could work, try it. */ + if (nextch == '\0' || *reginput == nextch) + if (regmatch(next)) + return(1); + /* Couldn't or didn't -- back up. */ + no--; + reginput = save + no; + } + return(0); + } + break; + case END: + return(1); /* Success! */ + break; + default: + printk("<3>Regexp: memory corruption\n"); + return(0); + break; + } + + scan = next; + } + + /* + * We get here only if there's trouble -- normally "case END" is + * the terminating point. + */ + printk("<3>Regexp: corrupted pointers\n"); + return(0); +} + +/* + - regrepeat - repeatedly match something simple, report how many + */ +static int +regrepeat(char *p) +{ + register int count = 0; + register char *scan; + register char *opnd; + + scan = reginput; + opnd = OPERAND(p); + switch (OP(p)) { + case ANY: + count = strlen(scan); + scan += count; + break; + case EXACTLY: + while (*opnd == *scan) { + count++; + scan++; + } + break; + case ANYOF: + while (*scan != '\0' && strchr(opnd, *scan) != NULL) { + count++; + scan++; + } + break; + case ANYBUT: + while (*scan != '\0' && strchr(opnd, *scan) == NULL) { + count++; + scan++; + } + break; + default: /* Oh dear. Called inappropriately. */ + printk("<3>Regexp: internal foulup\n"); + count = 0; /* Best compromise. */ + break; + } + reginput = scan; + + return(count); +} + +/* + - regnext - dig the "next" pointer out of a node + */ +static char* +regnext(char *p) +{ + register int offset; + + if (p == ®dummy) + return(NULL); + + offset = NEXT(p); + if (offset == 0) + return(NULL); + + if (OP(p) == BACK) + return(p-offset); + else + return(p+offset); +} + +#ifdef DEBUG + +STATIC char *regprop(); + +/* + - regdump - dump a regexp onto stdout in vaguely comprehensible form + */ +void +regdump(regexp *r) +{ + register char *s; + register char op = EXACTLY; /* Arbitrary non-END op. */ + register char *next; + /* extern char *strchr(); */ + + + s = r->program + 1; + while (op != END) { /* While that wasn't END last time... */ + op = OP(s); + printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */ + next = regnext(s); + if (next == NULL) /* Next ptr. */ + printf("(0)"); + else + printf("(%d)", (s-r->program)+(next-s)); + s += 3; + if (op == ANYOF || op == ANYBUT || op == EXACTLY) { + /* Literal string, where present. */ + while (*s != '\0') { + putchar(*s); + s++; + } + s++; + } + putchar('\n'); + } + + /* Header fields of interest. */ + if (r->regstart != '\0') + printf("start `%c' ", r->regstart); + if (r->reganch) + printf("anchored "); + if (r->regmust != NULL) + printf("must have \"%s\"", r->regmust); + printf("\n"); +} + +/* + - regprop - printable representation of opcode + */ +static char * +regprop(char *op) +{ +#define BUFLEN 50 + register char *p; + static char buf[BUFLEN]; + + strcpy(buf, ":"); + + switch (OP(op)) { + case BOL: + p = "BOL"; + break; + case EOL: + p = "EOL"; + break; + case ANY: + p = "ANY"; + break; + case ANYOF: + p = "ANYOF"; + break; + case ANYBUT: + p = "ANYBUT"; + break; + case BRANCH: + p = "BRANCH"; + break; + case EXACTLY: + p = "EXACTLY"; + break; + case NOTHING: + p = "NOTHING"; + break; + case BACK: + p = "BACK"; + break; + case END: + p = "END"; + break; + case OPEN+1: + case OPEN+2: + case OPEN+3: + case OPEN+4: + case OPEN+5: + case OPEN+6: + case OPEN+7: + case OPEN+8: + case OPEN+9: + snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "OPEN%d", OP(op)-OPEN); + p = NULL; + break; + case CLOSE+1: + case CLOSE+2: + case CLOSE+3: + case CLOSE+4: + case CLOSE+5: + case CLOSE+6: + case CLOSE+7: + case CLOSE+8: + case CLOSE+9: + snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "CLOSE%d", OP(op)-CLOSE); + p = NULL; + break; + case STAR: + p = "STAR"; + break; + case PLUS: + p = "PLUS"; + break; + default: + printk("<3>Regexp: corrupted opcode\n"); + break; + } + if (p != NULL) + strncat(buf, p, BUFLEN-strlen(buf)); + return(buf); +} +#endif + + diff --git a/release/src/linux/linux/net/ipv4/netfilter/regexp/regexp.h b/release/src/linux/linux/net/ipv4/netfilter/regexp/regexp.h new file mode 100644 index 00000000..fda9a7c4 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/regexp/regexp.h @@ -0,0 +1,40 @@ +/* + * Definitions etc. for regexp(3) routines. + * + * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], + * not the System V one. + */ + +#ifndef REGEXP_H +#define REGEXP_H + +/* +http://www.opensource.apple.com/darwinsource/10.3/expect-1/expect/expect.h , +which contains a version of this library, says: + + * + * NSUBEXP must be at least 10, and no greater than 117 or the parser + * will not work properly. + * + +However, it looks rather like this library is limited to 10. If you think +otherwise, let us know. +*/ + +#define NSUBEXP 10 +typedef struct regexp { + char *startp[NSUBEXP]; + char *endp[NSUBEXP]; + char regstart; /* Internal use only. */ + char reganch; /* Internal use only. */ + char *regmust; /* Internal use only. */ + int regmlen; /* Internal use only. */ + char program[1]; /* Unwarranted chumminess with compiler. */ +} regexp; + +regexp * regcomp(char *exp, int *patternsize); +int regexec(regexp *prog, char *string); +void regsub(regexp *prog, char *source, char *dest); +void regerror(char *s); + +#endif diff --git a/release/src/linux/linux/net/ipv4/netfilter/regexp/regmagic.h b/release/src/linux/linux/net/ipv4/netfilter/regexp/regmagic.h new file mode 100644 index 00000000..5acf4478 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/regexp/regmagic.h @@ -0,0 +1,5 @@ +/* + * The first byte of the regexp internal "program" is actually this magic + * number; the start node begins in the second byte. + */ +#define MAGIC 0234 diff --git a/release/src/linux/linux/net/ipv4/netfilter/regexp/regsub.c b/release/src/linux/linux/net/ipv4/netfilter/regexp/regsub.c new file mode 100644 index 00000000..339631f0 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/regexp/regsub.c @@ -0,0 +1,95 @@ +/* + * regsub + * @(#)regsub.c 1.3 of 2 April 86 + * + * Copyright (c) 1986 by University of Toronto. + * Written by Henry Spencer. Not derived from licensed software. + * + * Permission is granted to anyone to use this software for any + * purpose on any computer system, and to redistribute it freely, + * subject to the following restrictions: + * + * 1. The author is not responsible for the consequences of use of + * this software, no matter how awful, even if they arise + * from defects in it. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. + * + * 3. Altered versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * + * This code was modified by Ethan Sommer to work within the kernel + * (it now uses kmalloc etc..) + * + */ +#include "regexp.h" +#include "regmagic.h" +#include <linux/string.h> + + +#ifndef CHARBITS +#define UCHARAT(p) ((int)*(unsigned char *)(p)) +#else +#define UCHARAT(p) ((int)*(p)&CHARBITS) +#endif + +#if 0 +//void regerror(char * s) +//{ +// printk("regexp(3): %s", s); +// /* NOTREACHED */ +//} +#endif + +/* + - regsub - perform substitutions after a regexp match + */ +void +regsub(regexp * prog, char * source, char * dest) +{ + register char *src; + register char *dst; + register char c; + register int no; + register int len; + + /* Not necessary and gcc doesn't like it -MLS */ + /*extern char *strncpy();*/ + + if (prog == NULL || source == NULL || dest == NULL) { + regerror("NULL parm to regsub"); + return; + } + if (UCHARAT(prog->program) != MAGIC) { + regerror("damaged regexp fed to regsub"); + return; + } + + src = source; + dst = dest; + while ((c = *src++) != '\0') { + if (c == '&') + no = 0; + else if (c == '\\' && '0' <= *src && *src <= '9') + no = *src++ - '0'; + else + no = -1; + + if (no < 0) { /* Ordinary character. */ + if (c == '\\' && (*src == '\\' || *src == '&')) + c = *src++; + *dst++ = c; + } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) { + len = prog->endp[no] - prog->startp[no]; + (void) strncpy(dst, prog->startp[no], len); + dst += len; + if (len != 0 && *(dst-1) == '\0') { /* strncpy hit NUL. */ + regerror("damaged match string"); + return; + } + } + } + *dst++ = '\0'; +} diff --git a/release/src/linux/linux/net/ipv4/netfilter/tomato_ct.c b/release/src/linux/linux/net/ipv4/netfilter/tomato_ct.c new file mode 100644 index 00000000..a84cab09 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/tomato_ct.c @@ -0,0 +1,181 @@ +/* + + tomato_ct.c + Copyright (C) 2006 Jonathan Zarate + + Licensed under GNU GPL v2. + +*/ +#include <linux/module.h> +#include <linux/proc_fs.h> +#include <linux/netfilter_ipv4/ip_conntrack.h> +#include <linux/netfilter_ipv4/ip_conntrack_core.h> + +// #define TEST_HASHDIST + + +#ifdef TEST_HASHDIST +static int hashdist_read(char *buffer, char **start, off_t offset, int length, int *eof, void *data) +{ + struct list_head *h; + struct list_head *e; + int i; + int n; + int count; + char *buf; + int max; + + // do this the easy way... + max = ip_conntrack_htable_size * sizeof("12345\t12345\n"); + buf = kmalloc(max + 1, GFP_KERNEL); + if (buf == NULL) return 0; + + n = 0; + max -= sizeof("12345\t12345\n"); + + READ_LOCK(&ip_conntrack_lock); + + for (i = 0; i < ip_conntrack_htable_size; ++i) { + count = 0; + h = &ip_conntrack_hash[i]; + if (h) { + e = h; + while (e->next != h) { + ++count; + e = e->next; + } + } + + n += sprintf(buf + n, "%d\t%d\n", i, count); + if (n > max) { + printk("hashdist: %d > %d\n", n, max); + break; + } + } + + READ_UNLOCK(&ip_conntrack_lock); + + if (offset < n) { + n = n - offset; + if (n > length) { + n = length; + *eof = 0; + } + else { + *eof = 1; + } + memcpy(buffer, buf + offset, n); + *start = buffer; + } + else { + n = 0; + *eof = 1; + } + + kfree(buf); + return n; +} +#endif + + +static void interate_all(void (*func)(struct ip_conntrack *, unsigned long), unsigned long data) +{ + int i; + struct list_head *h; + struct list_head *e; + + WRITE_LOCK(&ip_conntrack_lock); + for (i = 0; i < ip_conntrack_htable_size; ++i) { + h = &ip_conntrack_hash[i]; + if (h) { + e = h; + while (e->next != h) { + e = e->next; + func(((struct ip_conntrack_tuple_hash *)e)->ctrack, data); + } + } + } + WRITE_UNLOCK(&ip_conntrack_lock); +} + +static void expireearly(struct ip_conntrack *ct, unsigned long data) +{ + if (ct->timeout.expires > data) { + if (del_timer(&ct->timeout)) { + ct->timeout.expires = data; + add_timer(&ct->timeout); + } + } +} + +static int expireearly_write(struct file *file, const char *buffer, unsigned long length, void *data) +{ + char s[8]; + unsigned long n; + + if ((length > 0) && (length < 6)) { + memcpy(s, buffer, length); + s[length] = 0; + n = simple_strtoul(s, NULL, 10); + if (n < 10) n = 10; + else if (n > 86400) n = 86400; + + interate_all(expireearly, jiffies + (n * HZ)); + } + +/* + if ((length > 0) && (buffer[0] == '1')) { + interate_all(expireearly, jiffies + (20 * HZ)); + } +*/ + + return length; +} + + +static void clearmarks(struct ip_conntrack *ct, unsigned long data) +{ + ct->mark = 0; +} + +static int clearmarks_write(struct file *file, const char *buffer, unsigned long length, void *data) +{ + if ((length > 0) && (buffer[0] == '1')) { + interate_all(clearmarks, 0); + } + return length; +} + +static int __init init(void) +{ + struct proc_dir_entry *p; + + printk(__FILE__ " [" __DATE__ " " __TIME__ "]\n"); + +#ifdef TEST_HASHDIST + p = create_proc_entry("hash_dist", 0400, proc_net); + if (p) p->read_proc = hashdist_read; +#endif + + p = create_proc_entry("expire_early", 0200, proc_net); + if (p) p->write_proc = expireearly_write; + + p = create_proc_entry("clear_marks", 0200, proc_net); + if (p) p->write_proc = clearmarks_write; +
+ return 0; +} + +static void __exit fini(void) +{ +#ifdef TEST_HASHDIST + remove_proc_entry("hash_dist", proc_net); +#endif + remove_proc_entry("expire_early", proc_net); + remove_proc_entry("clear_marks", proc_net); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); diff --git a/release/src/linux/linux/net/ipv4/route.c b/release/src/linux/linux/net/ipv4/route.c index dfae0871..f3cf20df 100644 --- a/release/src/linux/linux/net/ipv4/route.c +++ b/release/src/linux/linux/net/ipv4/route.c @@ -2465,6 +2465,7 @@ void __init ip_rt_init(void) panic("IP: failed to allocate ip_dst_cache\n"); goal = num_physpages >> (26 - PAGE_SHIFT); +// goal = num_physpages >> (21 - PAGE_SHIFT); for (order = 0; (1UL << order) < goal; order++) /* NOTHING */; @@ -2494,9 +2495,18 @@ void __init ip_rt_init(void) rt_hash_table[i].chain = NULL; } +// ip_rt_max_size = (rt_hash_mask + 1) * 2; +// ipv4_dst_ops.gc_thresh = (ip_rt_max_size / 4); + ipv4_dst_ops.gc_thresh = (rt_hash_mask + 1); ip_rt_max_size = (rt_hash_mask + 1) * 16; +// printk("gc_thresh=%d\n", ipv4_dst_ops.gc_thresh); +// printk("ip_rt_max_size=%d\n", ip_rt_max_size); +// printk("rt_hash_mask=%d\n", rt_hash_mask); +// printk("goal=%d\n", goal); + + devinet_init(); ip_fib_init(); diff --git a/release/src/linux/linux/net/ipv4/sysctl_net_ipv4.c b/release/src/linux/linux/net/ipv4/sysctl_net_ipv4.c index 1f4081a9..7fe16445 100644 --- a/release/src/linux/linux/net/ipv4/sysctl_net_ipv4.c +++ b/release/src/linux/linux/net/ipv4/sysctl_net_ipv4.c @@ -221,6 +221,18 @@ ctl_table ipv4_table[] = { &sysctl_icmp_ratemask, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_TCP_TW_REUSE, "tcp_tw_reuse", &sysctl_tcp_tw_reuse, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_TCP_VEGAS, "tcp_vegas_cong_avoid", + &sysctl_tcp_vegas_cong_avoid, sizeof(int), 0644, NULL, + &proc_dointvec}, + {NET_TCP_VEGAS_ALPHA, "tcp_vegas_alpha", + &sysctl_tcp_vegas_alpha, sizeof(int), 0644, NULL, + &proc_dointvec}, + {NET_TCP_VEGAS_BETA, "tcp_vegas_beta", + &sysctl_tcp_vegas_beta, sizeof(int), 0644, NULL, + &proc_dointvec}, + {NET_TCP_VEGAS_GAMMA, "tcp_vegas_gamma", + &sysctl_tcp_vegas_gamma, sizeof(int), 0644, NULL, + &proc_dointvec}, {0} }; diff --git a/release/src/linux/linux/net/ipv4/tcp_input.c b/release/src/linux/linux/net/ipv4/tcp_input.c index 8c99dd52..243e2991 100644 --- a/release/src/linux/linux/net/ipv4/tcp_input.c +++ b/release/src/linux/linux/net/ipv4/tcp_input.c @@ -87,6 +87,16 @@ int sysctl_tcp_stdurg = 0; int sysctl_tcp_rfc1337 = 0; int sysctl_tcp_max_orphans = NR_FILE; +int sysctl_tcp_vegas_cong_avoid = 0; + +/* Default values of the Vegas variables, in fixed-point representation + * with V_PARAM_SHIFT bits to the right of the binary point. + */ +#define V_PARAM_SHIFT 1 +int sysctl_tcp_vegas_alpha = 1<<V_PARAM_SHIFT; +int sysctl_tcp_vegas_beta = 3<<V_PARAM_SHIFT; +int sysctl_tcp_vegas_gamma = 1<<V_PARAM_SHIFT; + #define FLAG_DATA 0x01 /* Incoming frame contained data. */ #define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ #define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */ @@ -399,6 +409,42 @@ static void tcp_event_data_recv(struct sock *sk, struct tcp_opt *tp, struct sk_b tcp_grow_window(sk, tp, skb); } +/* Set up a new TCP connection, depending on whether it should be + * using Vegas or not. + */ +void tcp_vegas_init(struct tcp_opt *tp) +{ + if (sysctl_tcp_vegas_cong_avoid) { + tp->vegas.do_vegas = 1; + tp->vegas.baseRTT = 0x7fffffff; + tcp_vegas_enable(tp); + } else + tcp_vegas_disable(tp); +} + +/* Do RTT sampling needed for Vegas. + * Basically we: + * o min-filter RTT samples from within an RTT to get the current + * propagation delay + queuing delay (we are min-filtering to try to + * avoid the effects of delayed ACKs) + * o min-filter RTT samples from a much longer window (forever for now) + * to find the propagation delay (baseRTT) + */ +static inline void vegas_rtt_calc(struct tcp_opt *tp, __u32 rtt) +{ + __u32 vrtt = rtt + 1; /* Never allow zero rtt or baseRTT */ + + /* Filter to find propagation delay: */ + if (vrtt < tp->vegas.baseRTT) + tp->vegas.baseRTT = vrtt; + + /* Find the min RTT during the last RTT to find + * the current prop. delay + queuing delay: + */ + tp->vegas.minRTT = min(tp->vegas.minRTT, vrtt); + tp->vegas.cntRTT++; +} + /* Called to compute a smoothed rtt estimate. The data fed to this * routine either comes from timestamps, or from segments that were * known _not_ to have been retransmitted [see Karn/Partridge @@ -412,6 +458,9 @@ static __inline__ void tcp_rtt_estimator(struct tcp_opt *tp, __u32 mrtt) { long m = mrtt; /* RTT */ + if (tcp_vegas_enabled(tp)) + vegas_rtt_calc(tp, mrtt); + /* The following amusing code comes from Jacobson's * article in SIGCOMM '88. Note that rtt and mdev * are scaled versions of rtt and mean deviation. @@ -1013,7 +1062,7 @@ void tcp_enter_loss(struct sock *sk, int how) tcp_sync_left_out(tp); tp->reordering = min_t(unsigned int, tp->reordering, sysctl_tcp_reordering); - tp->ca_state = TCP_CA_Loss; + tcp_set_ca_state(tp, TCP_CA_Loss); tp->high_seq = tp->snd_nxt; TCP_ECN_queue_cwr(tp); } @@ -1375,7 +1424,7 @@ static int tcp_try_undo_recovery(struct sock *sk, struct tcp_opt *tp) tcp_moderate_cwnd(tp); return 1; } - tp->ca_state = TCP_CA_Open; + tcp_set_ca_state(tp, TCP_CA_Open); return 0; } @@ -1435,7 +1484,7 @@ static int tcp_try_undo_loss(struct sock *sk, struct tcp_opt *tp) tp->retransmits = 0; tp->undo_marker = 0; if (!IsReno(tp)) - tp->ca_state = TCP_CA_Open; + tcp_set_ca_state(tp, TCP_CA_Open); return 1; } return 0; @@ -1466,7 +1515,7 @@ static void tcp_try_to_open(struct sock *sk, struct tcp_opt *tp, int flag) state = TCP_CA_Disorder; if (tp->ca_state != state) { - tp->ca_state = state; + tcp_set_ca_state(tp, state); tp->high_seq = tp->snd_nxt; } tcp_moderate_cwnd(tp); @@ -1540,7 +1589,7 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una, * is ACKed for CWR bit to reach receiver. */ if (tp->snd_una != tp->high_seq) { tcp_complete_cwr(tp); - tp->ca_state = TCP_CA_Open; + tcp_set_ca_state(tp, TCP_CA_Open); } break; @@ -1551,7 +1600,7 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una, * catching for all duplicate ACKs. */ IsReno(tp) || tp->snd_una != tp->high_seq) { tp->undo_marker = 0; - tp->ca_state = TCP_CA_Open; + tcp_set_ca_state(tp, TCP_CA_Open); } break; @@ -1625,7 +1674,7 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una, } tp->snd_cwnd_cnt = 0; - tp->ca_state = TCP_CA_Recovery; + tcp_set_ca_state(tp, TCP_CA_Recovery); } if (is_dupack || tcp_head_timedout(sk, tp)) @@ -1696,7 +1745,7 @@ tcp_ack_update_rtt(struct tcp_opt *tp, int flag, s32 seq_rtt) /* This is Jacobson's slow start and congestion avoidance. * SIGCOMM '88, p. 328. */ -static __inline__ void tcp_cong_avoid(struct tcp_opt *tp) +static __inline__ void reno_cong_avoid(struct tcp_opt *tp) { if (tp->snd_cwnd <= tp->snd_ssthresh) { /* In "safe" area, increase. */ @@ -1716,6 +1765,236 @@ static __inline__ void tcp_cong_avoid(struct tcp_opt *tp) tp->snd_cwnd_stamp = tcp_time_stamp; } +/* This is based on the congestion detection/avoidance scheme described in + * Lawrence S. Brakmo and Larry L. Peterson. + * "TCP Vegas: End to end congestion avoidance on a global internet." + * IEEE Journal on Selected Areas in Communication, 13(8):1465--1480, + * October 1995. Available from: + * ftp://ftp.cs.arizona.edu/xkernel/Papers/jsac.ps + * + * See http://www.cs.arizona.edu/xkernel/ for their implementation. + * The main aspects that distinguish this implementation from the + * Arizona Vegas implementation are: + * o We do not change the loss detection or recovery mechanisms of + * Linux in any way. Linux already recovers from losses quite well, + * using fine-grained timers, NewReno, and FACK. + * o To avoid the performance penalty imposed by increasing cwnd + * only every-other RTT during slow start, we increase during + * every RTT during slow start, just like Reno. + * o Largely to allow continuous cwnd growth during slow start, + * we use the rate at which ACKs come back as the "actual" + * rate, rather than the rate at which data is sent. + * o To speed convergence to the right rate, we set the cwnd + * to achieve the right ("actual") rate when we exit slow start. + * o To filter out the noise caused by delayed ACKs, we use the + * minimum RTT sample observed during the last RTT to calculate + * the actual rate. + * o When the sender re-starts from idle, it waits until it has + * received ACKs for an entire flight of new data before making + * a cwnd adjustment decision. The original Vegas implementation + * assumed senders never went idle. + */ +static void vegas_cong_avoid(struct tcp_opt *tp, u32 ack, u32 seq_rtt) +{ + /* The key players are v_beg_snd_una and v_beg_snd_nxt. + * + * These are so named because they represent the approximate values + * of snd_una and snd_nxt at the beginning of the current RTT. More + * precisely, they represent the amount of data sent during the RTT. + * At the end of the RTT, when we receive an ACK for v_beg_snd_nxt, + * we will calculate that (v_beg_snd_nxt - v_beg_snd_una) outstanding + * bytes of data have been ACKed during the course of the RTT, giving + * an "actual" rate of: + * + * (v_beg_snd_nxt - v_beg_snd_una) / (rtt duration) + * + * Unfortunately, v_beg_snd_una is not exactly equal to snd_una, + * because delayed ACKs can cover more than one segment, so they + * don't line up nicely with the boundaries of RTTs. + * + * Another unfortunate fact of life is that delayed ACKs delay the + * advance of the left edge of our send window, so that the number + * of bytes we send in an RTT is often less than our cwnd will allow. + * So we keep track of our cwnd separately, in v_beg_snd_cwnd. + */ + + if (after(ack, tp->vegas.beg_snd_nxt)) { + /* Do the Vegas once-per-RTT cwnd adjustment. */ + u32 old_wnd, old_snd_cwnd; + + + /* Here old_wnd is essentially the window of data that was + * sent during the previous RTT, and has all + * been acknowledged in the course of the RTT that ended + * with the ACK we just received. Likewise, old_snd_cwnd + * is the cwnd during the previous RTT. + */ + old_wnd = (tp->vegas.beg_snd_nxt - tp->vegas.beg_snd_una) / + tp->mss_cache; + old_snd_cwnd = tp->vegas.beg_snd_cwnd; + + /* Save the extent of the current window so we can use this + * at the end of the next RTT. + */ + tp->vegas.beg_snd_una = tp->vegas.beg_snd_nxt; + tp->vegas.beg_snd_nxt = tp->snd_nxt; + tp->vegas.beg_snd_cwnd = tp->snd_cwnd; + + /* Take into account the current RTT sample too, to + * decrease the impact of delayed acks. This double counts + * this sample since we count it for the next window as well, + * but that's not too awful, since we're taking the min, + * rather than averaging. + */ + vegas_rtt_calc(tp, seq_rtt); + + /* We do the Vegas calculations only if we got enough RTT + * samples that we can be reasonably sure that we got + * at least one RTT sample that wasn't from a delayed ACK. + * If we only had 2 samples total, + * then that means we're getting only 1 ACK per RTT, which + * means they're almost certainly delayed ACKs. + * If we have 3 samples, we should be OK. + */ + + if (tp->vegas.cntRTT <= 2) { + /* We don't have enough RTT samples to do the Vegas + * calculation, so we'll behave like Reno. + */ + if (tp->snd_cwnd > tp->snd_ssthresh) + tp->snd_cwnd++; + } else { + u32 rtt, target_cwnd, diff; + + /* We have enough RTT samples, so, using the Vegas + * algorithm, we determine if we should increase or + * decrease cwnd, and by how much. + */ + + /* Pluck out the RTT we are using for the Vegas + * calculations. This is the min RTT seen during the + * last RTT. Taking the min filters out the effects + * of delayed ACKs, at the cost of noticing congestion + * a bit later. + */ + rtt = tp->vegas.minRTT; + + /* Calculate the cwnd we should have, if we weren't + * going too fast. + * + * This is: + * (actual rate in segments) * baseRTT + * We keep it as a fixed point number with + * V_PARAM_SHIFT bits to the right of the binary point. + */ + target_cwnd = ((old_wnd * tp->vegas.baseRTT) + << V_PARAM_SHIFT) / rtt; + + /* Calculate the difference between the window we had, + * and the window we would like to have. This quantity + * is the "Diff" from the Arizona Vegas papers. + * + * Again, this is a fixed point number with + * V_PARAM_SHIFT bits to the right of the binary + * point. + */ + diff = (old_wnd << V_PARAM_SHIFT) - target_cwnd; + + if (tp->snd_cwnd < tp->snd_ssthresh) { + /* Slow start. */ + if (diff > sysctl_tcp_vegas_gamma) { + /* Going too fast. Time to slow down + * and switch to congestion avoidance. + */ + tp->snd_ssthresh = 2; + + /* Set cwnd to match the actual rate + * exactly: + * cwnd = (actual rate) * baseRTT + * Then we add 1 because the integer + * truncation robs us of full link + * utilization. + */ + tp->snd_cwnd = min(tp->snd_cwnd, + (target_cwnd >> + V_PARAM_SHIFT)+1); + + } + } else { + /* Congestion avoidance. */ + u32 next_snd_cwnd; + + /* Figure out where we would like cwnd + * to be. + */ + if (diff > sysctl_tcp_vegas_beta) { + /* The old window was too fast, so + * we slow down. + */ + next_snd_cwnd = old_snd_cwnd - 1; + } else if (diff < sysctl_tcp_vegas_alpha) { + /* We don't have enough extra packets + * in the network, so speed up. + */ + next_snd_cwnd = old_snd_cwnd + 1; + } else { + /* Sending just as fast as we + * should be. + */ + next_snd_cwnd = old_snd_cwnd; + } + + /* Adjust cwnd upward or downward, toward the + * desired value. + */ + if (next_snd_cwnd > tp->snd_cwnd) + tp->snd_cwnd++; + else if (next_snd_cwnd < tp->snd_cwnd) + tp->snd_cwnd--; + } + } + + /* Wipe the slate clean for the next RTT. */ + tp->vegas.cntRTT = 0; + tp->vegas.minRTT = 0x7fffffff; + } + + /* The following code is executed for every ack we receive, + * except for conditions checked in should_advance_cwnd() + * before the call to tcp_cong_avoid(). Mainly this means that + * we only execute this code if the ack actually acked some + * data. + */ + + /* If we are in slow start, increase our cwnd in response to this ACK. + * (If we are not in slow start then we are in congestion avoidance, + * and adjust our congestion window only once per RTT. See the code + * above.) + */ + if (tp->snd_cwnd <= tp->snd_ssthresh) + tp->snd_cwnd++; + + /* to keep cwnd from growing without bound */ + tp->snd_cwnd = min_t(u32, tp->snd_cwnd, tp->snd_cwnd_clamp); + + /* Make sure that we are never so timid as to reduce our cwnd below + * 2 MSS. + * + * Going below 2 MSS would risk huge delayed ACKs from our receiver. + */ + tp->snd_cwnd = max(tp->snd_cwnd, 2U); + + tp->snd_cwnd_stamp = tcp_time_stamp; +} + +static inline void tcp_cong_avoid(struct tcp_opt *tp, u32 ack, u32 seq_rtt) +{ + if (tcp_vegas_enabled(tp)) + vegas_cong_avoid(tp, ack, seq_rtt); + else + reno_cong_avoid(tp); +} + /* Restart timer after forward progress on connection. * RFC2988 recommends to restart timer to now+rto. */ @@ -1730,7 +2009,7 @@ static __inline__ void tcp_ack_packets_out(struct sock *sk, struct tcp_opt *tp) } /* Remove acknowledged frames from the retransmission queue. */ -static int tcp_clean_rtx_queue(struct sock *sk) +static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); struct sk_buff *skb; @@ -1813,6 +2092,7 @@ static int tcp_clean_rtx_queue(struct sock *sk) } } #endif + *seq_rtt_p = seq_rtt; return acked; } @@ -1900,6 +2180,7 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag) u32 ack_seq = TCP_SKB_CB(skb)->seq; u32 ack = TCP_SKB_CB(skb)->ack_seq; u32 prior_in_flight; + s32 seq_rtt; int prior_packets; /* If the ack is newer than sent or older than previous acks @@ -1947,17 +2228,19 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag) prior_in_flight = tcp_packets_in_flight(tp); /* See if we can take anything off of the retransmit queue. */ - flag |= tcp_clean_rtx_queue(sk); + flag |= tcp_clean_rtx_queue(sk, &seq_rtt); if (tcp_ack_is_dubious(tp, flag)) { /* Advanve CWND, if state allows this. */ - if ((flag&FLAG_DATA_ACKED) && prior_in_flight >= tp->snd_cwnd && + if ((flag&FLAG_DATA_ACKED) && + (tcp_vegas_enabled(tp) || prior_in_flight >= tp->snd_cwnd) && tcp_may_raise_cwnd(tp, flag)) - tcp_cong_avoid(tp); + tcp_cong_avoid(tp, ack, seq_rtt); tcp_fastretrans_alert(sk, prior_snd_una, prior_packets, flag); } else { - if ((flag&FLAG_DATA_ACKED) && prior_in_flight >= tp->snd_cwnd) - tcp_cong_avoid(tp); + if ((flag & FLAG_DATA_ACKED) && + (tcp_vegas_enabled(tp) || prior_in_flight >= tp->snd_cwnd)) + tcp_cong_avoid(tp, ack, seq_rtt); } if ((flag & FLAG_FORWARD_PROGRESS) || !(flag&FLAG_NOT_DUP)) diff --git a/release/src/linux/linux/net/ipv4/tcp_minisocks.c b/release/src/linux/linux/net/ipv4/tcp_minisocks.c index b69cc32c..6fdb7681 100644 --- a/release/src/linux/linux/net/ipv4/tcp_minisocks.c +++ b/release/src/linux/linux/net/ipv4/tcp_minisocks.c @@ -715,7 +715,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, newtp->snd_cwnd = 2; newtp->snd_cwnd_cnt = 0; - newtp->ca_state = TCP_CA_Open; + tcp_set_ca_state(newtp, TCP_CA_Open); tcp_init_xmit_timers(newsk); skb_queue_head_init(&newtp->out_of_order_queue); newtp->send_head = NULL; @@ -783,6 +783,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, newtp->mss_clamp = req->mss; TCP_ECN_openreq_child(newtp, req); + tcp_vegas_init(newtp); TCP_INC_STATS_BH(TcpPassiveOpens); } return newsk; diff --git a/release/src/linux/linux/net/ipv4/tcp_output.c b/release/src/linux/linux/net/ipv4/tcp_output.c index 35cbbbf7..3fd4871f 100644 --- a/release/src/linux/linux/net/ipv4/tcp_output.c +++ b/release/src/linux/linux/net/ipv4/tcp_output.c @@ -105,6 +105,9 @@ static void tcp_cwnd_restart(struct tcp_opt *tp) u32 restart_cwnd = tcp_init_cwnd(tp); u32 cwnd = tp->snd_cwnd; + if (tcp_is_vegas(tp)) + tcp_vegas_enable(tp); + tp->snd_ssthresh = tcp_current_ssthresh(tp); restart_cwnd = min(restart_cwnd, cwnd); @@ -223,6 +226,19 @@ int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb) tcp_header_size += (TCPOLEN_SACK_BASE_ALIGNED + (tp->eff_sacks * TCPOLEN_SACK_PERBLOCK)); } + + /* + * If the connection is idle and we are restarting, + * then we don't want to do any Vegas calculations + * until we get fresh RTT samples. So when we + * restart, we reset our Vegas state to a clean + * slate. After we get acks for this flight of + * packets, _then_ we can make Vegas calculations + * again. + */ + if (tcp_is_vegas(tp) && tcp_packets_in_flight(tp) == 0) + tcp_vegas_enable(tp); + th = (struct tcphdr *) skb_push(skb, tcp_header_size); skb->h.th = th; skb_set_owner_w(skb, sk); @@ -800,7 +816,7 @@ void tcp_simple_retransmit(struct sock *sk) tp->snd_ssthresh = tcp_current_ssthresh(tp); tp->prior_ssthresh = 0; tp->undo_marker = 0; - tp->ca_state = TCP_CA_Loss; + tcp_set_ca_state(tp, TCP_CA_Loss); } tcp_xmit_retransmit_queue(sk); } @@ -1181,6 +1197,7 @@ static inline void tcp_connect_init(struct sock *sk) tp->window_clamp = dst->window; tp->advmss = dst->advmss; tcp_initialize_rcv_mss(sk); + tcp_vegas_init(tp); tcp_select_initial_window(tcp_full_space(sk), tp->advmss - (tp->ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0), @@ -1231,6 +1248,7 @@ int tcp_connect(struct sock *sk) TCP_SKB_CB(buff)->end_seq = tp->write_seq; tp->snd_nxt = tp->write_seq; tp->pushed_seq = tp->write_seq; + tcp_vegas_init(tp); /* Send it off. */ TCP_SKB_CB(buff)->when = tcp_time_stamp; diff --git a/release/src/linux/linux/net/ipv6/netfilter/Config.in b/release/src/linux/linux/net/ipv6/netfilter/Config.in index 062ed247..5d2dac2f 100644 --- a/release/src/linux/linux/net/ipv6/netfilter/Config.in +++ b/release/src/linux/linux/net/ipv6/netfilter/Config.in @@ -17,6 +17,7 @@ tristate 'IP6 tables support (required for filtering/masq/NAT)' CONFIG_IP6_NF_IP if [ "$CONFIG_IP6_NF_IPTABLES" != "n" ]; then # The simple matches. dep_tristate ' limit match support' CONFIG_IP6_NF_MATCH_LIMIT $CONFIG_IP6_NF_IPTABLES + dep_tristate ' condition match support' CONFIG_IP6_NF_MATCH_CONDITION $CONFIG_IP6_NF_IPTABLES dep_tristate ' MAC address match support' CONFIG_IP6_NF_MATCH_MAC $CONFIG_IP6_NF_IPTABLES dep_tristate ' Multiple port match support' CONFIG_IP6_NF_MATCH_MULTIPORT $CONFIG_IP6_NF_IPTABLES if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then @@ -55,6 +56,9 @@ if [ "$CONFIG_IP6_NF_IPTABLES" != "n" ]; then if [ "$CONFIG_IP6_NF_MANGLE" != "n" ]; then # dep_tristate ' TOS target support' CONFIG_IP6_NF_TARGET_TOS $CONFIG_IP_NF_MANGLE dep_tristate ' MARK target support' CONFIG_IP6_NF_TARGET_MARK $CONFIG_IP6_NF_MANGLE + dep_tristate ' ROUTE target support' CONFIG_IP6_NF_TARGET_ROUTE $CONFIG_IP6_NF_MANGLE + + dep_tristate ' IMQ target support' CONFIG_IP6_NF_TARGET_IMQ $CONFIG_IP6_NF_MANGLE fi #dep_tristate ' LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_IPTABLES fi diff --git a/release/src/linux/linux/net/ipv6/netfilter/Makefile b/release/src/linux/linux/net/ipv6/netfilter/Makefile index dfd36a89..2bd664f4 100644 --- a/release/src/linux/linux/net/ipv6/netfilter/Makefile +++ b/release/src/linux/linux/net/ipv6/netfilter/Makefile @@ -14,6 +14,7 @@ export-objs := ip6_tables.o # Link order matters here. obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o obj-$(CONFIG_IP6_NF_MATCH_LIMIT) += ip6t_limit.o +obj-$(CONFIG_IP6_NF_MATCH_CONDITION) += ip6t_condition.o obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o @@ -23,6 +24,8 @@ obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o +obj-$(CONFIG_IP6_NF_TARGET_ROUTE) += ip6t_ROUTE.o +obj-$(CONFIG_IP6_NF_TARGET_IMQ) += ip6t_IMQ.o obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o diff --git a/release/src/linux/linux/net/ipv6/netfilter/ip6_tables.c b/release/src/linux/linux/net/ipv6/netfilter/ip6_tables.c index b521af78..8eac7586 100644 --- a/release/src/linux/linux/net/ipv6/netfilter/ip6_tables.c +++ b/release/src/linux/linux/net/ipv6/netfilter/ip6_tables.c @@ -1241,13 +1241,7 @@ do_add_counters(void *user, unsigned int len) goto free; write_lock_bh(&t->lock); - /************************************* - * modify by tanghui @ 2006-10-11 - * for a RACE CONDITION in the "do_add_counters()" function - *************************************/ if (t->private->number != paddc->num_counters) { - if (t->private->number != tmp.num_counters) { - /*************************************/ ret = -EINVAL; goto unlock_up_free; } diff --git a/release/src/linux/linux/net/ipv6/netfilter/ip6t_IMQ.c b/release/src/linux/linux/net/ipv6/netfilter/ip6t_IMQ.c new file mode 100644 index 00000000..760d7447 --- /dev/null +++ b/release/src/linux/linux/net/ipv6/netfilter/ip6t_IMQ.c @@ -0,0 +1,78 @@ +/* This target marks packets to be enqueued to an imq device */ +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/netfilter_ipv6/ip6_tables.h> +#include <linux/netfilter_ipv6/ip6t_IMQ.h> +#include <linux/imq.h> + +static unsigned int imq_target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + struct ip6t_imq_info *mr = (struct ip6t_imq_info*)targinfo; + + (*pskb)->imq_flags = mr->todev | IMQ_F_ENQUEUE; + (*pskb)->nfcache |= NFC_ALTERED; + + return IP6T_CONTINUE; +} + +static int imq_checkentry(const char *tablename, + const struct ip6t_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + struct ip6t_imq_info *mr; + + if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_imq_info))) { + printk(KERN_WARNING "IMQ: invalid targinfosize\n"); + return 0; + } + mr = (struct ip6t_imq_info*)targinfo; + + if (strcmp(tablename, "mangle") != 0) { + printk(KERN_WARNING + "IMQ: IMQ can only be called from \"mangle\" table, not \"%s\"\n", + tablename); + return 0; + } + + if (mr->todev > IMQ_MAX_DEVS) { + printk(KERN_WARNING + "IMQ: invalid device specified, highest is %u\n", + IMQ_MAX_DEVS); + return 0; + } + + return 1; +} + +static struct ip6t_target ip6t_imq_reg = { + { NULL, NULL}, + "IMQ", + imq_target, + imq_checkentry, + NULL, + THIS_MODULE +}; + +static int __init init(void) +{ + if (ip6t_register_target(&ip6t_imq_reg)) + return -EINVAL; + + return 0; +} + +static void __exit fini(void) +{ + ip6t_unregister_target(&ip6t_imq_reg); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff --git a/release/src/linux/linux/net/ipv6/netfilter/ip6t_ROUTE.c b/release/src/linux/linux/net/ipv6/netfilter/ip6t_ROUTE.c new file mode 100644 index 00000000..bb6d11f8 --- /dev/null +++ b/release/src/linux/linux/net/ipv6/netfilter/ip6t_ROUTE.c @@ -0,0 +1,308 @@ +/* + * This implements the ROUTE v6 target, which enables you to setup unusual + * routes not supported by the standard kernel routing table. + * + * Copyright (C) 2003 Cedric de Launois <delaunois@info.ucl.ac.be> + * + * v 1.1 2004/11/23 + * + * This software is distributed under GNU GPL v2, 1991 + */ + +#include <linux/module.h> +#include <linux/skbuff.h> +#include <linux/ipv6.h> +#include <linux/netfilter_ipv6/ip6_tables.h> +#include <linux/netfilter_ipv6/ip6t_ROUTE.h> +#include <linux/netdevice.h> +#include <net/ipv6.h> +#include <net/ndisc.h> +#include <net/ip6_route.h> +#include <linux/icmpv6.h> + +#if 1 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +#define NIP6(addr) \ + ntohs((addr).s6_addr16[0]), \ + ntohs((addr).s6_addr16[1]), \ + ntohs((addr).s6_addr16[2]), \ + ntohs((addr).s6_addr16[3]), \ + ntohs((addr).s6_addr16[4]), \ + ntohs((addr).s6_addr16[5]), \ + ntohs((addr).s6_addr16[6]), \ + ntohs((addr).s6_addr16[7]) + +/* Route the packet according to the routing keys specified in + * route_info. Keys are : + * - ifindex : + * 0 if no oif preferred, + * otherwise set to the index of the desired oif + * - route_info->gw : + * 0 if no gateway specified, + * otherwise set to the next host to which the pkt must be routed + * If success, skb->dev is the output device to which the packet must + * be sent and skb->dst is not NULL + * + * RETURN: 1 if the packet was succesfully routed to the + * destination desired + * 0 if the kernel routing table could not route the packet + * according to the keys specified + */ +static int +route6(struct sk_buff *skb, + unsigned int ifindex, + const struct ip6t_route_target_info *route_info) +{ + struct rt6_info *rt = NULL; + struct ipv6hdr *ipv6h = skb->nh.ipv6h; + struct in6_addr *gw = (struct in6_addr*)&route_info->gw; + + DEBUGP("ip6t_ROUTE: called with: "); + DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr)); + DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(*gw)); + DEBUGP("OUT=%s\n", route_info->oif); + + if (ipv6_addr_any(gw)) + rt = rt6_lookup(&ipv6h->daddr, &ipv6h->saddr, ifindex, 1); + else + rt = rt6_lookup(gw, &ipv6h->saddr, ifindex, 1); + + if (!rt) + goto no_route; + + DEBUGP("ip6t_ROUTE: routing gives: "); + DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_dst.addr)); + DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_gateway)); + DEBUGP("OUT=%s\n", rt->rt6i_dev->name); + + if (ifindex && rt->rt6i_dev->ifindex!=ifindex) + goto wrong_route; + + if (!rt->rt6i_nexthop) { + DEBUGP("ip6t_ROUTE: discovering neighbour\n"); + rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_dst.addr); + } + + /* Drop old route. */ + dst_release(skb->dst); + skb->dst = &rt->u.dst; + skb->dev = rt->rt6i_dev; + return 1; + + wrong_route: + dst_release(&rt->u.dst); + no_route: + if (!net_ratelimit()) + return 0; + + printk("ip6t_ROUTE: no explicit route found "); + if (ifindex) + printk("via interface %s ", route_info->oif); + if (!ipv6_addr_any(gw)) + printk("via gateway %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", NIP6(*gw)); + printk("\n"); + return 0; +} + + +/* Stolen from ip6_output_finish + * PRE : skb->dev is set to the device we are leaving by + * skb->dst is not NULL + * POST: the packet is sent with the link layer header pushed + * the packet is destroyed + */ +static void ip_direct_send(struct sk_buff *skb) +{ + struct dst_entry *dst = skb->dst; + struct hh_cache *hh = dst->hh; + + if (hh) { + read_lock_bh(&hh->hh_lock); + memcpy(skb->data - 16, hh->hh_data, 16); + read_unlock_bh(&hh->hh_lock); + skb_push(skb, hh->hh_len); + hh->hh_output(skb); + } else if (dst->neighbour) + dst->neighbour->output(skb); + else { + if (net_ratelimit()) + DEBUGP(KERN_DEBUG "ip6t_ROUTE: no hdr & no neighbour cache!\n"); + kfree_skb(skb); + } +} + + +static unsigned int +route6_oif(const struct ip6t_route_target_info *route_info, + struct sk_buff *skb) +{ + unsigned int ifindex = 0; + struct net_device *dev_out = NULL; + + /* The user set the interface name to use. + * Getting the current interface index. + */ + if ((dev_out = dev_get_by_name(route_info->oif))) { + ifindex = dev_out->ifindex; + } else { + /* Unknown interface name : packet dropped */ + if (net_ratelimit()) + DEBUGP("ip6t_ROUTE: oif interface %s not found\n", route_info->oif); + + if (route_info->flags & IP6T_ROUTE_CONTINUE) + return IP6T_CONTINUE; + else + return NF_DROP; + } + + /* Trying the standard way of routing packets */ + if (route6(skb, ifindex, route_info)) { + dev_put(dev_out); + if (route_info->flags & IP6T_ROUTE_CONTINUE) + return IP6T_CONTINUE; + + ip_direct_send(skb); + return NF_STOLEN; + } else + return NF_DROP; +} + + +static unsigned int +route6_gw(const struct ip6t_route_target_info *route_info, + struct sk_buff *skb) +{ + if (route6(skb, 0, route_info)) { + if (route_info->flags & IP6T_ROUTE_CONTINUE) + return IP6T_CONTINUE; + + ip_direct_send(skb); + return NF_STOLEN; + } else + return NF_DROP; +} + + +static unsigned int +ip6t_route_target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + const struct ip6t_route_target_info *route_info = targinfo; + struct sk_buff *skb = *pskb; + struct in6_addr *gw = (struct in6_addr*)&route_info->gw; + unsigned int res; + + if (route_info->flags & IP6T_ROUTE_CONTINUE) + goto do_it; + + /* If we are at PREROUTING or INPUT hook + * the TTL isn't decreased by the IP stack + */ + if (hooknum == NF_IP6_PRE_ROUTING || + hooknum == NF_IP6_LOCAL_IN) { + + struct ipv6hdr *ipv6h = skb->nh.ipv6h; + + if (ipv6h->hop_limit <= 1) { + /* Force OUTPUT device used as source address */ + skb->dev = skb->dst->dev; + + icmpv6_send(skb, ICMPV6_TIME_EXCEED, + ICMPV6_EXC_HOPLIMIT, 0, skb->dev); + + return NF_DROP; + } + + ipv6h->hop_limit--; + } + + if ((route_info->flags & IP6T_ROUTE_TEE)) { + /* + * Copy the *pskb, and route the copy. Will later return + * IP6T_CONTINUE for the original skb, which should continue + * on its way as if nothing happened. The copy should be + * independantly delivered to the ROUTE --gw. + */ + skb = skb_copy(*pskb, GFP_ATOMIC); + if (!skb) { + if (net_ratelimit()) + DEBUGP(KERN_DEBUG "ip6t_ROUTE: copy failed!\n"); + return IP6T_CONTINUE; + } + } + +do_it: + if (route_info->oif[0]) { + res = route6_oif(route_info, skb); + } else if (!ipv6_addr_any(gw)) { + res = route6_gw(route_info, skb); + } else { + if (net_ratelimit()) + DEBUGP(KERN_DEBUG "ip6t_ROUTE: no parameter !\n"); + res = IP6T_CONTINUE; + } + + if ((route_info->flags & IP6T_ROUTE_TEE)) + res = IP6T_CONTINUE; + + return res; +} + + +static int +ip6t_route_checkentry(const char *tablename, + const struct ip6t_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + if (strcmp(tablename, "mangle") != 0) { + printk("ip6t_ROUTE: can only be called from \"mangle\" table.\n"); + return 0; + } + + if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_route_target_info))) { + printk(KERN_WARNING "ip6t_ROUTE: targinfosize %u != %Zu\n", + targinfosize, + IP6T_ALIGN(sizeof(struct ip6t_route_target_info))); + return 0; + } + + return 1; +} + + +static struct ip6t_target ip6t_route_reg = { + .name = "ROUTE", + .target = ip6t_route_target, + .checkentry = ip6t_route_checkentry, + .me = THIS_MODULE +}; + + +static int __init init(void) +{ + printk(KERN_DEBUG "registering ipv6 ROUTE target\n"); + if (ip6t_register_target(&ip6t_route_reg)) + return -EINVAL; + + return 0; +} + + +static void __exit fini(void) +{ + ip6t_unregister_target(&ip6t_route_reg); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff --git a/release/src/linux/linux/net/ipv6/netfilter/ip6t_condition.c b/release/src/linux/linux/net/ipv6/netfilter/ip6t_condition.c new file mode 100644 index 00000000..15d805e6 --- /dev/null +++ b/release/src/linux/linux/net/ipv6/netfilter/ip6t_condition.c @@ -0,0 +1,254 @@ +/*-------------------------------------------*\ +| Netfilter Condition Module for IPv6 | +| | +| Description: This module allows firewall | +| rules to match using condition variables | +| stored in /proc files. | +| | +| Author: Stephane Ouellette 2003-02-10 | +| <ouellettes@videotron.ca> | +| | +| This software is distributed under the | +| terms of the GNU GPL. | +\*-------------------------------------------*/ + +#include<linux/module.h> +#include<linux/proc_fs.h> +#include<linux/spinlock.h> +#include<linux/string.h> +#include<asm/atomic.h> +#include<linux/netfilter_ipv6/ip6_tables.h> +#include<linux/netfilter_ipv6/ip6t_condition.h> + + +#ifndef CONFIG_PROC_FS +#error "Proc file system support is required for this module" +#endif + + +MODULE_AUTHOR("Stephane Ouellette <ouellettes@videotron.ca>"); +MODULE_DESCRIPTION("Allows rules to match against condition variables"); +MODULE_LICENSE("GPL"); + + +struct condition_variable { + struct condition_variable *next; + struct proc_dir_entry *status_proc; + atomic_t refcount; + int enabled; /* TRUE == 1, FALSE == 0 */ +}; + + +static rwlock_t list_lock; +static struct condition_variable *head = NULL; +static struct proc_dir_entry *proc_net_condition = NULL; + + +static int +ipt_condition_read_info(char *buffer, char **start, off_t offset, + int length, int *eof, void *data) +{ + struct condition_variable *var = + (struct condition_variable *) data; + + if (offset == 0) { + *start = buffer; + buffer[0] = (var->enabled) ? '1' : '0'; + buffer[1] = '\n'; + return 2; + } + + *eof = 1; + return 0; +} + + +static int +ipt_condition_write_info(struct file *file, const char *buffer, + unsigned long length, void *data) +{ + struct condition_variable *var = + (struct condition_variable *) data; + + if (length) { + /* Match only on the first character */ + switch (buffer[0]) { + case '0': + var->enabled = 0; + break; + case '1': + var->enabled = 1; + } + } + + return (int) length; +} + + +static int +match(const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const void *matchinfo, int offset, + const void *hdr, u_int16_t datalen, int *hotdrop) +{ + const struct condition6_info *info = + (const struct condition6_info *) matchinfo; + struct condition_variable *var; + int condition_status = 0; + + read_lock(&list_lock); + + for (var = head; var; var = var->next) { + if (strcmp(info->name, var->status_proc->name) == 0) { + condition_status = var->enabled; + break; + } + } + + read_unlock(&list_lock); + + return condition_status ^ info->invert; +} + + + +static int +checkentry(const char *tablename, const struct ip6t_ip6 *ip, + void *matchinfo, unsigned int matchsize, unsigned int hook_mask) +{ + struct condition6_info *info = + (struct condition6_info *) matchinfo; + struct condition_variable *var, *newvar; + + if (matchsize != IP6T_ALIGN(sizeof(struct condition6_info))) + return 0; + + /* The first step is to check if the condition variable already exists. */ + /* Here, a read lock is sufficient because we won't change the list */ + read_lock(&list_lock); + + for (var = head; var; var = var->next) { + if (strcmp(info->name, var->status_proc->name) == 0) { + atomic_inc(&var->refcount); + read_unlock(&list_lock); + return 1; + } + } + + read_unlock(&list_lock); + + /* At this point, we need to allocate a new condition variable */ + newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL); + + if (!newvar) + return -ENOMEM; + + /* Create the condition variable's proc file entry */ + newvar->status_proc = create_proc_entry(info->name, 0644, proc_net_condition); + + if (!newvar->status_proc) { + /* + * There are two possibilities: + * 1- Another condition variable with the same name has been created, which is valid. + * 2- There was a memory allocation error. + */ + kfree(newvar); + read_lock(&list_lock); + + for (var = head; var; var = var->next) { + if (strcmp(info->name, var->status_proc->name) == 0) { + atomic_inc(&var->refcount); + read_unlock(&list_lock); + return 1; + } + } + + read_unlock(&list_lock); + return -ENOMEM; + } + + atomic_set(&newvar->refcount, 1); + newvar->enabled = 0; + newvar->status_proc->owner = THIS_MODULE; + newvar->status_proc->data = newvar; + wmb(); + newvar->status_proc->read_proc = ipt_condition_read_info; + newvar->status_proc->write_proc = ipt_condition_write_info; + + write_lock(&list_lock); + + newvar->next = head; + head = newvar; + + write_unlock(&list_lock); + + return 1; +} + + +static void +destroy(void *matchinfo, unsigned int matchsize) +{ + struct condition6_info *info = + (struct condition6_info *) matchinfo; + struct condition_variable *var, *prev = NULL; + + if (matchsize != IP6T_ALIGN(sizeof(struct condition6_info))) + return; + + write_lock(&list_lock); + + for (var = head; var && strcmp(info->name, var->status_proc->name); + prev = var, var = var->next); + + if (var && atomic_dec_and_test(&var->refcount)) { + if (prev) + prev->next = var->next; + else + head = var->next; + + write_unlock(&list_lock); + remove_proc_entry(var->status_proc->name, proc_net_condition); + kfree(var); + } else + write_unlock(&list_lock); +} + + +static struct ip6t_match condition_match = { + .name = "condition", + .match = &match, + .checkentry = &checkentry, + .destroy = &destroy, + .me = THIS_MODULE +}; + + +static int __init +init(void) +{ + int errorcode; + + rwlock_init(&list_lock); + proc_net_condition = proc_mkdir("ip6t_condition", proc_net); + + if (proc_net_condition) { + errorcode = ipt_register_match(&condition_match); + + if (errorcode) + remove_proc_entry("ip6t_condition", proc_net); + } else + errorcode = -EACCES; + + return errorcode; +} + + +static void __exit +fini(void) +{ + ipt_unregister_match(&condition_match); + remove_proc_entry("ip6t_condition", proc_net); +} + +module_init(init); +module_exit(fini); diff --git a/release/src/linux/linux/net/sched/Config.in b/release/src/linux/linux/net/sched/Config.in index 8e203456..468fdf2a 100644 --- a/release/src/linux/linux/net/sched/Config.in +++ b/release/src/linux/linux/net/sched/Config.in @@ -5,13 +5,14 @@ tristate ' CBQ packet scheduler' CONFIG_NET_SCH_CBQ tristate ' HTB packet scheduler' CONFIG_NET_SCH_HTB tristate ' CSZ packet scheduler' CONFIG_NET_SCH_CSZ #tristate ' H-PFQ packet scheduler' CONFIG_NET_SCH_HPFQ -#tristate ' H-FSC packet scheduler' CONFIG_NET_SCH_HFCS +tristate ' H-FSC packet scheduler' CONFIG_NET_SCH_HFSC if [ "$CONFIG_ATM" = "y" ]; then bool ' ATM pseudo-scheduler' CONFIG_NET_SCH_ATM fi tristate ' The simplest PRIO pseudoscheduler' CONFIG_NET_SCH_PRIO tristate ' RED queue' CONFIG_NET_SCH_RED tristate ' SFQ queue' CONFIG_NET_SCH_SFQ +tristate ' ESFQ queue' CONFIG_NET_SCH_ESFQ tristate ' TEQL queue' CONFIG_NET_SCH_TEQL tristate ' TBF queue' CONFIG_NET_SCH_TBF tristate ' GRED queue' CONFIG_NET_SCH_GRED diff --git a/release/src/linux/linux/net/sched/Makefile b/release/src/linux/linux/net/sched/Makefile index e48e5c3e..49cf71e7 100644 --- a/release/src/linux/linux/net/sched/Makefile +++ b/release/src/linux/linux/net/sched/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_NET_SCH_HPFQ) += sch_hpfq.o obj-$(CONFIG_NET_SCH_HFSC) += sch_hfsc.o obj-$(CONFIG_NET_SCH_HTB) += sch_htb.o obj-$(CONFIG_NET_SCH_SFQ) += sch_sfq.o +obj-$(CONFIG_NET_SCH_ESFQ) += sch_esfq.o obj-$(CONFIG_NET_SCH_RED) += sch_red.o obj-$(CONFIG_NET_SCH_TBF) += sch_tbf.o obj-$(CONFIG_NET_SCH_PRIO) += sch_prio.o diff --git a/release/src/linux/linux/net/sched/sch_api.c b/release/src/linux/linux/net/sched/sch_api.c index a5d8945e..ae384433 100644 --- a/release/src/linux/linux/net/sched/sch_api.c +++ b/release/src/linux/linux/net/sched/sch_api.c @@ -1232,6 +1232,9 @@ int __init pktsched_init(void) #ifdef CONFIG_NET_SCH_SFQ INIT_QDISC(sfq); #endif +#ifdef CONFIG_NET_SCH_ESFQ + INIT_QDISC(esfq); +#endif #ifdef CONFIG_NET_SCH_TBF INIT_QDISC(tbf); #endif diff --git a/release/src/linux/linux/net/sched/sch_esfq.c b/release/src/linux/linux/net/sched/sch_esfq.c new file mode 100644 index 00000000..26640f18 --- /dev/null +++ b/release/src/linux/linux/net/sched/sch_esfq.c @@ -0,0 +1,652 @@ +/* + * net/sched/sch_esfq.c Extended Stochastic Fairness Queueing discipline. + * + * 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. + * + * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> + * + * Changes: Alexander Atanasov, <alex@ssi.bg> + * Added dynamic depth,limit,divisor,hash_kind options. + * Added dst and src hashes. + * + * Alexander Clouter, <alex@digriz.org.uk> + * Ported ESFQ to Linux 2.6. + * + * Corey Hickey, <bugfood-c@fatooh.org> + * Maintenance of the Linux 2.6 port. + * Added fwmark hash (thanks to Robert Kurjata) + * Added direct hashing for src, dst, and fwmark. + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/bitops.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/socket.h> +#include <linux/sockios.h> +#include <linux/in.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/if_ether.h> +#include <linux/inet.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/notifier.h> +#include <linux/init.h> +#include <net/ip.h> +#include <linux/ipv6.h> +#include <net/route.h> +#include <linux/skbuff.h> +#include <net/sock.h> +#include <net/pkt_sched.h> + + +/* Stochastic Fairness Queuing algorithm. + For more comments look at sch_sfq.c. + The difference is that you can change limit, depth, + hash table size and choose 7 hash types. + + classic: same as in sch_sfq.c + dst: destination IP address + src: source IP address + fwmark: netfilter mark value + dst_direct: + src_direct: + fwmark_direct: direct hashing of the above sources + + TODO: + make sfq_change work. +*/ + +#ifndef IPPROTO_SCTP +#define IPPROTO_SCTP 132
+#endif +#ifndef IPPROTO_DCCP
+#define IPPROTO_DCCP 33
+#endif + +/* This type should contain at least SFQ_DEPTH*2 values */ +typedef unsigned int esfq_index; + +struct esfq_head +{ + esfq_index next; + esfq_index prev; +}; + +struct esfq_sched_data +{ +/* Parameters */ + int perturb_period; + unsigned quantum; /* Allotment per round: MUST BE >= MTU */ + int limit; + unsigned depth; + unsigned hash_divisor; + unsigned hash_kind; +/* Variables */ + struct timer_list perturb_timer; + int perturbation; + esfq_index tail; /* Index of current slot in round */ + esfq_index max_depth; /* Maximal depth */ + + esfq_index *ht; /* Hash table */ + esfq_index *next; /* Active slots link */ + short *allot; /* Current allotment per slot */ + unsigned short *hash; /* Hash value indexed by slots */ + struct sk_buff_head *qs; /* Slot queue */ + struct esfq_head *dep; /* Linked list of slots, indexed by depth */ + unsigned dyn_min; /* For dynamic divisor adjustment; minimum value seen */ + unsigned dyn_max; /* maximum value seen */ + unsigned dyn_range; /* saved range */ +}; + +static __inline__ unsigned esfq_hash_u32(struct esfq_sched_data *q,u32 h) +{ + int pert = q->perturbation; + + if (pert) + h = (h<<pert) ^ (h>>(0x1F - pert)); + + h = ntohl(h) * 2654435761UL; + return h & (q->hash_divisor-1); +} + +/* Hash input values directly into the "nearest" slot, taking into account the + * range of input values seen. This is most useful when the hash table is at + * least as large as the range of possible values. */ +static __inline__ unsigned esfq_hash_direct(struct esfq_sched_data *q, u32 h) +{ + /* adjust minimum and maximum */ + if (h < q->dyn_min || h > q->dyn_max) { + q->dyn_min = h < q->dyn_min ? h : q->dyn_min; + q->dyn_max = h > q->dyn_max ? h : q->dyn_max; + + /* find new range */ + if ((q->dyn_range = q->dyn_max - q->dyn_min) >= q->hash_divisor) + printk(KERN_WARNING "ESFQ: (direct hash) Input range %u is larger than hash " + "table. See ESFQ README for details.\n", q->dyn_range); + } + + /* hash input values into slot numbers */ + if (q->dyn_min == q->dyn_max) + return 0; /* only one value seen; avoid division by 0 */ + else + return (h - q->dyn_min) * (q->hash_divisor - 1) / q->dyn_range; +} + +static __inline__ unsigned esfq_fold_hash_classic(struct esfq_sched_data *q, u32 h, u32 h1) +{ + int pert = q->perturbation; + + /* Have we any rotation primitives? If not, WHY? */ + h ^= (h1<<pert) ^ (h1>>(0x1F - pert)); + h ^= h>>10; + return h & (q->hash_divisor-1); +} + +static unsigned esfq_hash(struct esfq_sched_data *q, struct sk_buff *skb) +{ + u32 h, h2; + u32 hs; + u32 nfm; + + switch (skb->protocol) { + case __constant_htons(ETH_P_IP): + { + struct iphdr *iph = skb->nh.iph; + h = iph->daddr; + hs = iph->saddr; + nfm = skb->nfmark; + h2 = hs^iph->protocol; + if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && + (iph->protocol == IPPROTO_TCP || + iph->protocol == IPPROTO_UDP || + iph->protocol == IPPROTO_SCTP || + iph->protocol == IPPROTO_DCCP || + iph->protocol == IPPROTO_ESP)) + h2 ^= *(((u32*)iph) + iph->ihl); + break; + } + case __constant_htons(ETH_P_IPV6): + { + struct ipv6hdr *iph = skb->nh.ipv6h; + h = iph->daddr.s6_addr32[3]; + hs = iph->saddr.s6_addr32[3]; + nfm = skb->nfmark; + h2 = hs^iph->nexthdr; + if (iph->nexthdr == IPPROTO_TCP || + iph->nexthdr == IPPROTO_UDP || + iph->nexthdr == IPPROTO_SCTP || + iph->nexthdr == IPPROTO_DCCP || + iph->nexthdr == IPPROTO_ESP) + h2 ^= *(u32*)&iph[1]; + break; + } + default: + h = (u32)(unsigned long)skb->dst; + hs = (u32)(unsigned long)skb->sk; + nfm = skb->nfmark; + h2 = hs^skb->protocol; + } + switch(q->hash_kind) + { + case TCA_SFQ_HASH_CLASSIC: + return esfq_fold_hash_classic(q, h, h2); + case TCA_SFQ_HASH_DST: + return esfq_hash_u32(q,h); + case TCA_SFQ_HASH_DSTDIR: + return esfq_hash_direct(q, ntohl(h)); + case TCA_SFQ_HASH_SRC: + return esfq_hash_u32(q,hs); + case TCA_SFQ_HASH_SRCDIR: + return esfq_hash_direct(q, ntohl(hs)); +#ifdef CONFIG_NETFILTER + case TCA_SFQ_HASH_FWMARK: + return esfq_hash_u32(q,nfm); + case TCA_SFQ_HASH_FWMARKDIR: + return esfq_hash_direct(q,nfm); +#endif + default: + if (net_ratelimit()) + printk(KERN_WARNING "ESFQ: Unknown hash method. Falling back to classic.\n"); + } + return esfq_fold_hash_classic(q, h, h2); +} + +static inline void esfq_link(struct esfq_sched_data *q, esfq_index x) +{ + esfq_index p, n; + int d = q->qs[x].qlen + q->depth; + + p = d; + n = q->dep[d].next; + q->dep[x].next = n; + q->dep[x].prev = p; + q->dep[p].next = q->dep[n].prev = x; +} + +static inline void esfq_dec(struct esfq_sched_data *q, esfq_index x) +{ + esfq_index p, n; + + n = q->dep[x].next; + p = q->dep[x].prev; + q->dep[p].next = n; + q->dep[n].prev = p; + + if (n == p && q->max_depth == q->qs[x].qlen + 1) + q->max_depth--; + + esfq_link(q, x); +} + +static inline void esfq_inc(struct esfq_sched_data *q, esfq_index x) +{ + esfq_index p, n; + int d; + + n = q->dep[x].next; + p = q->dep[x].prev; + q->dep[p].next = n; + q->dep[n].prev = p; + d = q->qs[x].qlen; + if (q->max_depth < d) + q->max_depth = d; + + esfq_link(q, x); +} + +static int esfq_drop(struct Qdisc *sch) +{ + struct esfq_sched_data *q = (struct esfq_sched_data *)sch->data; + esfq_index d = q->max_depth; + struct sk_buff *skb; + unsigned int len; + + /* Queue is full! Find the longest slot and + drop a packet from it */ + + if (d > 1) { + esfq_index x = q->dep[d+q->depth].next; + skb = q->qs[x].prev; + len = skb->len; + __skb_unlink(skb, &q->qs[x]); + kfree_skb(skb); + esfq_dec(q, x); + sch->q.qlen--; + sch->stats.drops++; + return len; + } + + if (d == 1) { + /* It is difficult to believe, but ALL THE SLOTS HAVE LENGTH 1. */ + d = q->next[q->tail]; + q->next[q->tail] = q->next[d]; + q->allot[q->next[d]] += q->quantum; + skb = q->qs[d].prev; + len = skb->len; + __skb_unlink(skb, &q->qs[d]); + kfree_skb(skb); + esfq_dec(q, d); + sch->q.qlen--; + q->ht[q->hash[d]] = q->depth; + sch->stats.drops++; + return len; + } + + return 0; +} + +static int +esfq_enqueue(struct sk_buff *skb, struct Qdisc* sch) +{ + struct esfq_sched_data *q = (struct esfq_sched_data *)sch->data; + unsigned hash = esfq_hash(q, skb); + unsigned depth = q->depth; + esfq_index x; + + x = q->ht[hash]; + if (x == depth) { + q->ht[hash] = x = q->dep[depth].next; + q->hash[x] = hash; + } + __skb_queue_tail(&q->qs[x], skb); + esfq_inc(q, x); + if (q->qs[x].qlen == 1) { /* The flow is new */ + if (q->tail == depth) { /* It is the first flow */ + q->tail = x; + q->next[x] = x; + q->allot[x] = q->quantum; + } else { + q->next[x] = q->next[q->tail]; + q->next[q->tail] = x; + q->tail = x; + } + } + if (++sch->q.qlen < q->limit-1) { + sch->stats.bytes += skb->len; + sch->stats.packets++; + return 0; + } + + esfq_drop(sch); + return NET_XMIT_CN; +} + +static int +esfq_requeue(struct sk_buff *skb, struct Qdisc* sch) +{ + struct esfq_sched_data *q = (struct esfq_sched_data *)sch->data; + unsigned hash = esfq_hash(q, skb); + unsigned depth = q->depth; + esfq_index x; + + x = q->ht[hash]; + if (x == depth) { + q->ht[hash] = x = q->dep[depth].next; + q->hash[x] = hash; + } + __skb_queue_head(&q->qs[x], skb); + esfq_inc(q, x); + if (q->qs[x].qlen == 1) { /* The flow is new */ + if (q->tail == depth) { /* It is the first flow */ + q->tail = x; + q->next[x] = x; + q->allot[x] = q->quantum; + } else { + q->next[x] = q->next[q->tail]; + q->next[q->tail] = x; + q->tail = x; + } + } + if (++sch->q.qlen < q->limit - 1) { +// sch->stats.requeues++; + return 0; + } + + sch->stats.drops++; + esfq_drop(sch); + return NET_XMIT_CN; +} + + + + +static struct sk_buff * +esfq_dequeue(struct Qdisc* sch) +{ + struct esfq_sched_data *q = (struct esfq_sched_data *)sch->data; + struct sk_buff *skb; + unsigned depth = q->depth; + esfq_index a, old_a; + + /* No active slots */ + if (q->tail == depth) + return NULL; + + a = old_a = q->next[q->tail]; + + /* Grab packet */ + skb = __skb_dequeue(&q->qs[a]); + esfq_dec(q, a); + sch->q.qlen--; + + /* Is the slot empty? */ + if (q->qs[a].qlen == 0) { + q->ht[q->hash[a]] = depth; + a = q->next[a]; + if (a == old_a) { + q->tail = depth; + return skb; + } + q->next[q->tail] = a; + q->allot[a] += q->quantum; + } else if ((q->allot[a] -= skb->len) <= 0) { + q->tail = a; + a = q->next[a]; + q->allot[a] += q->quantum; + } + + return skb; +} + +static void +esfq_reset(struct Qdisc* sch) +{ + struct sk_buff *skb; + + while ((skb = esfq_dequeue(sch)) != NULL) + kfree_skb(skb); +} + +static void esfq_perturbation(unsigned long arg) +{ + struct Qdisc *sch = (struct Qdisc*)arg; + struct esfq_sched_data *q = (struct esfq_sched_data *)sch->data; + + q->perturbation = net_random()&0x1F; + + if (q->perturb_period) { + q->perturb_timer.expires = jiffies + q->perturb_period; + add_timer(&q->perturb_timer); + } +} + +/* +static int esfq_change(struct Qdisc *sch, struct rtattr *opt) +{ + struct esfq_sched_data *q = (struct esfq_sched_data *)sch->data; + struct tc_esfq_qopt *ctl = RTA_DATA(opt); + int old_perturb = q->perturb_period; + + if (opt->rta_len < RTA_LENGTH(sizeof(*ctl))) + return -EINVAL; + + sch_tree_lock(sch); + q->quantum = ctl->quantum ? : psched_mtu(sch->dev); + q->perturb_period = ctl->perturb_period*HZ; +// q->hash_divisor = ctl->divisor; +// q->tail = q->limit = q->depth = ctl->flows; + + if (ctl->limit) + q->limit = min_t(u32, ctl->limit, q->depth); + + if (ctl->hash_kind) { + q->hash_kind = ctl->hash_kind; + if (q->hash_kind != TCA_SFQ_HASH_CLASSIC) + q->perturb_period = 0; + } + + // is sch_tree_lock enough to do this ? + while (sch->q.qlen >= q->limit-1) + esfq_drop(sch); + + if (old_perturb) + del_timer(&q->perturb_timer); + if (q->perturb_period) { + q->perturb_timer.expires = jiffies + q->perturb_period; + add_timer(&q->perturb_timer); + } else { + q->perturbation = 0; + } + sch_tree_unlock(sch); + return 0; +} +*/ + +static int esfq_init(struct Qdisc *sch, struct rtattr *opt) +{ + struct esfq_sched_data *q = (struct esfq_sched_data *)sch->data; + struct tc_esfq_qopt *ctl; + esfq_index p = ~0UL/2; + int i; + + if (opt && opt->rta_len < RTA_LENGTH(sizeof(*ctl))) + return -EINVAL; + + init_timer(&q->perturb_timer); + q->perturb_timer.data = (unsigned long)sch; + q->perturb_timer.function = esfq_perturbation; + q->perturbation = 0; + q->hash_kind = TCA_SFQ_HASH_CLASSIC; + q->max_depth = 0; + q->dyn_min = ~0U; /* maximum value for this type */ + q->dyn_max = 0; /* dyn_min/dyn_max will be set properly upon first packet */ + if (opt == NULL) { + q->quantum = psched_mtu(sch->dev); + q->perturb_period = 0; + q->hash_divisor = 1024; + q->tail = q->limit = q->depth = 128; + + } else { + ctl = RTA_DATA(opt); + q->quantum = ctl->quantum ? : psched_mtu(sch->dev); + q->perturb_period = ctl->perturb_period*HZ; + q->hash_divisor = ctl->divisor ? : 1024; + q->tail = q->limit = q->depth = ctl->flows ? : 128; + + if ( q->depth > p - 1 ) + return -EINVAL; + + if (ctl->limit) + q->limit = min_t(u32, ctl->limit, q->depth); + + if (ctl->hash_kind) { + q->hash_kind = ctl->hash_kind; + } + + if (q->perturb_period) { + q->perturb_timer.expires = jiffies + q->perturb_period; + add_timer(&q->perturb_timer); + } + } + + q->ht = kmalloc(q->hash_divisor*sizeof(esfq_index), GFP_KERNEL); + if (!q->ht) + goto err_case; + + q->dep = kmalloc((1+q->depth*2)*sizeof(struct esfq_head), GFP_KERNEL); + if (!q->dep) + goto err_case; + q->next = kmalloc(q->depth*sizeof(esfq_index), GFP_KERNEL); + if (!q->next) + goto err_case; + + q->allot = kmalloc(q->depth*sizeof(short), GFP_KERNEL); + if (!q->allot) + goto err_case; + q->hash = kmalloc(q->depth*sizeof(unsigned short), GFP_KERNEL); + if (!q->hash) + goto err_case; + q->qs = kmalloc(q->depth*sizeof(struct sk_buff_head), GFP_KERNEL); + if (!q->qs) + goto err_case; + + for (i=0; i< q->hash_divisor; i++) + q->ht[i] = q->depth; + for (i=0; i<q->depth; i++) { + skb_queue_head_init(&q->qs[i]); + q->dep[i+q->depth].next = i+q->depth; + q->dep[i+q->depth].prev = i+q->depth; + } + + for (i=0; i<q->depth; i++) + esfq_link(q, i); + return 0; +err_case: + del_timer(&q->perturb_timer); + if (q->ht) + kfree(q->ht); + if (q->dep) + kfree(q->dep); + if (q->next) + kfree(q->next); + if (q->allot) + kfree(q->allot); + if (q->hash) + kfree(q->hash); + if (q->qs) + kfree(q->qs); + return -ENOBUFS; +} + +static void esfq_destroy(struct Qdisc *sch) +{ + struct esfq_sched_data *q = (struct esfq_sched_data *)sch->data; + del_timer(&q->perturb_timer); + if(q->ht) + kfree(q->ht); + if(q->dep) + kfree(q->dep); + if(q->next) + kfree(q->next); + if(q->allot) + kfree(q->allot); + if(q->hash) + kfree(q->hash); + if(q->qs) + kfree(q->qs); +} + +static int esfq_dump(struct Qdisc *sch, struct sk_buff *skb) +{ + struct esfq_sched_data *q = (struct esfq_sched_data *)sch->data; + unsigned char *b = skb->tail; + struct tc_esfq_qopt opt; + + opt.quantum = q->quantum; + opt.perturb_period = q->perturb_period/HZ; + + opt.limit = q->limit; + opt.divisor = q->hash_divisor; + opt.flows = q->depth; + opt.hash_kind = q->hash_kind; + + RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); + + return skb->len; + +rtattr_failure: + skb_trim(skb, b - skb->data); + return -1; +} + +static struct Qdisc_ops esfq_qdisc_ops = +{ + .next = NULL, + .cl_ops = NULL, + .id = "esfq", + .priv_size = sizeof(struct esfq_sched_data), + .enqueue = esfq_enqueue, + .dequeue = esfq_dequeue, + .requeue = esfq_requeue, + .drop = esfq_drop, + .init = esfq_init, + .reset = esfq_reset, + .destroy = esfq_destroy, + .change = NULL, /* esfq_change - needs more work */ + .dump = esfq_dump, +// .owner = THIS_MODULE, +}; + +static int __init esfq_module_init(void) +{ + return register_qdisc(&esfq_qdisc_ops); +} +static void __exit esfq_module_exit(void) +{ + unregister_qdisc(&esfq_qdisc_ops); +} +module_init(esfq_module_init) +module_exit(esfq_module_exit) +MODULE_LICENSE("GPL"); diff --git a/release/src/linux/linux/net/sched/sch_fifo.c b/release/src/linux/linux/net/sched/sch_fifo.c index d8ce46f2..3a7741e9 100644 --- a/release/src/linux/linux/net/sched/sch_fifo.c +++ b/release/src/linux/linux/net/sched/sch_fifo.c @@ -46,7 +46,7 @@ bfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch) { struct fifo_sched_data *q = (struct fifo_sched_data *)sch->data; - if (sch->stats.backlog <= q->limit) { + if (sch->stats.backlog + skb->len <= q->limit) { __skb_queue_tail(&sch->q, skb); sch->stats.backlog += skb->len; sch->stats.bytes += skb->len; @@ -87,9 +87,10 @@ fifo_drop(struct Qdisc* sch) skb = __skb_dequeue_tail(&sch->q); if (skb) { - sch->stats.backlog -= skb->len; + int len = skb->len; + sch->stats.backlog -= len; kfree_skb(skb); - return 1; + return len; } return 0; } @@ -106,7 +107,7 @@ pfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch) { struct fifo_sched_data *q = (struct fifo_sched_data *)sch->data; - if (sch->q.qlen <= q->limit) { + if (sch->q.qlen < q->limit) { __skb_queue_tail(&sch->q, skb); sch->stats.bytes += skb->len; sch->stats.packets++; @@ -139,10 +140,12 @@ static int fifo_init(struct Qdisc *sch, struct rtattr *opt) struct fifo_sched_data *q = (void*)sch->data; if (opt == NULL) { + unsigned int limit = sch->dev->tx_queue_len ? : 1; + if (sch->ops == &bfifo_qdisc_ops) - q->limit = sch->dev->tx_queue_len*sch->dev->mtu; + q->limit = limit*sch->dev->mtu; else - q->limit = sch->dev->tx_queue_len; + q->limit = limit; } else { struct tc_fifo_qopt *ctl = RTA_DATA(opt); if (opt->rta_len < RTA_LENGTH(sizeof(*ctl))) diff --git a/release/src/linux/linux/net/sched/sch_generic.c b/release/src/linux/linux/net/sched/sch_generic.c index 7b0d49e7..ca30d124 100644 --- a/release/src/linux/linux/net/sched/sch_generic.c +++ b/release/src/linux/linux/net/sched/sch_generic.c @@ -29,6 +29,9 @@ #include <linux/skbuff.h> #include <linux/rtnetlink.h> #include <linux/init.h> +#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) +#include <linux/imq.h> +#endif #include <net/sock.h> #include <net/pkt_sched.h> @@ -79,6 +82,10 @@ int qdisc_restart(struct net_device *dev) struct Qdisc *q = dev->qdisc; struct sk_buff *skb; + /* BRCM: bail out if queue is null */ + if (!q) + return 0; + /* Dequeue packet */ if ((skb = q->dequeue(q)) != NULL) { if (spin_trylock(&dev->xmit_lock)) { @@ -89,7 +96,11 @@ int qdisc_restart(struct net_device *dev) spin_unlock(&dev->queue_lock); if (!netif_queue_stopped(dev)) { - if (netdev_nit) + if (netdev_nit +#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) + && !(skb->imq_flags & IMQ_F_ENQUEUE) +#endif + ) dev_queue_xmit_nit(skb, dev); if (dev->hard_start_xmit(skb, dev) == 0) { diff --git a/release/src/linux/linux/net/sched/sch_hfsc.c b/release/src/linux/linux/net/sched/sch_hfsc.c new file mode 100644 index 00000000..0b6e6d38 --- /dev/null +++ b/release/src/linux/linux/net/sched/sch_hfsc.c @@ -0,0 +1,1817 @@ +/* + * Copyright (c) 2003 Patrick McHardy, <kaber@trash.net> + * + * 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. + * + * 2003-10-17 - Ported from altq + */ +/* + * Copyright (c) 1997-1999 Carnegie Mellon University. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation is hereby granted (including for commercial or + * for-profit use), provided that both the copyright notice and this + * permission notice appear in all copies of the software, derivative + * works, or modified versions, and any portions thereof. + * + * THIS SOFTWARE IS EXPERIMENTAL AND IS KNOWN TO HAVE BUGS, SOME OF + * WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON PROVIDES THIS + * SOFTWARE IN ITS ``AS IS'' CONDITION, 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 CARNEGIE MELLON UNIVERSITY 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. + * + * Carnegie Mellon encourages (but does not require) users of this + * software to return any improvements or extensions that they make, + * and to grant Carnegie Mellon the rights to redistribute these + * changes without encumbrance. + */ +/* + * H-FSC is described in Proceedings of SIGCOMM'97, + * "A Hierarchical Fair Service Curve Algorithm for Link-Sharing, + * Real-Time and Priority Service" + * by Ion Stoica, Hui Zhang, and T. S. Eugene Ng. + * + * Oleg Cherevko <olwi@aq.ml.com.ua> added the upperlimit for link-sharing. + * when a class has an upperlimit, the fit-time is computed from the + * upperlimit service curve. the link-sharing scheduler does not schedule + * a class whose fit-time exceeds the current time. + */ + +#include <linux/kernel.h> +#include <linux/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/compiler.h> +#include <linux/spinlock.h> +#include <linux/skbuff.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/timer.h> +#include <linux/list.h> +#include <linux/rbtree.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/rtnetlink.h> +#include <linux/pkt_sched.h> +#include <net/pkt_sched.h> +#include <net/pkt_cls.h> +#include <asm/system.h> +#include <asm/div64.h> + +#define HFSC_DEBUG 0 + +/* + * kernel internal service curve representation: + * coordinates are given by 64 bit unsigned integers. + * x-axis: unit is clock count. + * y-axis: unit is byte. + * + * The service curve parameters are converted to the internal + * representation. The slope values are scaled to avoid overflow. + * the inverse slope values as well as the y-projection of the 1st + * segment are kept in order to to avoid 64-bit divide operations + * that are expensive on 32-bit architectures. + */ + +struct internal_sc +{ + u64 sm1; /* scaled slope of the 1st segment */ + u64 ism1; /* scaled inverse-slope of the 1st segment */ + u64 dx; /* the x-projection of the 1st segment */ + u64 dy; /* the y-projection of the 1st segment */ + u64 sm2; /* scaled slope of the 2nd segment */ + u64 ism2; /* scaled inverse-slope of the 2nd segment */ +}; + +/* runtime service curve */ +struct runtime_sc +{ + u64 x; /* current starting position on x-axis */ + u64 y; /* current starting position on y-axis */ + u64 sm1; /* scaled slope of the 1st segment */ + u64 ism1; /* scaled inverse-slope of the 1st segment */ + u64 dx; /* the x-projection of the 1st segment */ + u64 dy; /* the y-projection of the 1st segment */ + u64 sm2; /* scaled slope of the 2nd segment */ + u64 ism2; /* scaled inverse-slope of the 2nd segment */ +}; + +enum hfsc_class_flags +{ + HFSC_RSC = 0x1, + HFSC_FSC = 0x2, + HFSC_USC = 0x4 +}; + +struct hfsc_class +{ + u32 classid; /* class id */ + unsigned int refcnt; /* usage count */ + + struct tc_stats stats; /* generic statistics */ + unsigned int level; /* class level in hierarchy */ + struct tcf_proto *filter_list; /* filter list */ + unsigned int filter_cnt; /* filter count */ + + struct hfsc_sched *sched; /* scheduler data */ + struct hfsc_class *cl_parent; /* parent class */ + struct list_head siblings; /* sibling classes */ + struct list_head children; /* child classes */ + struct Qdisc *qdisc; /* leaf qdisc */ + + rb_node_t el_node; /* qdisc's eligible tree member */ + rb_root_t vt_tree; /* active children sorted by cl_vt */ + rb_node_t vt_node; /* parent's vt_tree member */ + rb_root_t cf_tree; /* active children sorted by cl_f */ + rb_node_t cf_node; /* parent's cf_heap member */ + struct list_head hlist; /* hash list member */ + struct list_head dlist; /* drop list member */ + + u64 cl_total; /* total work in bytes */ + u64 cl_cumul; /* cumulative work in bytes done by + real-time criteria */ + + u64 cl_d; /* deadline*/ + u64 cl_e; /* eligible time */ + u64 cl_vt; /* virtual time */ + u64 cl_f; /* time when this class will fit for + link-sharing, max(myf, cfmin) */ + u64 cl_myf; /* my fit-time (calculated from this + class's own upperlimit curve) */ + u64 cl_myfadj; /* my fit-time adjustment (to cancel + history dependence) */ + u64 cl_cfmin; /* earliest children's fit-time (used + with cl_myf to obtain cl_f) */ + u64 cl_cvtmin; /* minimal virtual time among the + children fit for link-sharing + (monotonic within a period) */ + u64 cl_vtadj; /* intra-period cumulative vt + adjustment */ + u64 cl_vtoff; /* inter-period cumulative vt offset */ + u64 cl_cvtmax; /* max child's vt in the last period */ + u64 cl_cvtoff; /* cumulative cvtmax of all periods */ + u64 cl_pcvtoff; /* parent's cvtoff at initalization + time */ + + struct internal_sc cl_rsc; /* internal real-time service curve */ + struct internal_sc cl_fsc; /* internal fair service curve */ + struct internal_sc cl_usc; /* internal upperlimit service curve */ + struct runtime_sc cl_deadline; /* deadline curve */ + struct runtime_sc cl_eligible; /* eligible curve */ + struct runtime_sc cl_virtual; /* virtual curve */ + struct runtime_sc cl_ulimit; /* upperlimit curve */ + + unsigned long cl_flags; /* which curves are valid */ + unsigned long cl_vtperiod; /* vt period sequence number */ + unsigned long cl_parentperiod;/* parent's vt period sequence number*/ + unsigned long cl_nactive; /* number of active children */ +}; + +#define HFSC_HSIZE 16 + +struct hfsc_sched +{ + u16 defcls; /* default class id */ + struct hfsc_class root; /* root class */ + struct list_head clhash[HFSC_HSIZE]; /* class hash */ + rb_root_t eligible; /* eligible tree */ + struct list_head droplist; /* active leaf class list (for + dropping) */ + struct sk_buff_head requeue; /* requeued packet */ + struct timer_list wd_timer; /* watchdog timer */ +}; + +/* + * macros + */ +#if PSCHED_CLOCK_SOURCE == PSCHED_GETTIMEOFDAY +#include <linux/time.h> +#undef PSCHED_GET_TIME +#define PSCHED_GET_TIME(stamp) \ +do { \ + struct timeval tv; \ + do_gettimeofday(&tv); \ + (stamp) = 1000000ULL * tv.tv_sec + tv.tv_usec; \ +} while (0) +#endif + +#if HFSC_DEBUG +#define ASSERT(cond) \ +do { \ + if (unlikely(!(cond))) \ + printk("assertion %s failed at %s:%i (%s)\n", \ + #cond, __FILE__, __LINE__, __FUNCTION__); \ +} while (0) +#else +#define ASSERT(cond) +#endif /* HFSC_DEBUG */ + +#define HT_INFINITY 0xffffffffffffffffULL /* infinite time value */ + + +/* + * eligible tree holds backlogged classes being sorted by their eligible times. + * there is one eligible tree per hfsc instance. + */ + +static void +eltree_insert(struct hfsc_class *cl) +{ + rb_node_t **p = &cl->sched->eligible.rb_node; + rb_node_t *parent = NULL; + struct hfsc_class *cl1; + + while (*p != NULL) { + parent = *p; + cl1 = rb_entry(parent, struct hfsc_class, el_node); + if (cl->cl_e >= cl1->cl_e) + p = &parent->rb_right; + else + p = &parent->rb_left; + } + rb_link_node(&cl->el_node, parent, p); + rb_insert_color(&cl->el_node, &cl->sched->eligible); +} + +static inline void +eltree_remove(struct hfsc_class *cl) +{ + rb_erase(&cl->el_node, &cl->sched->eligible); +} + +static inline void +eltree_update(struct hfsc_class *cl) +{ + eltree_remove(cl); + eltree_insert(cl); +} + +/* find the class with the minimum deadline among the eligible classes */ +static inline struct hfsc_class * +eltree_get_mindl(struct hfsc_sched *q, u64 cur_time) +{ + struct hfsc_class *p, *cl = NULL; + rb_node_t *n; + + for (n = rb_first(&q->eligible); n != NULL; n = rb_next(n)) { + p = rb_entry(n, struct hfsc_class, el_node); + if (p->cl_e > cur_time) + break; + if (cl == NULL || p->cl_d < cl->cl_d) + cl = p; + } + return cl; +} + +/* find the class with minimum eligible time among the eligible classes */ +static inline struct hfsc_class * +eltree_get_minel(struct hfsc_sched *q) +{ + rb_node_t *n; + + n = rb_first(&q->eligible); + if (n == NULL) + return NULL; + return rb_entry(n, struct hfsc_class, el_node); +} + +/* + * vttree holds holds backlogged child classes being sorted by their virtual + * time. each intermediate class has one vttree. + */ +static void +vttree_insert(struct hfsc_class *cl) +{ + rb_node_t **p = &cl->cl_parent->vt_tree.rb_node; + rb_node_t *parent = NULL; + struct hfsc_class *cl1; + + while (*p != NULL) { + parent = *p; + cl1 = rb_entry(parent, struct hfsc_class, vt_node); + if (cl->cl_vt >= cl1->cl_vt) + p = &parent->rb_right; + else + p = &parent->rb_left; + } + rb_link_node(&cl->vt_node, parent, p); + rb_insert_color(&cl->vt_node, &cl->cl_parent->vt_tree); +} + +static inline void +vttree_remove(struct hfsc_class *cl) +{ + rb_erase(&cl->vt_node, &cl->cl_parent->vt_tree); +} + +static inline void +vttree_update(struct hfsc_class *cl) +{ + vttree_remove(cl); + vttree_insert(cl); +} + +static inline struct hfsc_class * +vttree_firstfit(struct hfsc_class *cl, u64 cur_time) +{ + struct hfsc_class *p; + rb_node_t *n; + + for (n = rb_first(&cl->vt_tree); n != NULL; n = rb_next(n)) { + p = rb_entry(n, struct hfsc_class, vt_node); + if (p->cl_f <= cur_time) + return p; + } + return NULL; +} + +/* + * get the leaf class with the minimum vt in the hierarchy + */ +static struct hfsc_class * +vttree_get_minvt(struct hfsc_class *cl, u64 cur_time) +{ + /* if root-class's cfmin is bigger than cur_time nothing to do */ + if (cl->cl_cfmin > cur_time) + return NULL; + + while (cl->level > 0) { + cl = vttree_firstfit(cl, cur_time); + if (cl == NULL) + return NULL; + /* + * update parent's cl_cvtmin. + */ + if (cl->cl_parent->cl_cvtmin < cl->cl_vt) + cl->cl_parent->cl_cvtmin = cl->cl_vt; + } + return cl; +} + +static void +cftree_insert(struct hfsc_class *cl) +{ + rb_node_t **p = &cl->cl_parent->cf_tree.rb_node; + rb_node_t *parent = NULL; + struct hfsc_class *cl1; + + while (*p != NULL) { + parent = *p; + cl1 = rb_entry(parent, struct hfsc_class, cf_node); + if (cl->cl_f >= cl1->cl_f) + p = &parent->rb_right; + else + p = &parent->rb_left; + } + rb_link_node(&cl->cf_node, parent, p); + rb_insert_color(&cl->cf_node, &cl->cl_parent->cf_tree); +} + +static inline void +cftree_remove(struct hfsc_class *cl) +{ + rb_erase(&cl->cf_node, &cl->cl_parent->cf_tree); +} + +static inline void +cftree_update(struct hfsc_class *cl) +{ + cftree_remove(cl); + cftree_insert(cl); +} + +/* + * service curve support functions + * + * external service curve parameters + * m: bps + * d: us + * internal service curve parameters + * sm: (bytes/psched_us) << SM_SHIFT + * ism: (psched_us/byte) << ISM_SHIFT + * dx: psched_us + * + * Time source resolution + * PSCHED_JIFFIES: for 48<=HZ<=1534 resolution is between 0.63us and 1.27us. + * PSCHED_CPU: resolution is between 0.5us and 1us. + * PSCHED_GETTIMEOFDAY: resolution is exactly 1us. + * + * sm and ism are scaled in order to keep effective digits. + * SM_SHIFT and ISM_SHIFT are selected to keep at least 4 effective + * digits in decimal using the following table. + * + * Note: We can afford the additional accuracy (altq hfsc keeps at most + * 3 effective digits) thanks to the fact that linux clock is bounded + * much more tightly. + * + * bits/sec 100Kbps 1Mbps 10Mbps 100Mbps 1Gbps + * ------------+------------------------------------------------------- + * bytes/0.5us 6.25e-3 62.5e-3 625e-3 6250e-e 62500e-3 + * bytes/us 12.5e-3 125e-3 1250e-3 12500e-3 125000e-3 + * bytes/1.27us 15.875e-3 158.75e-3 1587.5e-3 15875e-3 158750e-3 + * + * 0.5us/byte 160 16 1.6 0.16 0.016 + * us/byte 80 8 0.8 0.08 0.008 + * 1.27us/byte 63 6.3 0.63 0.063 0.0063 + */ +#define SM_SHIFT 20 +#define ISM_SHIFT 18 + +#define SM_MASK ((1ULL << SM_SHIFT) - 1) +#define ISM_MASK ((1ULL << ISM_SHIFT) - 1) + +static inline u64 +seg_x2y(u64 x, u64 sm) +{ + u64 y; + + /* + * compute + * y = x * sm >> SM_SHIFT + * but divide it for the upper and lower bits to avoid overflow + */ + y = (x >> SM_SHIFT) * sm + (((x & SM_MASK) * sm) >> SM_SHIFT); + return y; +} + +static inline u64 +seg_y2x(u64 y, u64 ism) +{ + u64 x; + + if (y == 0) + x = 0; + else if (ism == HT_INFINITY) + x = HT_INFINITY; + else { + x = (y >> ISM_SHIFT) * ism + + (((y & ISM_MASK) * ism) >> ISM_SHIFT); + } + return x; +} + +/* Convert m (bps) into sm (bytes/psched us) */ +static u64 +m2sm(u32 m) +{ + u64 sm; + + sm = ((u64)m << SM_SHIFT); + sm += PSCHED_JIFFIE2US(HZ) - 1; + do_div(sm, PSCHED_JIFFIE2US(HZ)); + return sm; +} + +/* convert m (bps) into ism (psched us/byte) */ +static u64 +m2ism(u32 m) +{ + u64 ism; + + if (m == 0) + ism = HT_INFINITY; + else { + ism = ((u64)PSCHED_JIFFIE2US(HZ) << ISM_SHIFT); + ism += m - 1; + do_div(ism, m); + } + return ism; +} + +/* convert d (us) into dx (psched us) */ +static u64 +d2dx(u32 d) +{ + u64 dx; + + dx = ((u64)d * PSCHED_JIFFIE2US(HZ)); + dx += 1000000 - 1; + do_div(dx, 1000000); + return dx; +} + +/* convert sm (bytes/psched us) into m (bps) */ +static u32 +sm2m(u64 sm) +{ + u64 m; + + m = (sm * PSCHED_JIFFIE2US(HZ)) >> SM_SHIFT; + return (u32)m; +} + +/* convert dx (psched us) into d (us) */ +static u32 +dx2d(u64 dx) +{ + u64 d; + + d = dx * 1000000; + do_div(d, PSCHED_JIFFIE2US(HZ)); + return (u32)d; +} + +static void +sc2isc(struct tc_service_curve *sc, struct internal_sc *isc) +{ + isc->sm1 = m2sm(sc->m1); + isc->ism1 = m2ism(sc->m1); + isc->dx = d2dx(sc->d); + isc->dy = seg_x2y(isc->dx, isc->sm1); + isc->sm2 = m2sm(sc->m2); + isc->ism2 = m2ism(sc->m2); +} + +/* + * initialize the runtime service curve with the given internal + * service curve starting at (x, y). + */ +static void +rtsc_init(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y) +{ + rtsc->x = x; + rtsc->y = y; + rtsc->sm1 = isc->sm1; + rtsc->ism1 = isc->ism1; + rtsc->dx = isc->dx; + rtsc->dy = isc->dy; + rtsc->sm2 = isc->sm2; + rtsc->ism2 = isc->ism2; +} + +/* + * calculate the y-projection of the runtime service curve by the + * given x-projection value + */ +static u64 +rtsc_y2x(struct runtime_sc *rtsc, u64 y) +{ + u64 x; + + if (y < rtsc->y) + x = rtsc->x; + else if (y <= rtsc->y + rtsc->dy) { + /* x belongs to the 1st segment */ + if (rtsc->dy == 0) + x = rtsc->x + rtsc->dx; + else + x = rtsc->x + seg_y2x(y - rtsc->y, rtsc->ism1); + } else { + /* x belongs to the 2nd segment */ + x = rtsc->x + rtsc->dx + + seg_y2x(y - rtsc->y - rtsc->dy, rtsc->ism2); + } + return x; +} + +static u64 +rtsc_x2y(struct runtime_sc *rtsc, u64 x) +{ + u64 y; + + if (x <= rtsc->x) + y = rtsc->y; + else if (x <= rtsc->x + rtsc->dx) + /* y belongs to the 1st segment */ + y = rtsc->y + seg_x2y(x - rtsc->x, rtsc->sm1); + else + /* y belongs to the 2nd segment */ + y = rtsc->y + rtsc->dy + + seg_x2y(x - rtsc->x - rtsc->dx, rtsc->sm2); + return y; +} + +/* + * update the runtime service curve by taking the minimum of the current + * runtime service curve and the service curve starting at (x, y). + */ +static void +rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y) +{ + u64 y1, y2, dx, dy; + u32 dsm; + + if (isc->sm1 <= isc->sm2) { + /* service curve is convex */ + y1 = rtsc_x2y(rtsc, x); + if (y1 < y) + /* the current rtsc is smaller */ + return; + rtsc->x = x; + rtsc->y = y; + return; + } + + /* + * service curve is concave + * compute the two y values of the current rtsc + * y1: at x + * y2: at (x + dx) + */ + y1 = rtsc_x2y(rtsc, x); + if (y1 <= y) { + /* rtsc is below isc, no change to rtsc */ + return; + } + + y2 = rtsc_x2y(rtsc, x + isc->dx); + if (y2 >= y + isc->dy) { + /* rtsc is above isc, replace rtsc by isc */ + rtsc->x = x; + rtsc->y = y; + rtsc->dx = isc->dx; + rtsc->dy = isc->dy; + return; + } + + /* + * the two curves intersect + * compute the offsets (dx, dy) using the reverse + * function of seg_x2y() + * seg_x2y(dx, sm1) == seg_x2y(dx, sm2) + (y1 - y) + */ + dx = (y1 - y) << SM_SHIFT; + dsm = isc->sm1 - isc->sm2; + do_div(dx, dsm); + /* + * check if (x, y1) belongs to the 1st segment of rtsc. + * if so, add the offset. + */ + if (rtsc->x + rtsc->dx > x) + dx += rtsc->x + rtsc->dx - x; + dy = seg_x2y(dx, isc->sm1); + + rtsc->x = x; + rtsc->y = y; + rtsc->dx = dx; + rtsc->dy = dy; + return; +} + +static void +init_ed(struct hfsc_class *cl, unsigned int next_len) +{ + u64 cur_time; + + PSCHED_GET_TIME(cur_time); + + /* update the deadline curve */ + rtsc_min(&cl->cl_deadline, &cl->cl_rsc, cur_time, cl->cl_cumul); + + /* + * update the eligible curve. + * for concave, it is equal to the deadline curve. + * for convex, it is a linear curve with slope m2. + */ + cl->cl_eligible = cl->cl_deadline; + if (cl->cl_rsc.sm1 <= cl->cl_rsc.sm2) { + cl->cl_eligible.dx = 0; + cl->cl_eligible.dy = 0; + } + + /* compute e and d */ + cl->cl_e = rtsc_y2x(&cl->cl_eligible, cl->cl_cumul); + cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len); + + eltree_insert(cl); +} + +static void +update_ed(struct hfsc_class *cl, unsigned int next_len) +{ + cl->cl_e = rtsc_y2x(&cl->cl_eligible, cl->cl_cumul); + cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len); + + eltree_update(cl); +} + +static inline void +update_d(struct hfsc_class *cl, unsigned int next_len) +{ + cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len); +} + +static inline void +update_cfmin(struct hfsc_class *cl) +{ + rb_node_t *n = rb_first(&cl->cf_tree); + struct hfsc_class *p; + + if (n == NULL) { + cl->cl_cfmin = 0; + return; + } + p = rb_entry(n, struct hfsc_class, cf_node); + cl->cl_cfmin = p->cl_f; +} + +static void +init_vf(struct hfsc_class *cl, unsigned int len) +{ + struct hfsc_class *max_cl; + rb_node_t *n; + u64 vt, f, cur_time; + int go_active; + + cur_time = 0; + go_active = 1; + for (; cl->cl_parent != NULL; cl = cl->cl_parent) { + if (go_active && cl->cl_nactive++ == 0) + go_active = 1; + else + go_active = 0; + + if (go_active) { + n = rb_last(&cl->cl_parent->vt_tree); + if (n != NULL) { + max_cl = rb_entry(n, struct hfsc_class,vt_node); + /* + * set vt to the average of the min and max + * classes. if the parent's period didn't + * change, don't decrease vt of the class. + */ + vt = max_cl->cl_vt; + if (cl->cl_parent->cl_cvtmin != 0) + vt = (cl->cl_parent->cl_cvtmin + vt)/2; + + if (cl->cl_parent->cl_vtperiod != + cl->cl_parentperiod || vt > cl->cl_vt) + cl->cl_vt = vt; + } else { + /* + * first child for a new parent backlog period. + * add parent's cvtmax to cvtoff to make a new + * vt (vtoff + vt) larger than the vt in the + * last period for all children. + */ + vt = cl->cl_parent->cl_cvtmax; + cl->cl_parent->cl_cvtoff += vt; + cl->cl_parent->cl_cvtmax = 0; + cl->cl_parent->cl_cvtmin = 0; + cl->cl_vt = 0; + } + + cl->cl_vtoff = cl->cl_parent->cl_cvtoff - + cl->cl_pcvtoff; + + /* update the virtual curve */ + vt = cl->cl_vt + cl->cl_vtoff; + rtsc_min(&cl->cl_virtual, &cl->cl_fsc, vt, + cl->cl_total); + if (cl->cl_virtual.x == vt) { + cl->cl_virtual.x -= cl->cl_vtoff; + cl->cl_vtoff = 0; + } + cl->cl_vtadj = 0; + + cl->cl_vtperiod++; /* increment vt period */ + cl->cl_parentperiod = cl->cl_parent->cl_vtperiod; + if (cl->cl_parent->cl_nactive == 0) + cl->cl_parentperiod++; + cl->cl_f = 0; + + vttree_insert(cl); + cftree_insert(cl); + + if (cl->cl_flags & HFSC_USC) { + /* class has upper limit curve */ + if (cur_time == 0) + PSCHED_GET_TIME(cur_time); + + /* update the ulimit curve */ + rtsc_min(&cl->cl_ulimit, &cl->cl_usc, cur_time, + cl->cl_total); + /* compute myf */ + cl->cl_myf = rtsc_y2x(&cl->cl_ulimit, + cl->cl_total); + cl->cl_myfadj = 0; + } + } + + f = max(cl->cl_myf, cl->cl_cfmin); + if (f != cl->cl_f) { + cl->cl_f = f; + cftree_update(cl); + update_cfmin(cl->cl_parent); + } + } +} + +static void +update_vf(struct hfsc_class *cl, unsigned int len, u64 cur_time) +{ + u64 f; /* , myf_bound, delta; */ + int go_passive = 0; + + if (cl->qdisc->q.qlen == 0 && cl->cl_flags & HFSC_FSC) + go_passive = 1; + + for (; cl->cl_parent != NULL; cl = cl->cl_parent) { + cl->cl_total += len; + + if (!(cl->cl_flags & HFSC_FSC) || cl->cl_nactive == 0) + continue; + + if (go_passive && --cl->cl_nactive == 0) + go_passive = 1; + else + go_passive = 0; + + if (go_passive) { + /* no more active child, going passive */ + + /* update cvtmax of the parent class */ + if (cl->cl_vt > cl->cl_parent->cl_cvtmax) + cl->cl_parent->cl_cvtmax = cl->cl_vt; + + /* remove this class from the vt tree */ + vttree_remove(cl); + + cftree_remove(cl); + update_cfmin(cl->cl_parent); + + continue; + } + + /* + * update vt and f + */ + cl->cl_vt = rtsc_y2x(&cl->cl_virtual, cl->cl_total) + - cl->cl_vtoff + cl->cl_vtadj; + + /* + * if vt of the class is smaller than cvtmin, + * the class was skipped in the past due to non-fit. + * if so, we need to adjust vtadj. + */ + if (cl->cl_vt < cl->cl_parent->cl_cvtmin) { + cl->cl_vtadj += cl->cl_parent->cl_cvtmin - cl->cl_vt; + cl->cl_vt = cl->cl_parent->cl_cvtmin; + } + + /* update the vt tree */ + vttree_update(cl); + + if (cl->cl_flags & HFSC_USC) { + cl->cl_myf = cl->cl_myfadj + rtsc_y2x(&cl->cl_ulimit, + cl->cl_total); +#if 0 + /* + * This code causes classes to stay way under their + * limit when multiple classes are used at gigabit + * speed. needs investigation. -kaber + */ + /* + * if myf lags behind by more than one clock tick + * from the current time, adjust myfadj to prevent + * a rate-limited class from going greedy. + * in a steady state under rate-limiting, myf + * fluctuates within one clock tick. + */ + myf_bound = cur_time - PSCHED_JIFFIE2US(1); + if (cl->cl_myf < myf_bound) { + delta = cur_time - cl->cl_myf; + cl->cl_myfadj += delta; + cl->cl_myf += delta; + } +#endif + } + + f = max(cl->cl_myf, cl->cl_cfmin); + if (f != cl->cl_f) { + cl->cl_f = f; + cftree_update(cl); + update_cfmin(cl->cl_parent); + } + } +} + +static void +set_active(struct hfsc_class *cl, unsigned int len) +{ + if (cl->cl_flags & HFSC_RSC) + init_ed(cl, len); + if (cl->cl_flags & HFSC_FSC) + init_vf(cl, len); + + list_add_tail(&cl->dlist, &cl->sched->droplist); +} + +static void +set_passive(struct hfsc_class *cl) +{ + if (cl->cl_flags & HFSC_RSC) + eltree_remove(cl); + + list_del(&cl->dlist); + + /* + * vttree is now handled in update_vf() so that update_vf(cl, 0, 0) + * needs to be called explicitly to remove a class from vttree. + */ +} + +/* + * hack to get length of first packet in queue. + */ +static unsigned int +qdisc_peek_len(struct Qdisc *sch) +{ + struct sk_buff *skb; + unsigned int len; + + skb = sch->dequeue(sch); + if (skb == NULL) { + if (net_ratelimit()) + printk("qdisc_peek_len: non work-conserving qdisc ?\n"); + return 0; + } + len = skb->len; + if (unlikely(sch->ops->requeue(skb, sch) != NET_XMIT_SUCCESS)) { + if (net_ratelimit()) + printk("qdisc_peek_len: failed to requeue\n"); + return 0; + } + return len; +} + +static void +hfsc_purge_queue(struct Qdisc *sch, struct hfsc_class *cl) +{ + unsigned int len = cl->qdisc->q.qlen; + + qdisc_reset(cl->qdisc); + if (len > 0) { + update_vf(cl, 0, 0); + set_passive(cl); + sch->q.qlen -= len; + } +} + +static void +hfsc_adjust_levels(struct hfsc_class *cl) +{ + struct hfsc_class *p; + unsigned int level; + + do { + level = 0; + list_for_each_entry(p, &cl->children, siblings) { + if (p->level > level) + level = p->level; + } + cl->level = level + 1; + } while ((cl = cl->cl_parent) != NULL); +} + +static inline unsigned int +hfsc_hash(u32 h) +{ + h ^= h >> 8; + h ^= h >> 4; + + return h & (HFSC_HSIZE - 1); +} + +static inline struct hfsc_class * +hfsc_find_class(u32 classid, struct Qdisc *sch) +{ + struct hfsc_sched *q = (struct hfsc_sched *)sch->data; + struct hfsc_class *cl; + + list_for_each_entry(cl, &q->clhash[hfsc_hash(classid)], hlist) { + if (cl->classid == classid) + return cl; + } + return NULL; +} + +static void +hfsc_change_rsc(struct hfsc_class *cl, struct tc_service_curve *rsc, + u64 cur_time) +{ + sc2isc(rsc, &cl->cl_rsc); + rtsc_init(&cl->cl_deadline, &cl->cl_rsc, cur_time, cl->cl_cumul); + cl->cl_eligible = cl->cl_deadline; + if (cl->cl_rsc.sm1 <= cl->cl_rsc.sm2) { + cl->cl_eligible.dx = 0; + cl->cl_eligible.dy = 0; + } + cl->cl_flags |= HFSC_RSC; +} + +static void +hfsc_change_fsc(struct hfsc_class *cl, struct tc_service_curve *fsc) +{ + sc2isc(fsc, &cl->cl_fsc); + rtsc_init(&cl->cl_virtual, &cl->cl_fsc, cl->cl_vt, cl->cl_total); + cl->cl_flags |= HFSC_FSC; +} + +static void +hfsc_change_usc(struct hfsc_class *cl, struct tc_service_curve *usc, + u64 cur_time) +{ + sc2isc(usc, &cl->cl_usc); + rtsc_init(&cl->cl_ulimit, &cl->cl_usc, cur_time, cl->cl_total); + cl->cl_flags |= HFSC_USC; +} + +static int +hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + struct rtattr **tca, unsigned long *arg) +{ + struct hfsc_sched *q = (struct hfsc_sched *)sch->data; + struct hfsc_class *cl = (struct hfsc_class *)*arg; + struct hfsc_class *parent = NULL; + struct rtattr *opt = tca[TCA_OPTIONS-1]; + struct rtattr *tb[TCA_HFSC_MAX]; + struct tc_service_curve *rsc = NULL, *fsc = NULL, *usc = NULL; + u64 cur_time; + + if (opt == NULL || + rtattr_parse(tb, TCA_HFSC_MAX, RTA_DATA(opt), RTA_PAYLOAD(opt))) + return -EINVAL; + + if (tb[TCA_HFSC_RSC-1]) { + if (RTA_PAYLOAD(tb[TCA_HFSC_RSC-1]) < sizeof(*rsc)) + return -EINVAL; + rsc = RTA_DATA(tb[TCA_HFSC_RSC-1]); + if (rsc->m1 == 0 && rsc->m2 == 0) + rsc = NULL; + } + + if (tb[TCA_HFSC_FSC-1]) { + if (RTA_PAYLOAD(tb[TCA_HFSC_FSC-1]) < sizeof(*fsc)) + return -EINVAL; + fsc = RTA_DATA(tb[TCA_HFSC_FSC-1]); + if (fsc->m1 == 0 && fsc->m2 == 0) + fsc = NULL; + } + + if (tb[TCA_HFSC_USC-1]) { + if (RTA_PAYLOAD(tb[TCA_HFSC_USC-1]) < sizeof(*usc)) + return -EINVAL; + usc = RTA_DATA(tb[TCA_HFSC_USC-1]); + if (usc->m1 == 0 && usc->m2 == 0) + usc = NULL; + } + + if (cl != NULL) { + if (parentid) { + if (cl->cl_parent && cl->cl_parent->classid != parentid) + return -EINVAL; + if (cl->cl_parent == NULL && parentid != TC_H_ROOT) + return -EINVAL; + } + PSCHED_GET_TIME(cur_time); + + sch_tree_lock(sch); + if (rsc != NULL) + hfsc_change_rsc(cl, rsc, cur_time); + if (fsc != NULL) + hfsc_change_fsc(cl, fsc); + if (usc != NULL) + hfsc_change_usc(cl, usc, cur_time); + + if (cl->qdisc->q.qlen != 0) { + if (cl->cl_flags & HFSC_RSC) + update_ed(cl, qdisc_peek_len(cl->qdisc)); + if (cl->cl_flags & HFSC_FSC) + update_vf(cl, 0, cur_time); + } + sch_tree_unlock(sch); + +#ifdef CONFIG_NET_ESTIMATOR + if (tca[TCA_RATE-1]) { + qdisc_kill_estimator(&cl->stats); + qdisc_new_estimator(&cl->stats, tca[TCA_RATE-1]); + } +#endif + return 0; + } + + if (parentid == TC_H_ROOT) + return -EEXIST; + + parent = &q->root; + if (parentid) { + parent = hfsc_find_class(parentid, sch); + if (parent == NULL) + return -ENOENT; + } + + if (classid == 0 || TC_H_MAJ(classid ^ sch->handle) != 0) + return -EINVAL; + if (hfsc_find_class(classid, sch)) + return -EEXIST; + + if (rsc == NULL && fsc == NULL) + return -EINVAL; + + cl = kmalloc(sizeof(struct hfsc_class), GFP_KERNEL); + if (cl == NULL) + return -ENOBUFS; + memset(cl, 0, sizeof(struct hfsc_class)); + + if (rsc != NULL) + hfsc_change_rsc(cl, rsc, 0); + if (fsc != NULL) + hfsc_change_fsc(cl, fsc); + if (usc != NULL) + hfsc_change_usc(cl, usc, 0); + + cl->refcnt = 1; + cl->classid = classid; + cl->sched = q; + cl->cl_parent = parent; + cl->qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops); + if (cl->qdisc == NULL) + cl->qdisc = &noop_qdisc; + cl->stats.lock = &sch->dev->queue_lock; + INIT_LIST_HEAD(&cl->children); + cl->vt_tree = RB_ROOT; + cl->cf_tree = RB_ROOT; + + sch_tree_lock(sch); + list_add_tail(&cl->hlist, &q->clhash[hfsc_hash(classid)]); + list_add_tail(&cl->siblings, &parent->children); + if (parent->level == 0) + hfsc_purge_queue(sch, parent); + hfsc_adjust_levels(parent); + cl->cl_pcvtoff = parent->cl_cvtoff; + sch_tree_unlock(sch); + +#ifdef CONFIG_NET_ESTIMATOR + if (tca[TCA_RATE-1]) + qdisc_new_estimator(&cl->stats, tca[TCA_RATE-1]); +#endif + *arg = (unsigned long)cl; + return 0; +} + +static void +hfsc_destroy_filters(struct tcf_proto **fl) +{ + struct tcf_proto *tp; + + while ((tp = *fl) != NULL) { + *fl = tp->next; + tcf_destroy(tp); + } +} + +static void +hfsc_destroy_class(struct Qdisc *sch, struct hfsc_class *cl) +{ + struct hfsc_sched *q = (struct hfsc_sched *)sch->data; + + hfsc_destroy_filters(&cl->filter_list); + qdisc_destroy(cl->qdisc); +#ifdef CONFIG_NET_ESTIMATOR + qdisc_kill_estimator(&cl->stats); +#endif + if (cl != &q->root) + kfree(cl); +} + +static int +hfsc_delete_class(struct Qdisc *sch, unsigned long arg) +{ + struct hfsc_sched *q = (struct hfsc_sched *)sch->data; + struct hfsc_class *cl = (struct hfsc_class *)arg; + + if (cl->level > 0 || cl->filter_cnt > 0 || cl == &q->root) + return -EBUSY; + + sch_tree_lock(sch); + + list_del(&cl->hlist); + list_del(&cl->siblings); + hfsc_adjust_levels(cl->cl_parent); + hfsc_purge_queue(sch, cl); + if (--cl->refcnt == 0) + hfsc_destroy_class(sch, cl); + + sch_tree_unlock(sch); + return 0; +} + +static struct hfsc_class * +hfsc_classify(struct sk_buff *skb, struct Qdisc *sch) +{ + struct hfsc_sched *q = (struct hfsc_sched *)sch->data; + struct hfsc_class *cl; + struct tcf_result res; + struct tcf_proto *tcf; + int result; + + if (TC_H_MAJ(skb->priority ^ sch->handle) == 0 && + (cl = hfsc_find_class(skb->priority, sch)) != NULL) + if (cl->level == 0) + return cl; + + tcf = q->root.filter_list; + while (tcf && (result = tc_classify(skb, tcf, &res)) >= 0) { +#ifdef CONFIG_NET_CLS_POLICE + if (result == TC_POLICE_SHOT) + return NULL; +#endif + if ((cl = (struct hfsc_class *)res.class) == NULL) { + if ((cl = hfsc_find_class(res.classid, sch)) == NULL) + break; /* filter selected invalid classid */ + } + + if (cl->level == 0) + return cl; /* hit leaf class */ + + /* apply inner filter chain */ + tcf = cl->filter_list; + } + + /* classification failed, try default class */ + cl = hfsc_find_class(TC_H_MAKE(TC_H_MAJ(sch->handle), q->defcls), sch); + if (cl == NULL || cl->level > 0) + return NULL; + + return cl; +} + +static int +hfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, + struct Qdisc **old) +{ + struct hfsc_class *cl = (struct hfsc_class *)arg; + + if (cl == NULL) + return -ENOENT; + if (cl->level > 0) + return -EINVAL; + if (new == NULL) { + new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops); + if (new == NULL) + new = &noop_qdisc; + } + + sch_tree_lock(sch); + hfsc_purge_queue(sch, cl); + *old = xchg(&cl->qdisc, new); + sch_tree_unlock(sch); + return 0; +} + +static struct Qdisc * +hfsc_class_leaf(struct Qdisc *sch, unsigned long arg) +{ + struct hfsc_class *cl = (struct hfsc_class *)arg; + + if (cl != NULL && cl->level == 0) + return cl->qdisc; + + return NULL; +} + +static unsigned long +hfsc_get_class(struct Qdisc *sch, u32 classid) +{ + struct hfsc_class *cl = hfsc_find_class(classid, sch); + + if (cl != NULL) + cl->refcnt++; + + return (unsigned long)cl; +} + +static void +hfsc_put_class(struct Qdisc *sch, unsigned long arg) +{ + struct hfsc_class *cl = (struct hfsc_class *)arg; + + if (--cl->refcnt == 0) + hfsc_destroy_class(sch, cl); +} + +static unsigned long +hfsc_bind_tcf(struct Qdisc *sch, unsigned long parent, u32 classid) +{ + struct hfsc_class *p = (struct hfsc_class *)parent; + struct hfsc_class *cl = hfsc_find_class(classid, sch); + + if (cl != NULL) { + if (p != NULL && p->level <= cl->level) + return 0; + cl->filter_cnt++; + } + + return (unsigned long)cl; +} + +static void +hfsc_unbind_tcf(struct Qdisc *sch, unsigned long arg) +{ + struct hfsc_class *cl = (struct hfsc_class *)arg; + + cl->filter_cnt--; +} + +static struct tcf_proto ** +hfsc_tcf_chain(struct Qdisc *sch, unsigned long arg) +{ + struct hfsc_sched *q = (struct hfsc_sched *)sch->data; + struct hfsc_class *cl = (struct hfsc_class *)arg; + + if (cl == NULL) + cl = &q->root; + + return &cl->filter_list; +} + +static int +hfsc_dump_sc(struct sk_buff *skb, int attr, struct internal_sc *sc) +{ + struct tc_service_curve tsc; + + tsc.m1 = sm2m(sc->sm1); + tsc.d = dx2d(sc->dx); + tsc.m2 = sm2m(sc->sm2); + RTA_PUT(skb, attr, sizeof(tsc), &tsc); + + return skb->len; + + rtattr_failure: + return -1; +} + +static inline int +hfsc_dump_curves(struct sk_buff *skb, struct hfsc_class *cl) +{ + if ((cl->cl_flags & HFSC_RSC) && + (hfsc_dump_sc(skb, TCA_HFSC_RSC, &cl->cl_rsc) < 0)) + goto rtattr_failure; + + if ((cl->cl_flags & HFSC_FSC) && + (hfsc_dump_sc(skb, TCA_HFSC_FSC, &cl->cl_fsc) < 0)) + goto rtattr_failure; + + if ((cl->cl_flags & HFSC_USC) && + (hfsc_dump_sc(skb, TCA_HFSC_USC, &cl->cl_usc) < 0)) + goto rtattr_failure; + + return skb->len; + + rtattr_failure: + return -1; +} + +static inline int +hfsc_dump_stats(struct sk_buff *skb, struct hfsc_class *cl) +{ + cl->stats.qlen = cl->qdisc->q.qlen; + if (qdisc_copy_stats(skb, &cl->stats) < 0) + goto rtattr_failure; + + return skb->len; + + rtattr_failure: + return -1; +} + +static inline int +hfsc_dump_xstats(struct sk_buff *skb, struct hfsc_class *cl) +{ + struct tc_hfsc_stats xstats; + + xstats.level = cl->level; + xstats.period = cl->cl_vtperiod; + xstats.work = cl->cl_total; + xstats.rtwork = cl->cl_cumul; + RTA_PUT(skb, TCA_XSTATS, sizeof(xstats), &xstats); + + return skb->len; + + rtattr_failure: + return -1; +} + +static int +hfsc_dump_class(struct Qdisc *sch, unsigned long arg, struct sk_buff *skb, + struct tcmsg *tcm) +{ + struct hfsc_class *cl = (struct hfsc_class *)arg; + unsigned char *b = skb->tail; + struct rtattr *rta = (struct rtattr *)b; + + tcm->tcm_parent = cl->cl_parent ? cl->cl_parent->classid : TC_H_ROOT; + tcm->tcm_handle = cl->classid; + if (cl->level == 0) + tcm->tcm_info = cl->qdisc->handle; + + RTA_PUT(skb, TCA_OPTIONS, 0, NULL); + if (hfsc_dump_curves(skb, cl) < 0) + goto rtattr_failure; + rta->rta_len = skb->tail - b; + + if ((hfsc_dump_stats(skb, cl) < 0) || + (hfsc_dump_xstats(skb, cl) < 0)) + goto rtattr_failure; + + return skb->len; + + rtattr_failure: + skb_trim(skb, b - skb->data); + return -1; +} + +static void +hfsc_walk(struct Qdisc *sch, struct qdisc_walker *arg) +{ + struct hfsc_sched *q = (struct hfsc_sched *)sch->data; + struct hfsc_class *cl; + unsigned int i; + + if (arg->stop) + return; + + for (i = 0; i < HFSC_HSIZE; i++) { + list_for_each_entry(cl, &q->clhash[i], hlist) { + if (arg->count < arg->skip) { + arg->count++; + continue; + } + if (arg->fn(sch, (unsigned long)cl, arg) < 0) { + arg->stop = 1; + return; + } + arg->count++; + } + } +} + +static void +hfsc_watchdog(unsigned long arg) +{ + struct Qdisc *sch = (struct Qdisc *)arg; + + sch->flags &= ~TCQ_F_THROTTLED; + netif_schedule(sch->dev); +} + +static void +hfsc_schedule_watchdog(struct Qdisc *sch, u64 cur_time) +{ + struct hfsc_sched *q = (struct hfsc_sched *)sch->data; + struct hfsc_class *cl; + u64 next_time = 0; + long delay; + + if ((cl = eltree_get_minel(q)) != NULL) + next_time = cl->cl_e; + if (q->root.cl_cfmin != 0) { + if (next_time == 0 || next_time > q->root.cl_cfmin) + next_time = q->root.cl_cfmin; + } + ASSERT(next_time != 0); + delay = next_time - cur_time; + delay = PSCHED_US2JIFFIE(delay); + + sch->flags |= TCQ_F_THROTTLED; + mod_timer(&q->wd_timer, jiffies + delay); +} + +static int +hfsc_init_qdisc(struct Qdisc *sch, struct rtattr *opt) +{ + struct hfsc_sched *q = (struct hfsc_sched *)sch->data; + struct tc_hfsc_qopt *qopt; + unsigned int i; + + if (opt == NULL || RTA_PAYLOAD(opt) < sizeof(*qopt)) + return -EINVAL; + qopt = RTA_DATA(opt); + + sch->stats.lock = &sch->dev->queue_lock; + + q->defcls = qopt->defcls; + for (i = 0; i < HFSC_HSIZE; i++) + INIT_LIST_HEAD(&q->clhash[i]); + q->eligible = RB_ROOT; + INIT_LIST_HEAD(&q->droplist); + skb_queue_head_init(&q->requeue); + + q->root.refcnt = 1; + q->root.classid = sch->handle; + q->root.sched = q; + q->root.qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops); + if (q->root.qdisc == NULL) + q->root.qdisc = &noop_qdisc; + q->root.stats.lock = &sch->dev->queue_lock; + INIT_LIST_HEAD(&q->root.children); + q->root.vt_tree = RB_ROOT; + q->root.cf_tree = RB_ROOT; + + list_add(&q->root.hlist, &q->clhash[hfsc_hash(q->root.classid)]); + + init_timer(&q->wd_timer); + q->wd_timer.function = hfsc_watchdog; + q->wd_timer.data = (unsigned long)sch; + + MOD_INC_USE_COUNT; + return 0; +} + +static int +hfsc_change_qdisc(struct Qdisc *sch, struct rtattr *opt) +{ + struct hfsc_sched *q = (struct hfsc_sched *)sch->data; + struct tc_hfsc_qopt *qopt; + + if (opt == NULL || RTA_PAYLOAD(opt) < sizeof(*qopt)) + return -EINVAL;; + qopt = RTA_DATA(opt); + + sch_tree_lock(sch); + q->defcls = qopt->defcls; + sch_tree_unlock(sch); + + return 0; +} + +static void +hfsc_reset_class(struct hfsc_class *cl) +{ + cl->cl_total = 0; + cl->cl_cumul = 0; + cl->cl_d = 0; + cl->cl_e = 0; + cl->cl_vt = 0; + cl->cl_vtadj = 0; + cl->cl_vtoff = 0; + cl->cl_cvtmin = 0; + cl->cl_cvtmax = 0; + cl->cl_cvtoff = 0; + cl->cl_pcvtoff = 0; + cl->cl_vtperiod = 0; + cl->cl_parentperiod = 0; + cl->cl_f = 0; + cl->cl_myf = 0; + cl->cl_myfadj = 0; + cl->cl_cfmin = 0; + cl->cl_nactive = 0; + + cl->vt_tree = RB_ROOT; + cl->cf_tree = RB_ROOT; + qdisc_reset(cl->qdisc); + + if (cl->cl_flags & HFSC_RSC) + rtsc_init(&cl->cl_deadline, &cl->cl_rsc, 0, 0); + if (cl->cl_flags & HFSC_FSC) + rtsc_init(&cl->cl_virtual, &cl->cl_fsc, 0, 0); + if (cl->cl_flags & HFSC_USC) + rtsc_init(&cl->cl_ulimit, &cl->cl_usc, 0, 0); +} + +static void +hfsc_reset_qdisc(struct Qdisc *sch) +{ + struct hfsc_sched *q = (struct hfsc_sched *)sch->data; + struct hfsc_class *cl; + unsigned int i; + + for (i = 0; i < HFSC_HSIZE; i++) { + list_for_each_entry(cl, &q->clhash[i], hlist) + hfsc_reset_class(cl); + } + __skb_queue_purge(&q->requeue); + q->eligible = RB_ROOT; + INIT_LIST_HEAD(&q->droplist); + del_timer(&q->wd_timer); + sch->flags &= ~TCQ_F_THROTTLED; + sch->q.qlen = 0; +} + +static void +hfsc_destroy_qdisc(struct Qdisc *sch) +{ + struct hfsc_sched *q = (struct hfsc_sched *)sch->data; + struct hfsc_class *cl, *next; + unsigned int i; + + for (i = 0; i < HFSC_HSIZE; i++) { + list_for_each_entry_safe(cl, next, &q->clhash[i], hlist) + hfsc_destroy_class(sch, cl); + } + __skb_queue_purge(&q->requeue); + del_timer(&q->wd_timer); + MOD_DEC_USE_COUNT; +} + +static int +hfsc_dump_qdisc(struct Qdisc *sch, struct sk_buff *skb) +{ + struct hfsc_sched *q = (struct hfsc_sched *)sch->data; + unsigned char *b = skb->tail; + struct tc_hfsc_qopt qopt; + + qopt.defcls = q->defcls; + RTA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt); + + return skb->len; + + rtattr_failure: + skb_trim(skb, b - skb->data); + return -1; +} + +static int +hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch) +{ + struct hfsc_class *cl = hfsc_classify(skb, sch); + unsigned int len = skb->len; + int err; + + if (cl == NULL) { + kfree_skb(skb); + sch->stats.drops++; + return NET_XMIT_DROP; + } + + err = cl->qdisc->enqueue(skb, cl->qdisc); + if (unlikely(err != NET_XMIT_SUCCESS)) { + cl->stats.drops++; + sch->stats.drops++; + return err; + } + + if (cl->qdisc->q.qlen == 1) + set_active(cl, len); + + cl->stats.packets++; + cl->stats.bytes += len; + sch->stats.packets++; + sch->stats.bytes += len; + sch->q.qlen++; + + return NET_XMIT_SUCCESS; +} + +static struct sk_buff * +hfsc_dequeue(struct Qdisc *sch) +{ + struct hfsc_sched *q = (struct hfsc_sched *)sch->data; + struct hfsc_class *cl; + struct sk_buff *skb; + u64 cur_time; + unsigned int next_len; + int realtime = 0; + + if (sch->q.qlen == 0) + return NULL; + if ((skb = __skb_dequeue(&q->requeue))) + goto out; + + PSCHED_GET_TIME(cur_time); + + /* + * if there are eligible classes, use real-time criteria. + * find the class with the minimum deadline among + * the eligible classes. + */ + if ((cl = eltree_get_mindl(q, cur_time)) != NULL) { + realtime = 1; + } else { + /* + * use link-sharing criteria + * get the class with the minimum vt in the hierarchy + */ + cl = vttree_get_minvt(&q->root, cur_time); + if (cl == NULL) { + sch->stats.overlimits++; + hfsc_schedule_watchdog(sch, cur_time); + return NULL; + } + } + + skb = cl->qdisc->dequeue(cl->qdisc); + if (skb == NULL) { + if (net_ratelimit()) + printk("HFSC: Non-work-conserving qdisc ?\n"); + return NULL; + } + + update_vf(cl, skb->len, cur_time); + if (realtime) + cl->cl_cumul += skb->len; + + if (cl->qdisc->q.qlen != 0) { + if (cl->cl_flags & HFSC_RSC) { + /* update ed */ + next_len = qdisc_peek_len(cl->qdisc); + if (realtime) + update_ed(cl, next_len); + else + update_d(cl, next_len); + } + } else { + /* the class becomes passive */ + set_passive(cl); + } + + out: + sch->flags &= ~TCQ_F_THROTTLED; + sch->q.qlen--; + + return skb; +} + +static int +hfsc_requeue(struct sk_buff *skb, struct Qdisc *sch) +{ + struct hfsc_sched *q = (struct hfsc_sched *)sch->data; + + __skb_queue_head(&q->requeue, skb); + sch->q.qlen++; + return NET_XMIT_SUCCESS; +} + +static unsigned int +hfsc_drop(struct Qdisc *sch) +{ + struct hfsc_sched *q = (struct hfsc_sched *)sch->data; + struct hfsc_class *cl; + unsigned int len; + + list_for_each_entry(cl, &q->droplist, dlist) { + if (cl->qdisc->ops->drop != NULL && + (len = cl->qdisc->ops->drop(cl->qdisc)) > 0) { + if (cl->qdisc->q.qlen == 0) { + update_vf(cl, 0, 0); + set_passive(cl); + } else { + list_move_tail(&cl->dlist, &q->droplist); + } + cl->stats.drops++; + sch->stats.drops++; + sch->q.qlen--; + return len; + } + } + return 0; +} + +static struct Qdisc_class_ops hfsc_class_ops = { + .change = hfsc_change_class, + .delete = hfsc_delete_class, + .graft = hfsc_graft_class, + .leaf = hfsc_class_leaf, + .get = hfsc_get_class, + .put = hfsc_put_class, + .bind_tcf = hfsc_bind_tcf, + .unbind_tcf = hfsc_unbind_tcf, + .tcf_chain = hfsc_tcf_chain, + .dump = hfsc_dump_class, + .walk = hfsc_walk +}; + +struct Qdisc_ops hfsc_qdisc_ops = { + .id = "hfsc", + .init = hfsc_init_qdisc, + .change = hfsc_change_qdisc, + .reset = hfsc_reset_qdisc, + .destroy = hfsc_destroy_qdisc, + .dump = hfsc_dump_qdisc, + .enqueue = hfsc_enqueue, + .dequeue = hfsc_dequeue, + .requeue = hfsc_requeue, + .drop = hfsc_drop, + .cl_ops = &hfsc_class_ops, + .priv_size = sizeof(struct hfsc_sched) +}; + +static int __init +hfsc_init(void) +{ + return register_qdisc(&hfsc_qdisc_ops); +} + +static void __exit +hfsc_cleanup(void) +{ + unregister_qdisc(&hfsc_qdisc_ops); +} + +MODULE_LICENSE("GPL"); +module_init(hfsc_init); +module_exit(hfsc_cleanup); diff --git a/release/src/linux/linux/net/sched/sch_htb.c b/release/src/linux/linux/net/sched/sch_htb.c index 7539e490..944cb555 100644 --- a/release/src/linux/linux/net/sched/sch_htb.c +++ b/release/src/linux/linux/net/sched/sch_htb.c @@ -9,6 +9,8 @@ * Authors: Martin Devera, <devik@cdi.cz> * * Credits (in time order) for older HTB versions: + * Stef Coene <stef.coene@docum.org> + * HTB support at LARTC mailing list * Ondrej Kraus, <krauso@barr.cz> * found missing INIT_QDISC(htb) * Vladimir Smelhaus, Aamer Akhter, Bert Hubert @@ -17,9 +19,13 @@ * code review and helpful comments on shaping * Tomasz Wrona, <tw@eter.tym.pl> * created test case so that I was able to fix nasty bug + * Wilfried Weissmann + * spotted bug in dequeue code and helped with fix + * Jiri Fojtasek + * fixed requeue routine * and many others. thanks. * - * $Id: sch_htb.c,v 1.1.1.4 2003/10/14 08:09:35 sparq Exp $ + * $Id: sch_htb.c,v 1.25 2003/12/07 11:08:25 devik Exp devik $ */ #include <linux/config.h> #include <linux/module.h> @@ -66,21 +72,17 @@ #define HTB_HSIZE 16 /* classid hash size */ #define HTB_EWMAC 2 /* rate average over HTB_EWMAC*HTB_HSIZE sec */ -#define HTB_DEBUG 1 /* compile debugging support (activated by tc tool) */ +//#define HTB_DEBUG 1 /* compile debugging support (activated by tc tool) */ #define HTB_RATECM 1 /* whether to use rate computer */ -#define HTB_HYSTERESIS 1/* whether to use mode hysteresis for speedup */ +#define HTB_HYSTERESIS 0/* whether to use mode hysteresis for speedup */ #define HTB_QLOCK(S) spin_lock_bh(&(S)->dev->queue_lock) #define HTB_QUNLOCK(S) spin_unlock_bh(&(S)->dev->queue_lock) -#define HTB_VER 0x30007 /* major must be matched with number suplied by TC as version */ +#define HTB_VER 0x30011 /* major must be matched with number suplied by TC as version */ #if HTB_VER >> 16 != TC_HTB_PROTOVER #error "Mismatched sch_htb.c and pkt_sch.h" #endif -/* temporary debug defines to be removed after beta stage */ -#define DEVIK_MEND(N) -#define DEVIK_MSTART(N) - /* debugging support; S is subsystem, these are defined: 0 - netlink messages 1 - enqueue @@ -100,13 +102,16 @@ from LSB */ #ifdef HTB_DEBUG -#define HTB_DBG(S,L,FMT,ARG...) if (((q->debug>>(2*S))&3) >= L) \ +#define HTB_DBG_COND(S,L) (((q->debug>>(2*S))&3) >= L) +#define HTB_DBG(S,L,FMT,ARG...) if (HTB_DBG_COND(S,L)) \ printk(KERN_DEBUG FMT,##ARG) #define HTB_CHCL(cl) BUG_TRAP((cl)->magic == HTB_CMAGIC) #define HTB_PASSQ q, #define HTB_ARGQ struct htb_sched *q, #define static +#undef __inline__ #define __inline__ +#undef inline #define inline #define HTB_CMAGIC 0xFEFAFEF1 #define htb_safe_rb_erase(N,R) do { BUG_TRAP((N)->rb_color != -1); \ @@ -114,6 +119,7 @@ rb_erase(N,R); \ (N)->rb_color = -1; } while (0) #else +#define HTB_DBG_COND(S,L) (0) #define HTB_DBG(S,L,FMT,ARG...) #define HTB_PASSQ #define HTB_ARGQ @@ -166,6 +172,11 @@ struct htb_class struct htb_class_inner { rb_root_t feed[TC_HTB_NUMPRIO]; /* feed trees */ rb_node_t *ptr[TC_HTB_NUMPRIO]; /* current class ptr */ + /* When class changes from state 1->2 and disconnects from + parent's feed then we lost ptr value and start from the + first child again. Here we store classid of the + last valid ptr (used when ptr is NULL). */ + u32 last_ptr_id[TC_HTB_NUMPRIO]; } inner; } un; rb_node_t node[TC_HTB_NUMPRIO]; /* node for self or feed tree */ @@ -212,6 +223,7 @@ struct htb_sched rb_root_t row[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO]; int row_mask[TC_HTB_MAXDEPTH]; rb_node_t *ptr[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO]; + u32 last_ptr_id[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO]; /* self wait list - roots of wait PQs per row */ rb_root_t wait_pq[TC_HTB_MAXDEPTH]; @@ -219,6 +231,9 @@ struct htb_sched /* time of nearest event per level (row) */ unsigned long near_ev_cache[TC_HTB_MAXDEPTH]; + /* cached value of jiffies in dequeue */ + unsigned long jiffies; + /* whether we hit non-work conserving class during this dequeue; we use */ int nwc_hit; /* this to disable mindelay complaint in dequeue */ @@ -297,7 +312,7 @@ static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch) rules in it */ if (skb->priority == sch->handle) return HTB_DIRECT; /* X:0 (direct flow) selected */ - if ((cl = htb_find(skb->priority,sch)) != NULL) + if ((cl = htb_find(skb->priority,sch)) != NULL && cl->level == 0) return cl; tcf = q->filter_list; @@ -338,7 +353,7 @@ static void htb_next_rb_node(rb_node_t **n); static void htb_debug_dump (struct htb_sched *q) { int i,p; - printk(KERN_DEBUG "htb*g j=%lu\n",jiffies); + printk(KERN_DEBUG "htb*g j=%lu lj=%lu\n",jiffies,q->jiffies); /* rows */ for (i=TC_HTB_MAXDEPTH-1;i>=0;i--) { printk(KERN_DEBUG "htb*r%d m=%x",i,q->row_mask[i]); @@ -421,26 +436,24 @@ static void htb_add_to_wait_tree (struct htb_sched *q, if ((delay <= 0 || delay > cl->mbuffer) && net_ratelimit()) printk(KERN_ERR "HTB: suspicious delay in wait_tree d=%ld cl=%X h=%d\n",delay,cl->classid,debug_hint); #endif - DEVIK_MSTART(9); - cl->pq_key = jiffies + PSCHED_US2JIFFIE(delay); - if (cl->pq_key == jiffies) + cl->pq_key = q->jiffies + PSCHED_US2JIFFIE(delay); + if (cl->pq_key == q->jiffies) cl->pq_key++; /* update the nearest event cache */ - if (q->near_ev_cache[cl->level] - cl->pq_key < 0x80000000) + if (time_after(q->near_ev_cache[cl->level], cl->pq_key)) q->near_ev_cache[cl->level] = cl->pq_key; while (*p) { struct htb_class *c; parent = *p; c = rb_entry(parent, struct htb_class, pq_node); - if (cl->pq_key - c->pq_key < 0x80000000) + if (time_after_eq(cl->pq_key, c->pq_key)) p = &parent->rb_right; else p = &parent->rb_left; } rb_link_node(&cl->pq_node, parent, p); rb_insert_color(&cl->pq_node, &q->wait_pq[cl->level]); - DEVIK_MEND(9); } /** @@ -453,12 +466,14 @@ static void htb_next_rb_node(rb_node_t **n) { rb_node_t *p; if ((*n)->rb_right) { + /* child at right. use it or its leftmost ancestor */ *n = (*n)->rb_right; while ((*n)->rb_left) *n = (*n)->rb_left; return; } while ((p = (*n)->rb_parent) != NULL) { + /* if we've arrived from left child then we have next node */ if (p->rb_left == *n) break; *n = p; } @@ -567,8 +582,13 @@ static void htb_deactivate_prios(struct htb_sched *q, struct htb_class *cl) int prio = ffz(~m); m &= ~(1 << prio); - if (p->un.inner.ptr[prio] == cl->node+prio) - htb_next_rb_node(p->un.inner.ptr + prio); + if (p->un.inner.ptr[prio] == cl->node+prio) { + /* we are removing child which is pointed to from + parent feed - forget the pointer but remember + classid */ + p->un.inner.last_ptr_id[prio] = cl->classid; + p->un.inner.ptr[prio] = NULL; + } htb_safe_rb_erase(cl->node + prio,p->un.inner.feed + prio); @@ -602,7 +622,7 @@ htb_class_mode(struct htb_class *cl,long *diff) long toks; if ((toks = (cl->ctokens + *diff)) < ( -#ifdef HTB_HYSTERESIS +#if HTB_HYSTERESIS cl->cmode != HTB_CANT_SEND ? -cl->cbuffer : #endif 0)) { @@ -610,7 +630,7 @@ htb_class_mode(struct htb_class *cl,long *diff) return HTB_CANT_SEND; } if ((toks = (cl->tokens + *diff)) >= ( -#ifdef HTB_HYSTERESIS +#if HTB_HYSTERESIS cl->cmode == HTB_CAN_SEND ? -cl->buffer : #endif 0)) @@ -689,7 +709,6 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch) struct htb_sched *q = (struct htb_sched *)sch->data; struct htb_class *cl = htb_classify(skb,sch); - DEVIK_MSTART(0); if (cl == HTB_DIRECT || !cl) { /* enqueue to helper queue */ if (q->direct_queue.qlen < q->direct_qlen && cl) { @@ -698,25 +717,20 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch) } else { kfree_skb (skb); sch->stats.drops++; - DEVIK_MEND(0); return NET_XMIT_DROP; } } else if (cl->un.leaf.q->enqueue(skb, cl->un.leaf.q) != NET_XMIT_SUCCESS) { sch->stats.drops++; cl->stats.drops++; - DEVIK_MEND(0); return NET_XMIT_DROP; } else { cl->stats.packets++; cl->stats.bytes += skb->len; - DEVIK_MSTART(1); htb_activate (q,cl); - DEVIK_MEND(1); } sch->q.qlen++; sch->stats.packets++; sch->stats.bytes += skb->len; - HTB_DBG(1,1,"htb_enq_ok cl=%X skb=%p\n",cl?cl->classid:0,skb); - DEVIK_MEND(0); + HTB_DBG(1,1,"htb_enq_ok cl=%X skb=%p\n",(cl && cl != HTB_DIRECT)?cl->classid:0,skb); return NET_XMIT_SUCCESS; } @@ -725,16 +739,18 @@ static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch) { struct htb_sched *q = (struct htb_sched *)sch->data; struct htb_class *cl = htb_classify(skb,sch); + struct sk_buff *tskb; if (cl == HTB_DIRECT || !cl) { /* enqueue to helper queue */ if (q->direct_queue.qlen < q->direct_qlen && cl) { - __skb_queue_tail(&q->direct_queue, skb); - q->direct_pkts++; + __skb_queue_head(&q->direct_queue, skb); } else { - kfree_skb (skb); - sch->stats.drops++; - return NET_XMIT_DROP; + __skb_queue_head(&q->direct_queue, skb); + tskb = __skb_dequeue_tail(&q->direct_queue); + kfree_skb (tskb); + sch->stats.drops++; + return NET_XMIT_CN; } } else if (cl->un.leaf.q->ops->requeue(skb, cl->un.leaf.q) != NET_XMIT_SUCCESS) { sch->stats.drops++; @@ -744,7 +760,7 @@ static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch) htb_activate (q,cl); sch->q.qlen++; - HTB_DBG(1,1,"htb_req_ok cl=%X skb=%p\n",cl?cl->classid:0,skb); + HTB_DBG(1,1,"htb_req_ok cl=%X skb=%p\n",(cl && cl != HTB_DIRECT)?cl->classid:0,skb); return NET_XMIT_SUCCESS; } @@ -819,7 +835,7 @@ static void htb_charge_class(struct htb_sched *q,struct htb_class *cl, cl->classid, diff, (unsigned long long) q->now, (unsigned long long) cl->t_c, - jiffies); + q->jiffies); diff = 1000; } #endif @@ -862,6 +878,7 @@ static void htb_charge_class(struct htb_sched *q,struct htb_class *cl, * * Scans event queue for pending events and applies them. Returns jiffies to * next pending event (0 for no event in pq). + * Note: Aplied are events whose have cl->pq_key <= jiffies. */ static long htb_do_events(struct htb_sched *q,int level) { @@ -876,9 +893,9 @@ static long htb_do_events(struct htb_sched *q,int level) while (p->rb_left) p = p->rb_left; cl = rb_entry(p, struct htb_class, pq_node); - if (cl->pq_key - (jiffies+1) < 0x80000000) { - HTB_DBG(8,3,"htb_do_ev_ret delay=%ld\n",cl->pq_key - jiffies); - return cl->pq_key - jiffies; + if (time_after(cl->pq_key, q->jiffies)) { + HTB_DBG(8,3,"htb_do_ev_ret delay=%ld\n",cl->pq_key - q->jiffies); + return cl->pq_key - q->jiffies; } htb_safe_rb_erase(p,q->wait_pq+level); diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32)cl->mbuffer, 0); @@ -889,7 +906,7 @@ static long htb_do_events(struct htb_sched *q,int level) cl->classid, diff, (unsigned long long) q->now, (unsigned long long) cl->t_c, - jiffies); + q->jiffies); diff = 1000; } #endif @@ -902,24 +919,56 @@ static long htb_do_events(struct htb_sched *q,int level) return HZ/10; } +/* Returns class->node+prio from id-tree where classe's id is >= id. NULL + is no such one exists. */ +static rb_node_t * +htb_id_find_next_upper(int prio,rb_node_t *n,u32 id) +{ + rb_node_t *r = NULL; + while (n) { + struct htb_class *cl = rb_entry(n,struct htb_class,node[prio]); + if (id == cl->classid) return n; + + if (id > cl->classid) { + n = n->rb_right; + } else { + r = n; + n = n->rb_left; + } + } + return r; +} + /** * htb_lookup_leaf - returns next leaf class in DRR order * * Find leaf where current feed pointers points to. */ static struct htb_class * -htb_lookup_leaf(rb_root_t *tree,int prio,rb_node_t **pptr) +htb_lookup_leaf(HTB_ARGQ rb_root_t *tree,int prio,rb_node_t **pptr,u32 *pid) { int i; struct { rb_node_t *root; rb_node_t **pptr; + u32 *pid; } stk[TC_HTB_MAXDEPTH],*sp = stk; + BUG_TRAP(tree->rb_node); sp->root = tree->rb_node; sp->pptr = pptr; + sp->pid = pid; for (i = 0; i < 65535; i++) { + HTB_DBG(4,2,"htb_lleaf ptr=%p pid=%X\n",*sp->pptr,*sp->pid); + + if (!*sp->pptr && *sp->pid) { + /* ptr was invalidated but id is valid - try to recover + the original or next ptr */ + *sp->pptr = htb_id_find_next_upper(prio,sp->root,*sp->pid); + } + *sp->pid = 0; /* ptr is valid now so that remove this hint as it + can become out of date quickly */ if (!*sp->pptr) { /* we are at right end; rewind & go up */ *sp->pptr = sp->root; while ((*sp->pptr)->rb_left) @@ -937,6 +986,7 @@ htb_lookup_leaf(rb_root_t *tree,int prio,rb_node_t **pptr) return cl; (++sp)->root = cl->un.inner.feed[prio].rb_node; sp->pptr = cl->un.inner.ptr+prio; + sp->pid = cl->un.inner.last_ptr_id+prio; } } BUG_TRAP(0); @@ -949,16 +999,37 @@ static struct sk_buff * htb_dequeue_tree(struct htb_sched *q,int prio,int level) { struct sk_buff *skb = NULL; - //struct htb_sched *q = (struct htb_sched *)sch->data; struct htb_class *cl,*start; /* look initial class up in the row */ - DEVIK_MSTART(6); - start = cl = htb_lookup_leaf (q->row[level]+prio,prio,q->ptr[level]+prio); + start = cl = htb_lookup_leaf (HTB_PASSQ q->row[level]+prio,prio, + q->ptr[level]+prio,q->last_ptr_id[level]+prio); do { - BUG_TRAP(cl && cl->un.leaf.q->q.qlen); if (!cl) return NULL; +next: + BUG_TRAP(cl); + if (!cl) return NULL; HTB_DBG(4,1,"htb_deq_tr prio=%d lev=%d cl=%X defic=%d\n", prio,level,cl->classid,cl->un.leaf.deficit[level]); + + /* class can be empty - it is unlikely but can be true if leaf + qdisc drops packets in enqueue routine or if someone used + graft operation on the leaf since last dequeue; + simply deactivate and skip such class */ + if (unlikely(cl->un.leaf.q->q.qlen == 0)) { + struct htb_class *next; + htb_deactivate(q,cl); + + /* row/level might become empty */ + if ((q->row_mask[level] & (1 << prio)) == 0) + return NULL; + + next = htb_lookup_leaf (HTB_PASSQ q->row[level]+prio, + prio,q->ptr[level]+prio,q->last_ptr_id[level]+prio); + if (cl == start) /* fix start if we just deleted it */ + start = next; + cl = next; + goto next; + } if (likely((skb = cl->un.leaf.q->dequeue(cl->un.leaf.q)) != NULL)) break; @@ -968,11 +1039,10 @@ htb_dequeue_tree(struct htb_sched *q,int prio,int level) } q->nwc_hit++; htb_next_rb_node((level?cl->parent->un.inner.ptr:q->ptr[0])+prio); - cl = htb_lookup_leaf (q->row[level]+prio,prio,q->ptr[level]+prio); + cl = htb_lookup_leaf (HTB_PASSQ q->row[level]+prio,prio,q->ptr[level]+prio, + q->last_ptr_id[level]+prio); } while (cl != start); - DEVIK_MEND(6); - DEVIK_MSTART(7); if (likely(skb != NULL)) { if ((cl->un.leaf.deficit[level] -= skb->len) < 0) { HTB_DBG(4,2,"htb_next_cl oldptr=%p quant_add=%d\n", @@ -984,27 +1054,22 @@ htb_dequeue_tree(struct htb_sched *q,int prio,int level) gives us slightly better performance */ if (!cl->un.leaf.q->q.qlen) htb_deactivate (q,cl); - DEVIK_MSTART(8); htb_charge_class (q,cl,level,skb->len); - DEVIK_MEND(8); } - DEVIK_MEND(7); return skb; } static void htb_delay_by(struct Qdisc *sch,long delay) { struct htb_sched *q = (struct htb_sched *)sch->data; - if (netif_queue_stopped(sch->dev)) return; if (delay <= 0) delay = 1; if (unlikely(delay > 5*HZ)) { if (net_ratelimit()) printk(KERN_INFO "HTB delay %ld > 5sec\n", delay); delay = 5*HZ; } - del_timer(&q->timer); - q->timer.expires = jiffies + delay; - add_timer(&q->timer); + /* why don't use jiffies here ? because expires can be in past */ + mod_timer(&q->timer, q->jiffies + delay); sch->flags |= TCQ_F_THROTTLED; sch->stats.overlimits++; HTB_DBG(3,1,"htb_deq t_delay=%ld\n",delay); @@ -1016,7 +1081,11 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch) struct htb_sched *q = (struct htb_sched *)sch->data; int level; long min_delay; +#ifdef HTB_DEBUG + int evs_used = 0; +#endif + q->jiffies = jiffies; HTB_DBG(3,1,"htb_deq dircnt=%d qlen=%d\n",skb_queue_len(&q->direct_queue), sch->q.qlen); @@ -1027,27 +1096,26 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch) return skb; } - DEVIK_MSTART(2); if (!sch->q.qlen) goto fin; PSCHED_GET_TIME(q->now); - min_delay = HZ*5; + min_delay = LONG_MAX; q->nwc_hit = 0; for (level = 0; level < TC_HTB_MAXDEPTH; level++) { /* common case optimization - skip event handler quickly */ int m; long delay; - DEVIK_MSTART(3); - if (jiffies - q->near_ev_cache[level] < 0x80000000 || 0) { + if (time_after_eq(q->jiffies, q->near_ev_cache[level])) { delay = htb_do_events(q,level); - q->near_ev_cache[level] += delay ? delay : HZ; + q->near_ev_cache[level] = q->jiffies + (delay ? delay : HZ); +#ifdef HTB_DEBUG + evs_used++; +#endif } else - delay = q->near_ev_cache[level] - jiffies; + delay = q->near_ev_cache[level] - q->jiffies; if (delay && min_delay > delay) min_delay = delay; - DEVIK_MEND(3); - DEVIK_MSTART(5); m = ~q->row_mask[level]; while (m != (int)(-1)) { int prio = ffz (m); @@ -1056,29 +1124,29 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch) if (likely(skb != NULL)) { sch->q.qlen--; sch->flags &= ~TCQ_F_THROTTLED; - DEVIK_MEND(5); goto fin; } } - DEVIK_MEND(5); } - DEVIK_MSTART(4); #ifdef HTB_DEBUG - if (!q->nwc_hit && min_delay >= 5*HZ && net_ratelimit()) { - printk(KERN_ERR "HTB: mindelay=%ld, report it please !\n",min_delay); - htb_debug_dump(q); + if (!q->nwc_hit && min_delay >= 10*HZ && net_ratelimit()) { + if (min_delay == LONG_MAX) { + printk(KERN_ERR "HTB: dequeue bug (%d,%lu,%lu), report it please !\n", + evs_used,q->jiffies,jiffies); + htb_debug_dump(q); + } else + printk(KERN_WARNING "HTB: mindelay=%ld, some class has " + "too small rate\n",min_delay); } #endif - htb_delay_by (sch,min_delay); - DEVIK_MEND(4); + htb_delay_by (sch,min_delay > 5*HZ ? 5*HZ : min_delay); fin: - HTB_DBG(3,1,"htb_deq_end %s j=%lu skb=%p\n",sch->dev->name,jiffies,skb); - DEVIK_MEND(2); + HTB_DBG(3,1,"htb_deq_end %s j=%lu skb=%p\n",sch->dev->name,q->jiffies,skb); return skb; } /* try to drop from each class (by prio) until one succeed */ -static int htb_drop(struct Qdisc* sch) +static unsigned int htb_drop(struct Qdisc* sch) { struct htb_sched *q = (struct htb_sched *)sch->data; int prio; @@ -1086,14 +1154,15 @@ static int htb_drop(struct Qdisc* sch) for (prio = TC_HTB_NUMPRIO - 1; prio >= 0; prio--) { struct list_head *p; list_for_each (p,q->drops+prio) { - struct htb_class *cl = list_entry(p,struct htb_class, - un.leaf.drop_list); + struct htb_class *cl = list_entry(p, struct htb_class, + un.leaf.drop_list); + unsigned int len; if (cl->un.leaf.q->ops->drop && - cl->un.leaf.q->ops->drop(cl->un.leaf.q)) { + (len = cl->un.leaf.q->ops->drop(cl->un.leaf.q))) { sch->q.qlen--; if (!cl->un.leaf.q->q.qlen) htb_deactivate (q,cl); - return 1; + return len; } } } @@ -1162,7 +1231,6 @@ static int htb_init(struct Qdisc *sch, struct rtattr *opt) HTB_VER >> 16,HTB_VER & 0xffff,gopt->version); return -EINVAL; } - memset(q,0,sizeof(*q)); q->debug = gopt->debug; HTB_DBG(0,1,"htb_init sch=%p handle=%X r2q=%d\n",sch,sch->handle,gopt->rate2quantum); @@ -1208,7 +1276,8 @@ static int htb_dump(struct Qdisc *sch, struct sk_buff *skb) gopt.direct_pkts = q->direct_pkts; #ifdef HTB_DEBUG - htb_debug_dump(q); + if (HTB_DBG_COND(0,2)) + htb_debug_dump(q); #endif gopt.version = HTB_VER; gopt.rate2quantum = q->rate2quantum; @@ -1218,8 +1287,6 @@ static int htb_dump(struct Qdisc *sch, struct sk_buff *skb) RTA_PUT(skb, TCA_OPTIONS, 0, NULL); RTA_PUT(skb, TCA_HTB_INIT, sizeof(gopt), &gopt); rta->rta_len = skb->tail - b; - sch->stats.qlen = sch->q.qlen; - RTA_PUT(skb, TCA_STATS, sizeof(sch->stats), &sch->stats); HTB_QUNLOCK(sch); return skb->len; rtattr_failure: @@ -1289,6 +1356,9 @@ static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, return -ENOBUFS; sch_tree_lock(sch); if ((*old = xchg(&cl->un.leaf.q, new)) != NULL) { + if (cl->prio_activity) + htb_deactivate ((struct htb_sched*)sch->data,cl); + /* TODO: is it correct ? Why CBQ doesn't do it ? */ sch->q.qlen -= (*old)->q.qlen; qdisc_reset(*old); @@ -1323,7 +1393,7 @@ static void htb_destroy_filters(struct tcf_proto **fl) while ((tp = *fl) != NULL) { *fl = tp->next; - tp->ops->destroy(tp); + tcf_destroy(tp); } } @@ -1371,11 +1441,16 @@ static void htb_destroy(struct Qdisc* sch) #ifdef HTB_RATECM del_timer_sync (&q->rttim); #endif + /* This line used to be after htb_destroy_class call below + and surprisingly it worked in 2.4. But it must precede it + because filter need its target class alive to be able to call + unbind_filter on it (without Oops). */ + htb_destroy_filters(&q->filter_list); + while (!list_empty(&q->root)) htb_destroy_class (sch,list_entry(q->root.next, struct htb_class,sibling)); - htb_destroy_filters(&q->filter_list); __skb_queue_purge(&q->direct_queue); MOD_DEC_USE_COUNT; } @@ -1438,12 +1513,13 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, parent = parentid == TC_H_ROOT ? NULL : htb_find (parentid,sch); hopt = RTA_DATA(tb[TCA_HTB_PARMS-1]); - HTB_DBG(0,1,"htb_chg cl=%p, clid=%X, opt/prio=%d, rate=%u, buff=%d, quant=%d\n", cl,cl?cl->classid:0,(int)hopt->prio,hopt->rate.rate,hopt->buffer,hopt->quantum); + HTB_DBG(0,1,"htb_chg cl=%p(%X), clid=%X, parid=%X, opt/prio=%d, rate=%u, buff=%d, quant=%d\n", cl,cl?cl->classid:0,classid,parentid,(int)hopt->prio,hopt->rate.rate,hopt->buffer,hopt->quantum); rtab = qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB-1]); ctab = qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB-1]); if (!rtab || !ctab) goto failure; if (!cl) { /* new class */ + struct Qdisc *new_q; /* check for valid classid */ if (!classid || TC_H_MAJ(classid^sch->handle) || htb_find(classid,sch)) goto failure; @@ -1467,6 +1543,10 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, cl->magic = HTB_CMAGIC; #endif + /* create leaf qdisc early because it uses kmalloc(GFP_KERNEL) + so that can't be used inside of sch_tree_lock + -- thanks to Karlis Peisenieks */ + new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops); sch_tree_lock(sch); if (parent && !parent->level) { /* turn parent into inner node */ @@ -1485,8 +1565,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, memset (&parent->un.inner,0,sizeof(parent->un.inner)); } /* leaf (we) needs elementary qdisc */ - if (!(cl->un.leaf.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops))) - cl->un.leaf.q = &noop_qdisc; + cl->un.leaf.q = new_q ? new_q : &noop_qdisc; cl->classid = classid; cl->parent = parent; @@ -1514,11 +1593,11 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, if (!cl->level) { cl->un.leaf.quantum = rtab->rate.rate / q->rate2quantum; if (!hopt->quantum && cl->un.leaf.quantum < 1000) { - printk(KERN_WARNING "HTB: quantum of class %X is small. Consider r2q change.", cl->classid); + printk(KERN_WARNING "HTB: quantum of class %X is small. Consider r2q change.\n", cl->classid); cl->un.leaf.quantum = 1000; } if (!hopt->quantum && cl->un.leaf.quantum > 200000) { - printk(KERN_WARNING "HTB: quantum of class %X is big. Consider r2q change.", cl->classid); + printk(KERN_WARNING "HTB: quantum of class %X is big. Consider r2q change.\n", cl->classid); cl->un.leaf.quantum = 200000; } if (hopt->quantum) diff --git a/release/src/linux/linux/net/sched/sch_ingress.c b/release/src/linux/linux/net/sched/sch_ingress.c index 2b30fce0..70698728 100644 --- a/release/src/linux/linux/net/sched/sch_ingress.c +++ b/release/src/linux/linux/net/sched/sch_ingress.c @@ -250,7 +250,6 @@ int ingress_init(struct Qdisc *sch,struct rtattr *opt) } DPRINTK("ingress_init(sch %p,[qdisc %p],opt %p)\n",sch,p,opt); - memset(p, 0, sizeof(*p)); p->filter_list = NULL; p->q = &noop_qdisc; MOD_INC_USE_COUNT; @@ -286,10 +285,7 @@ static void ingress_destroy(struct Qdisc *sch) p->filter_list = tp->next; tp->ops->destroy(tp); } - memset(p, 0, sizeof(*p)); - p->filter_list = NULL; - MOD_DEC_USE_COUNT; } diff --git a/release/src/linux/linux/net/sched/sch_sfq.c b/release/src/linux/linux/net/sched/sch_sfq.c index c96762fb..a6c17424 100644 --- a/release/src/linux/linux/net/sched/sch_sfq.c +++ b/release/src/linux/linux/net/sched/sch_sfq.c @@ -218,6 +218,7 @@ static int sfq_drop(struct Qdisc *sch) struct sfq_sched_data *q = (struct sfq_sched_data *)sch->data; sfq_index d = q->max_depth; struct sk_buff *skb; + int len; /* Queue is full! Find the longest slot and drop a packet from it */ @@ -225,12 +226,13 @@ static int sfq_drop(struct Qdisc *sch) if (d > 1) { sfq_index x = q->dep[d+SFQ_DEPTH].next; skb = q->qs[x].prev; + len = skb->len; __skb_unlink(skb, &q->qs[x]); kfree_skb(skb); sfq_dec(q, x); sch->q.qlen--; sch->stats.drops++; - return 1; + return len; } if (d == 1) { @@ -239,13 +241,14 @@ static int sfq_drop(struct Qdisc *sch) q->next[q->tail] = q->next[d]; q->allot[q->next[d]] += q->quantum; skb = q->qs[d].prev; + len = skb->len; __skb_unlink(skb, &q->qs[d]); kfree_skb(skb); sfq_dec(q, d); sch->q.qlen--; q->ht[q->hash[d]] = SFQ_DEPTH; sch->stats.drops++; - return 1; + return len; } return 0; @@ -342,6 +345,7 @@ sfq_dequeue(struct Qdisc* sch) /* Is the slot empty? */ if (q->qs[a].qlen == 0) { + q->ht[q->hash[a]] = SFQ_DEPTH; a = q->next[a]; if (a == old_a) { q->tail = SFQ_DEPTH; diff --git a/release/src/linux/linux/net/socket.c b/release/src/linux/linux/net/socket.c index d8b479c9..4816eeb6 100644 --- a/release/src/linux/linux/net/socket.c +++ b/release/src/linux/linux/net/socket.c @@ -607,6 +607,9 @@ ssize_t sock_sendpage(struct file *file, struct page *page, if (more) flags |= MSG_MORE; + if (!sock->ops->sendpage) + return sock_no_sendpage(sock, page, offset, size, flags); + return sock->ops->sendpage(sock, page, offset, size, flags); } diff --git a/release/src/linux/linux/scripts/squashfs/Makefile b/release/src/linux/linux/scripts/squashfs/Makefile index f563eceb..fa3f29e4 100644 --- a/release/src/linux/linux/scripts/squashfs/Makefile +++ b/release/src/linux/linux/scripts/squashfs/Makefile @@ -1,17 +1,39 @@ -INCLUDEDIR = . - CC=gcc +CXX=g++ +INCLUDEDIR = . +LZMALIB = lzma/C/7zip/Compress/LZMA_Lib +LZMAPATH = lzma/C/7zip/Compress/LZMA_Alone CFLAGS := -I$(INCLUDEDIR) -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -O2 +all: liblzma.a mksquashfs unsquashfs mksquashfs-lzma lzma + mksquashfs: mksquashfs.o read_fs.o sort.o $(CC) mksquashfs.o read_fs.o sort.o -lz -o $@ -mksquashfs.o: mksquashfs.c mksquashfs.h +mksquashfs-lzma: liblzma.a mksquashfs.o read_fs.o sort.o + $(CXX) mksquashfs.o read_fs.o sort.o -L$(LZMALIB) -llzma -o $@ + +mksquashfs.o: mksquashfs.c squashfs_fs.h mksquashfs.h global.h sort.h -read_fs.o: read_fs.c read_fs.h +read_fs.o: read_fs.c squashfs_fs.h read_fs.h global.h -sort.o: sort.c +sort.o: sort.c squashfs_fs.h global.h sort.h + +unsquashfs: unsquashfs.o + $(CC) unsquashfs.o -lz -o $@ + +unsquashfs.o: unsquashfs.c squashfs_fs.h read_fs.h global.h + +liblzma.a: + $(MAKE) -C $(LZMALIB) + +lzma: + $(MAKE) -C $(LZMAPATH) -f makefile.gcc clean: - rm -f *.o mksquashfs + find . -iname "*.o" -exec rm -f {} \; + find . -iname "*.a" -exec rm -f {} \; + rm -f mksquashfs unsquashfs mksquashfs-lzma $(LZMAPATH)/lzma + +.PHONY: lzma diff --git a/release/src/linux/linux/scripts/squashfs/global.h b/release/src/linux/linux/scripts/squashfs/global.h new file mode 100644 index 00000000..2c45c4a4 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/global.h @@ -0,0 +1,46 @@ +#ifndef GLOBAL_H +#define GLOBAL_H + +/* + * Squashfs + * + * Copyright (c) 2002, 2003, 2004, 2005, 2006 + * Phillip Lougher <phillip@lougher.org.uk> + * + * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * global.h + */ + +typedef struct squashfs_super_block squashfs_super_block; +typedef struct squashfs_dir_index squashfs_dir_index; +typedef struct squashfs_base_inode_header squashfs_base_inode_header; +typedef struct squashfs_ipc_inode_header squashfs_ipc_inode_header; +typedef struct squashfs_dev_inode_header squashfs_dev_inode_header; +typedef struct squashfs_symlink_inode_header squashfs_symlink_inode_header; +typedef struct squashfs_reg_inode_header squashfs_reg_inode_header; +typedef struct squashfs_lreg_inode_header squashfs_lreg_inode_header; +typedef struct squashfs_dir_inode_header squashfs_dir_inode_header; +typedef struct squashfs_ldir_inode_header squashfs_ldir_inode_header; +typedef struct squashfs_dir_entry squashfs_dir_entry; +typedef struct squashfs_dir_header squashfs_dir_header; +typedef struct squashfs_fragment_entry squashfs_fragment_entry; + +typedef union squashfs_inode_header squashfs_inode_header; +typedef unsigned int squashfs_uid; +typedef long long squashfs_fragment_index; +typedef squashfs_inode_t squashfs_inode; +typedef squashfs_block_t squashfs_block; +#endif diff --git a/release/src/linux/linux/scripts/squashfs/lzma/7zC.txt b/release/src/linux/linux/scripts/squashfs/lzma/7zC.txt new file mode 100644 index 00000000..1c81eacf --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/7zC.txt @@ -0,0 +1,235 @@ +7z ANSI-C Decoder 4.23
+----------------------
+
+7z ANSI-C Decoder 4.23 Copyright (C) 1999-2005 Igor Pavlov
+
+7z ANSI-C provides 7z/LZMA decoding.
+7z ANSI-C version is simplified version ported from C++ code.
+
+LZMA is default and general compression method of 7z format
+in 7-Zip compression program (www.7-zip.org). LZMA provides high
+compression ratio and very fast decompression.
+
+
+LICENSE
+-------
+
+Read lzma.txt for information about license.
+
+
+Files
+---------------------
+
+7zAlloc.* - Allocate and Free
+7zBuffer.* - Buffer structure
+7zCrc.* - CRC32 code
+7zDecode.* - Low level memory->memory decoding
+7zExtract.* - High level stream->memory decoding
+7zHeader.* - .7z format constants
+7zIn.* - .7z archive opening
+7zItem.* - .7z structures
+7zMain.c - Test application
+7zMethodID.* - MethodID structure
+7zTypes.h - Base types and constants
+
+
+How To Use
+----------
+
+You must download 7-Zip program from www.7-zip.org.
+
+You can create .7z archive with 7z.exe or 7za.exe:
+
+ 7za.exe a archive.7z *.htm -r -mx -m0fb=255
+
+If you have big number of files in archive, and you need fast extracting,
+you can use partly-solid archives:
+
+ 7za.exe a archive.7z *.htm -ms=512K -r -mx -m0fb=255 -m0d=512K
+
+In that example 7-Zip will use 512KB solid blocks. So it needs to decompress only
+512KB for extracting one file from such archive.
+
+
+Limitations of current version of 7z ANSI-C Decoder
+---------------------------------------------------
+
+ - It reads only "FileName", "Size", and "CRC" information for each file in archive.
+ - It supports only LZMA and Copy (no compression) methods.
+ - It converts original UTF-16 Unicode file names to UTF-8 Unicode file names.
+
+These limitations will be fixed in future versions.
+
+
+Using 7z ANSI-C Decoder Test application:
+-----------------------------------------
+
+Usage: 7zDec <command> <archive_name>
+
+<Command>:
+ e: Extract files from archive
+ l: List contents of archive
+ t: Test integrity of archive
+
+Example:
+
+ 7zDec l archive.7z
+
+lists contents of archive.7z
+
+ 7zDec e archive.7z
+
+extracts files from archive.7z to current folder.
+
+
+How to use .7z Decoder
+----------------------
+
+.7z Decoder can be compiled in one of two modes:
+
+1) Default mode. In that mode 7z Decoder will read full compressed
+ block to RAM before decompressing.
+
+2) Mode with defined _LZMA_IN_CB. In that mode 7z Decoder can read
+ compressed block by parts. And you can specify desired buffer size.
+ So memory requirements can be reduced. But decompressing speed will
+ be 5-10% lower and code size is slightly larger.
+
+
+Memory allocation
+~~~~~~~~~~~~~~~~~
+
+7z Decoder uses two memory pools:
+1) Temporary pool
+2) Main pool
+Such scheme can allow you to avoid fragmentation of allocated blocks.
+
+Steps for using 7z decoder
+--------------------------
+
+Use code at 7zMain.c as example.
+
+1) Declare variables:
+ inStream /* implements ISzInStream interface */
+ CArchiveDatabaseEx db; /* 7z archive database structure */
+ ISzAlloc allocImp; /* memory functions for main pool */
+ ISzAlloc allocTempImp; /* memory functions for temporary pool */
+
+2) call InitCrcTable(); function to initialize CRC structures.
+
+3) call SzArDbExInit(&db); function to initialize db structures.
+
+4) call SzArchiveOpen(inStream, &db, &allocMain, &allocTemp) to open archive
+
+This function opens archive "inStream" and reads headers to "db".
+All items in "db" will be allocated with "allocMain" functions.
+SzArchiveOpen function allocates and frees temporary structures by "allocTemp" functions.
+
+5) List items or Extract items
+
+ Listing code:
+ ~~~~~~~~~~~~~
+ {
+ UInt32 i;
+ for (i = 0; i < db.Database.NumFiles; i++)
+ {
+ CFileItem *f = db.Database.Files + i;
+ printf("%10d %s\n", (int)f->Size, f->Name);
+ }
+ }
+
+ Extracting code:
+ ~~~~~~~~~~~~~~~~
+
+ SZ_RESULT SzExtract(
+ ISzInStream *inStream,
+ CArchiveDatabaseEx *db,
+ UInt32 fileIndex, /* index of file */
+ UInt32 *blockIndex, /* index of solid block */
+ Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */
+ size_t *outBufferSize, /* buffer size for output buffer */
+ size_t *offset, /* offset of stream for required file in *outBuffer */
+ size_t *outSizeProcessed, /* size of file in *outBuffer */
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp);
+
+ If you need to decompress more than one file, you can send these values from previous call:
+ blockIndex,
+ outBuffer,
+ outBufferSize,
+ You can consider "outBuffer" as cache of solid block. If your archive is solid,
+ it will increase decompression speed.
+
+ After decompressing you must free "outBuffer":
+ allocImp.Free(outBuffer);
+
+6) call SzArDbExFree(&db, allocImp.Free) to free allocated items in "db".
+
+
+
+
+Memory requirements for .7z decoding
+------------------------------------
+
+Memory usage for Archive opening:
+ - Temporary pool:
+ - Memory for compressed .7z headers (if _LZMA_IN_CB is not defined)
+ - Memory for uncompressed .7z headers
+ - some other temporary blocks
+ - Main pool:
+ - Memory for database:
+ Estimated size of one file structures in solid archive:
+ - Size (4 or 8 Bytes)
+ - CRC32 (4 bytes)
+ - Some file information (4 bytes)
+ - File Name (variable length) + pointer + allocation structures
+
+Memory usage for archive Decompressing:
+ - Temporary pool:
+ - Memory for compressed solid block (if _LZMA_IN_CB is not defined)
+ - Memory for LZMA decompressing structures
+ - Main pool:
+ - Memory for decompressed solid block
+
+
+If _LZMA_IN_CB is defined, 7z Decoder will not allocate memory for
+compressed blocks. Instead of this, you must allocate buffer with desired
+size before calling 7z Decoder. Use 7zMain.c as example.
+
+
+
+EXIT codes
+-----------
+
+7z Decoder functions can return one of the following codes:
+
+#define SZ_OK (0)
+#define SZE_DATA_ERROR (1)
+#define SZE_OUTOFMEMORY (2)
+#define SZE_CRC_ERROR (3)
+
+#define SZE_NOTIMPL (4)
+#define SZE_FAIL (5)
+
+#define SZE_ARCHIVE_ERROR (6)
+
+
+
+LZMA Defines
+------------
+
+_LZMA_IN_CB - Use special callback mode for input stream to reduce memory requirements
+
+_SZ_FILE_SIZE_64 - define it if you need support for files larger than 4 GB
+_SZ_NO_INT_64 - define it if your compiler doesn't support long long int
+
+_LZMA_PROB32 - it can increase LZMA decompressing speed on some 32-bit CPUs.
+
+_SZ_ONE_DIRECTORY - define it if you want to locate all source files to one directory
+_SZ_ALLOC_DEBUG - define it if you want to debug alloc/free operations to stderr.
+
+
+---
+
+http://www.7-zip.org
+http://www.7-zip.org/support.html
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/7zFormat.txt b/release/src/linux/linux/scripts/squashfs/lzma/7zFormat.txt new file mode 100644 index 00000000..7e2b14ad --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/7zFormat.txt @@ -0,0 +1,471 @@ +7z Format description (2.30 Beta 25)
+-----------------------------------
+
+This file contains description of 7z archive format.
+7z archive can contain files compressed with any method.
+See "Methods.txt" for description for defined compressing methods.
+
+
+Format structure Overview
+-------------------------
+
+Some fields can be optional.
+
+Archive structure
+~~~~~~~~~~~~~~~~~
+SignatureHeader
+[PackedStreams]
+[PackedStreamsForHeaders]
+[
+ Header
+ or
+ {
+ Packed Header
+ HeaderInfo
+ }
+]
+
+
+
+Header structure
+~~~~~~~~~~~~~~~~
+{
+ ArchiveProperties
+ AdditionalStreams
+ {
+ PackInfo
+ {
+ PackPos
+ NumPackStreams
+ Sizes[NumPackStreams]
+ CRCs[NumPackStreams]
+ }
+ CodersInfo
+ {
+ NumFolders
+ Folders[NumFolders]
+ {
+ NumCoders
+ CodersInfo[NumCoders]
+ {
+ ID
+ NumInStreams;
+ NumOutStreams;
+ PropertiesSize
+ Properties[PropertiesSize]
+ }
+ NumBindPairs
+ BindPairsInfo[NumBindPairs]
+ {
+ InIndex;
+ OutIndex;
+ }
+ PackedIndices
+ }
+ UnPackSize[Folders][Folders.NumOutstreams]
+ CRCs[NumFolders]
+ }
+ SubStreamsInfo
+ {
+ NumUnPackStreamsInFolders[NumFolders];
+ UnPackSizes[]
+ CRCs[]
+ }
+ }
+ MainStreamsInfo
+ {
+ (Same as in AdditionalStreams)
+ }
+ FilesInfo
+ {
+ NumFiles
+ Properties[]
+ {
+ ID
+ Size
+ Data
+ }
+ }
+}
+
+HeaderInfo structure
+~~~~~~~~~~~~~~~~~~~~
+{
+ (Same as in AdditionalStreams)
+}
+
+
+
+Notes about Notation and encoding
+---------------------------------
+
+7z uses little endian encoding.
+
+7z archive format has optional headers that are marked as
+[]
+Header
+[]
+
+REAL_UINT64 means real UINT64.
+
+UINT64 means real UINT64 encoded with the following scheme:
+
+ Size of encoding sequence depends from first byte:
+ First_Byte Extra_Bytes Value
+ (binary)
+ 0xxxxxxx : ( xxxxxxx )
+ 10xxxxxx BYTE y[1] : ( xxxxxx << (8 * 1)) + y
+ 110xxxxx BYTE y[2] : ( xxxxx << (8 * 2)) + y
+ ...
+ 1111110x BYTE y[6] : ( x << (8 * 6)) + y
+ 11111110 BYTE y[7] : y
+ 11111111 BYTE y[8] : y
+
+
+
+Property IDs
+------------
+
+0x00 = kEnd,
+
+0x01 = kHeader,
+
+0x02 = kArchiveProperties,
+
+0x03 = kAdditionalStreamsInfo,
+0x04 = kMainStreamsInfo,
+0x05 = kFilesInfo,
+
+0x06 = kPackInfo,
+0x07 = kUnPackInfo,
+0x08 = kSubStreamsInfo,
+
+0x09 = kSize,
+0x0A = kCRC,
+
+0x0B = kFolder,
+
+0x0C = kCodersUnPackSize,
+0x0D = kNumUnPackStream,
+
+0x0E = kEmptyStream,
+0x0F = kEmptyFile,
+0x10 = kAnti,
+
+0x11 = kName,
+0x12 = kCreationTime,
+0x13 = kLastAccessTime,
+0x14 = kLastWriteTime,
+0x15 = kWinAttributes,
+0x16 = kComment,
+
+0x17 = kEncodedHeader,
+
+
+7z format headers
+-----------------
+
+SignatureHeader
+~~~~~~~~~~~~~~~
+ BYTE kSignature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
+
+ ArchiveVersion
+ {
+ BYTE Major; // now = 0
+ BYTE Minor; // now = 2
+ };
+
+ UINT32 StartHeaderCRC;
+
+ StartHeader
+ {
+ REAL_UINT64 NextHeaderOffset
+ REAL_UINT64 NextHeaderSize
+ UINT32 NextHeaderCRC
+ }
+
+
+...........................
+
+
+ArchiveProperties
+~~~~~~~~~~~~~~~~~
+BYTE NID::kArchiveProperties (0x02)
+while(true)
+{
+ BYTE PropertyType;
+ if (aType == 0)
+ break;
+ UINT64 PropertySize;
+ BYTE PropertyData[PropertySize];
+}
+
+
+Digests (NumStreams)
+~~~~~~~~~~~~~~~~~~~~~
+ BYTE AllAreDefined
+ if (AllAreDefined == 0)
+ {
+ for(NumStreams)
+ BIT Defined
+ }
+ UINT32 CRCs[NumDefined]
+
+
+PackInfo
+~~~~~~~~~~~~
+ BYTE NID::kPackInfo (0x06)
+ UINT64 PackPos
+ UINT64 NumPackStreams
+
+ []
+ BYTE NID::kSize (0x09)
+ UINT64 PackSizes[NumPackStreams]
+ []
+
+ []
+ BYTE NID::kCRC (0x0A)
+ PackStreamDigests[NumPackStreams]
+ []
+
+ BYTE NID::kEnd
+
+
+Folder
+~~~~~~
+ UINT64 NumCoders;
+ for (NumCoders)
+ {
+ BYTE
+ {
+ 0:3 DecompressionMethod.IDSize
+ 4:
+ 0 - IsSimple
+ 1 - Is not simple
+ 5:
+ 0 - No Attributes
+ 1 - There Are Attributes
+ 7:
+ 0 - Last Method in Alternative_Method_List
+ 1 - There are more alternative methods
+ }
+ BYTE DecompressionMethod.ID[DecompressionMethod.IDSize]
+ if (!IsSimple)
+ {
+ UINT64 NumInStreams;
+ UINT64 NumOutStreams;
+ }
+ if (DecompressionMethod[0] != 0)
+ {
+ UINT64 PropertiesSize
+ BYTE Properties[PropertiesSize]
+ }
+ }
+
+ NumBindPairs = NumOutStreamsTotal - 1;
+
+ for (NumBindPairs)
+ {
+ UINT64 InIndex;
+ UINT64 OutIndex;
+ }
+
+ NumPackedStreams = NumInStreamsTotal - NumBindPairs;
+ if (NumPackedStreams > 1)
+ for(NumPackedStreams)
+ {
+ UINT64 Index;
+ };
+
+
+
+
+Coders Info
+~~~~~~~~~~~
+
+ BYTE NID::kUnPackInfo (0x07)
+
+
+ BYTE NID::kFolder (0x0B)
+ UINT64 NumFolders
+ BYTE External
+ switch(External)
+ {
+ case 0:
+ Folders[NumFolders]
+ case 1:
+ UINT64 DataStreamIndex
+ }
+
+
+ BYTE ID::kCodersUnPackSize (0x0C)
+ for(Folders)
+ for(Folder.NumOutStreams)
+ UINT64 UnPackSize;
+
+
+ []
+ BYTE NID::kCRC (0x0A)
+ UnPackDigests[NumFolders]
+ []
+
+
+
+ BYTE NID::kEnd
+
+
+
+SubStreams Info
+~~~~~~~~~~~~~~
+ BYTE NID::kSubStreamsInfo; (0x08)
+
+ []
+ BYTE NID::kNumUnPackStream; (0x0D)
+ UINT64 NumUnPackStreamsInFolders[NumFolders];
+ []
+
+
+ []
+ BYTE NID::kSize (0x09)
+ UINT64 UnPackSizes[]
+ []
+
+
+ []
+ BYTE NID::kCRC (0x0A)
+ Digests[Number of streams with unknown CRC]
+ []
+
+
+ BYTE NID::kEnd
+
+
+Streams Info
+~~~~~~~~~~~~
+
+ []
+ PackInfo
+ []
+
+
+ []
+ CodersInfo
+ []
+
+
+ []
+ SubStreamsInfo
+ []
+
+ BYTE NID::kEnd
+
+
+FilesInfo
+~~~~~~~~~
+ BYTE NID::kFilesInfo; (0x05)
+ UINT64 NumFiles
+
+ while(true)
+ {
+ BYTE PropertyType;
+ if (aType == 0)
+ break;
+
+ UINT64 Size;
+
+ switch(PropertyType)
+ {
+ kEmptyStream: (0x0E)
+ for(NumFiles)
+ BIT IsEmptyStream
+
+ kEmptyFile: (0x0F)
+ for(EmptyStreams)
+ BIT IsEmptyFile
+
+ kAnti: (0x10)
+ for(EmptyStreams)
+ BIT IsAntiFile
+
+ case kCreationTime: (0x12)
+ case kLastAccessTime: (0x13)
+ case kLastWriteTime: (0x14)
+ BYTE AllAreDefined
+ if (AllAreDefined == 0)
+ {
+ for(NumFiles)
+ BIT TimeDefined
+ }
+ BYTE External;
+ if(External != 0)
+ UINT64 DataIndex
+ []
+ for(Definded Items)
+ UINT32 Time
+ []
+
+ kNames: (0x11)
+ BYTE External;
+ if(External != 0)
+ UINT64 DataIndex
+ []
+ for(Files)
+ {
+ wchar_t Names[NameSize];
+ wchar_t 0;
+ }
+ []
+
+ kAttributes: (0x15)
+ BYTE AllAreDefined
+ if (AllAreDefined == 0)
+ {
+ for(NumFiles)
+ BIT AttributesAreDefined
+ }
+ BYTE External;
+ if(External != 0)
+ UINT64 DataIndex
+ []
+ for(Definded Attributes)
+ UINT32 Attributes
+ []
+ }
+ }
+
+
+Header
+~~~~~~
+ BYTE NID::kHeader (0x01)
+
+ []
+ ArchiveProperties
+ []
+
+ []
+ BYTE NID::kAdditionalStreamsInfo; (0x03)
+ StreamsInfo
+ []
+
+ []
+ BYTE NID::kMainStreamsInfo; (0x04)
+ StreamsInfo
+ []
+
+ []
+ FilesInfo
+ []
+
+ BYTE NID::kEnd
+
+
+HeaderInfo
+~~~~~~~~~~
+ []
+ BYTE NID::kEncodedHeader; (0x17)
+ StreamsInfo for Encoded Header
+ []
+
+
+---
+End of document
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zAlloc.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zAlloc.c new file mode 100644 index 00000000..d5da81b1 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zAlloc.c @@ -0,0 +1,70 @@ +/* 7zAlloc.c */
+
+#include <stdlib.h>
+#include "7zAlloc.h"
+
+/* #define _SZ_ALLOC_DEBUG */
+/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
+
+#ifdef _SZ_ALLOC_DEBUG
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+#include <stdio.h>
+int g_allocCount = 0;
+int g_allocCountTemp = 0;
+#endif
+
+void *SzAlloc(size_t size)
+{
+ if (size == 0)
+ return 0;
+ #ifdef _SZ_ALLOC_DEBUG
+ fprintf(stderr, "\nAlloc %10d bytes; count = %10d", size, g_allocCount);
+ g_allocCount++;
+ #endif
+ return malloc(size);
+}
+
+void SzFree(void *address)
+{
+ #ifdef _SZ_ALLOC_DEBUG
+ if (address != 0)
+ {
+ g_allocCount--;
+ fprintf(stderr, "\nFree; count = %10d", g_allocCount);
+ }
+ #endif
+ free(address);
+}
+
+void *SzAllocTemp(size_t size)
+{
+ if (size == 0)
+ return 0;
+ #ifdef _SZ_ALLOC_DEBUG
+ fprintf(stderr, "\nAlloc_temp %10d bytes; count = %10d", size, g_allocCountTemp);
+ g_allocCountTemp++;
+ #ifdef _WIN32
+ return HeapAlloc(GetProcessHeap(), 0, size);
+ #endif
+ #endif
+ return malloc(size);
+}
+
+void SzFreeTemp(void *address)
+{
+ #ifdef _SZ_ALLOC_DEBUG
+ if (address != 0)
+ {
+ g_allocCountTemp--;
+ fprintf(stderr, "\nFree_temp; count = %10d", g_allocCountTemp);
+ }
+ #ifdef _WIN32
+ HeapFree(GetProcessHeap(), 0, address);
+ return;
+ #endif
+ #endif
+ free(address);
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zAlloc.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zAlloc.h new file mode 100644 index 00000000..b02c1dea --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zAlloc.h @@ -0,0 +1,20 @@ +/* 7zAlloc.h */
+
+#ifndef __7Z_ALLOC_H
+#define __7Z_ALLOC_H
+
+#include <stddef.h>
+
+typedef struct _ISzAlloc
+{
+ void *(*Alloc)(size_t size);
+ void (*Free)(void *address); /* address can be 0 */
+} ISzAlloc;
+
+void *SzAlloc(size_t size);
+void SzFree(void *address);
+
+void *SzAllocTemp(size_t size);
+void SzFreeTemp(void *address);
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zBuffer.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zBuffer.c new file mode 100644 index 00000000..8bc8e067 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zBuffer.c @@ -0,0 +1,29 @@ +/* 7zBuffer.c */
+
+#include "7zBuffer.h"
+#include "7zAlloc.h"
+
+void SzByteBufferInit(CSzByteBuffer *buffer)
+{
+ buffer->Capacity = 0;
+ buffer->Items = 0;
+}
+
+int SzByteBufferCreate(CSzByteBuffer *buffer, size_t newCapacity, void * (*allocFunc)(size_t size))
+{
+ buffer->Capacity = newCapacity;
+ if (newCapacity == 0)
+ {
+ buffer->Items = 0;
+ return 1;
+ }
+ buffer->Items = (Byte *)allocFunc(newCapacity);
+ return (buffer->Items != 0);
+}
+
+void SzByteBufferFree(CSzByteBuffer *buffer, void (*freeFunc)(void *))
+{
+ freeFunc(buffer->Items);
+ buffer->Items = 0;
+ buffer->Capacity = 0;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zBuffer.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zBuffer.h new file mode 100644 index 00000000..afea3ca8 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zBuffer.h @@ -0,0 +1,19 @@ +/* 7zBuffer.h */
+
+#ifndef __7Z_BUFFER_H
+#define __7Z_BUFFER_H
+
+#include <stddef.h>
+#include "7zTypes.h"
+
+typedef struct _CSzByteBuffer
+{
+ size_t Capacity;
+ Byte *Items;
+}CSzByteBuffer;
+
+void SzByteBufferInit(CSzByteBuffer *buffer);
+int SzByteBufferCreate(CSzByteBuffer *buffer, size_t newCapacity, void * (*allocFunc)(size_t size));
+void SzByteBufferFree(CSzByteBuffer *buffer, void (*freeFunc)(void *));
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zCrc.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zCrc.c new file mode 100644 index 00000000..6dc7dd32 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zCrc.c @@ -0,0 +1,76 @@ +/* 7zCrc.c */
+
+#include "7zCrc.h"
+
+#define kCrcPoly 0xEDB88320
+
+UInt32 g_CrcTable[256];
+
+void InitCrcTable()
+{
+ UInt32 i;
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 r = i;
+ int j;
+ for (j = 0; j < 8; j++)
+ if (r & 1)
+ r = (r >> 1) ^ kCrcPoly;
+ else
+ r >>= 1;
+ g_CrcTable[i] = r;
+ }
+}
+
+void CrcInit(UInt32 *crc) { *crc = 0xFFFFFFFF; }
+UInt32 CrcGetDigest(UInt32 *crc) { return *crc ^ 0xFFFFFFFF; }
+
+void CrcUpdateByte(UInt32 *crc, Byte b)
+{
+ *crc = g_CrcTable[((Byte)(*crc)) ^ b] ^ (*crc >> 8);
+}
+
+void CrcUpdateUInt16(UInt32 *crc, UInt16 v)
+{
+ CrcUpdateByte(crc, (Byte)v);
+ CrcUpdateByte(crc, (Byte)(v >> 8));
+}
+
+void CrcUpdateUInt32(UInt32 *crc, UInt32 v)
+{
+ int i;
+ for (i = 0; i < 4; i++)
+ CrcUpdateByte(crc, (Byte)(v >> (8 * i)));
+}
+
+void CrcUpdateUInt64(UInt32 *crc, UInt64 v)
+{
+ int i;
+ for (i = 0; i < 8; i++)
+ {
+ CrcUpdateByte(crc, (Byte)(v));
+ v >>= 8;
+ }
+}
+
+void CrcUpdate(UInt32 *crc, const void *data, size_t size)
+{
+ UInt32 v = *crc;
+ const Byte *p = (const Byte *)data;
+ for (; size > 0 ; size--, p++)
+ v = g_CrcTable[((Byte)(v)) ^ *p] ^ (v >> 8);
+ *crc = v;
+}
+
+UInt32 CrcCalculateDigest(const void *data, size_t size)
+{
+ UInt32 crc;
+ CrcInit(&crc);
+ CrcUpdate(&crc, data, size);
+ return CrcGetDigest(&crc);
+}
+
+int CrcVerifyDigest(UInt32 digest, const void *data, size_t size)
+{
+ return (CrcCalculateDigest(data, size) == digest);
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zCrc.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zCrc.h new file mode 100644 index 00000000..bac26b14 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zCrc.h @@ -0,0 +1,24 @@ +/* 7zCrc.h */
+
+#ifndef __7Z_CRC_H
+#define __7Z_CRC_H
+
+#include <stddef.h>
+
+#include "7zTypes.h"
+
+extern UInt32 g_CrcTable[256];
+void InitCrcTable();
+
+void CrcInit(UInt32 *crc);
+UInt32 CrcGetDigest(UInt32 *crc);
+void CrcUpdateByte(UInt32 *crc, Byte v);
+void CrcUpdateUInt16(UInt32 *crc, UInt16 v);
+void CrcUpdateUInt32(UInt32 *crc, UInt32 v);
+void CrcUpdateUInt64(UInt32 *crc, UInt64 v);
+void CrcUpdate(UInt32 *crc, const void *data, size_t size);
+
+UInt32 CrcCalculateDigest(const void *data, size_t size);
+int CrcVerifyDigest(UInt32 digest, const void *data, size_t size);
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zDecode.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zDecode.c new file mode 100644 index 00000000..9dfbe7dc --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zDecode.c @@ -0,0 +1,150 @@ +/* 7zDecode.c */
+
+#include "7zDecode.h"
+#ifdef _SZ_ONE_DIRECTORY
+#include "LzmaDecode.h"
+#else
+#include "../../Compress/LZMA_C/LzmaDecode.h"
+#endif
+
+CMethodID k_Copy = { { 0x0 }, 1 };
+CMethodID k_LZMA = { { 0x3, 0x1, 0x1 }, 3 };
+
+#ifdef _LZMA_IN_CB
+
+typedef struct _CLzmaInCallbackImp
+{
+ ILzmaInCallback InCallback;
+ ISzInStream *InStream;
+ size_t Size;
+} CLzmaInCallbackImp;
+
+int LzmaReadImp(void *object, const unsigned char **buffer, SizeT *size)
+{
+ CLzmaInCallbackImp *cb = (CLzmaInCallbackImp *)object;
+ size_t processedSize;
+ SZ_RESULT res;
+ *size = 0;
+ res = cb->InStream->Read((void *)cb->InStream, (void **)buffer, cb->Size, &processedSize);
+ *size = (SizeT)processedSize;
+ if (processedSize > cb->Size)
+ return (int)SZE_FAIL;
+ cb->Size -= processedSize;
+ if (res == SZ_OK)
+ return 0;
+ return (int)res;
+}
+
+#endif
+
+SZ_RESULT SzDecode(const CFileSize *packSizes, const CFolder *folder,
+ #ifdef _LZMA_IN_CB
+ ISzInStream *inStream,
+ #else
+ const Byte *inBuffer,
+ #endif
+ Byte *outBuffer, size_t outSize,
+ size_t *outSizeProcessed, ISzAlloc *allocMain)
+{
+ UInt32 si;
+ size_t inSize = 0;
+ CCoderInfo *coder;
+ if (folder->NumPackStreams != 1)
+ return SZE_NOTIMPL;
+ if (folder->NumCoders != 1)
+ return SZE_NOTIMPL;
+ coder = folder->Coders;
+ *outSizeProcessed = 0;
+
+ for (si = 0; si < folder->NumPackStreams; si++)
+ inSize += (size_t)packSizes[si];
+
+ if (AreMethodsEqual(&coder->MethodID, &k_Copy))
+ {
+ size_t i;
+ if (inSize != outSize)
+ return SZE_DATA_ERROR;
+ #ifdef _LZMA_IN_CB
+ for (i = 0; i < inSize;)
+ {
+ size_t j;
+ Byte *inBuffer;
+ size_t bufferSize;
+ RINOK(inStream->Read((void *)inStream, (void **)&inBuffer, inSize - i, &bufferSize));
+ if (bufferSize == 0)
+ return SZE_DATA_ERROR;
+ if (bufferSize > inSize - i)
+ return SZE_FAIL;
+ *outSizeProcessed += bufferSize;
+ for (j = 0; j < bufferSize && i < inSize; j++, i++)
+ outBuffer[i] = inBuffer[j];
+ }
+ #else
+ for (i = 0; i < inSize; i++)
+ outBuffer[i] = inBuffer[i];
+ *outSizeProcessed = inSize;
+ #endif
+ return SZ_OK;
+ }
+
+ if (AreMethodsEqual(&coder->MethodID, &k_LZMA))
+ {
+ #ifdef _LZMA_IN_CB
+ CLzmaInCallbackImp lzmaCallback;
+ #else
+ SizeT inProcessed;
+ #endif
+
+ CLzmaDecoderState state; /* it's about 24-80 bytes structure, if int is 32-bit */
+ int result;
+ SizeT outSizeProcessedLoc;
+
+ #ifdef _LZMA_IN_CB
+ lzmaCallback.Size = inSize;
+ lzmaCallback.InStream = inStream;
+ lzmaCallback.InCallback.Read = LzmaReadImp;
+ #endif
+
+ if (LzmaDecodeProperties(&state.Properties, coder->Properties.Items,
+ coder->Properties.Capacity) != LZMA_RESULT_OK)
+ return SZE_FAIL;
+
+ state.Probs = (CProb *)allocMain->Alloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
+ if (state.Probs == 0)
+ return SZE_OUTOFMEMORY;
+
+ #ifdef _LZMA_OUT_READ
+ if (state.Properties.DictionarySize == 0)
+ state.Dictionary = 0;
+ else
+ {
+ state.Dictionary = (unsigned char *)allocMain->Alloc(state.Properties.DictionarySize);
+ if (state.Dictionary == 0)
+ {
+ allocMain->Free(state.Probs);
+ return SZE_OUTOFMEMORY;
+ }
+ }
+ LzmaDecoderInit(&state);
+ #endif
+
+ result = LzmaDecode(&state,
+ #ifdef _LZMA_IN_CB
+ &lzmaCallback.InCallback,
+ #else
+ inBuffer, (SizeT)inSize, &inProcessed,
+ #endif
+ outBuffer, (SizeT)outSize, &outSizeProcessedLoc);
+ *outSizeProcessed = (size_t)outSizeProcessedLoc;
+ allocMain->Free(state.Probs);
+ #ifdef _LZMA_OUT_READ
+ allocMain->Free(state.Dictionary);
+ #endif
+ if (result == LZMA_RESULT_DATA_ERROR)
+ return SZE_DATA_ERROR;
+ if (result != LZMA_RESULT_OK)
+ return SZE_FAIL;
+ return SZ_OK;
+ }
+ return SZE_NOTIMPL;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zDecode.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zDecode.h new file mode 100644 index 00000000..432b7ce3 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zDecode.h @@ -0,0 +1,21 @@ +/* 7zDecode.h */
+
+#ifndef __7Z_DECODE_H
+#define __7Z_DECODE_H
+
+#include "7zItem.h"
+#include "7zAlloc.h"
+#ifdef _LZMA_IN_CB
+#include "7zIn.h"
+#endif
+
+SZ_RESULT SzDecode(const CFileSize *packSizes, const CFolder *folder,
+ #ifdef _LZMA_IN_CB
+ ISzInStream *stream,
+ #else
+ const Byte *inBuffer,
+ #endif
+ Byte *outBuffer, size_t outSize,
+ size_t *outSizeProcessed, ISzAlloc *allocMain);
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zExtract.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zExtract.c new file mode 100644 index 00000000..21fb0131 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zExtract.c @@ -0,0 +1,116 @@ +/* 7zExtract.c */
+
+#include "7zExtract.h"
+#include "7zDecode.h"
+#include "7zCrc.h"
+
+SZ_RESULT SzExtract(
+ ISzInStream *inStream,
+ CArchiveDatabaseEx *db,
+ UInt32 fileIndex,
+ UInt32 *blockIndex,
+ Byte **outBuffer,
+ size_t *outBufferSize,
+ size_t *offset,
+ size_t *outSizeProcessed,
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp)
+{
+ UInt32 folderIndex = db->FileIndexToFolderIndexMap[fileIndex];
+ SZ_RESULT res = SZ_OK;
+ *offset = 0;
+ *outSizeProcessed = 0;
+ if (folderIndex == (UInt32)-1)
+ {
+ allocMain->Free(*outBuffer);
+ *blockIndex = folderIndex;
+ *outBuffer = 0;
+ *outBufferSize = 0;
+ return SZ_OK;
+ }
+
+ if (*outBuffer == 0 || *blockIndex != folderIndex)
+ {
+ CFolder *folder = db->Database.Folders + folderIndex;
+ CFileSize unPackSize = SzFolderGetUnPackSize(folder);
+ #ifndef _LZMA_IN_CB
+ CFileSize packSize = SzArDbGetFolderFullPackSize(db, folderIndex);
+ Byte *inBuffer = 0;
+ size_t processedSize;
+ #endif
+ *blockIndex = folderIndex;
+ allocMain->Free(*outBuffer);
+ *outBuffer = 0;
+
+ RINOK(inStream->Seek(inStream, SzArDbGetFolderStreamPos(db, folderIndex, 0)));
+
+ #ifndef _LZMA_IN_CB
+ if (packSize != 0)
+ {
+ inBuffer = (Byte *)allocTemp->Alloc((size_t)packSize);
+ if (inBuffer == 0)
+ return SZE_OUTOFMEMORY;
+ }
+ res = inStream->Read(inStream, inBuffer, (size_t)packSize, &processedSize);
+ if (res == SZ_OK && processedSize != (size_t)packSize)
+ res = SZE_FAIL;
+ #endif
+ if (res == SZ_OK)
+ {
+ *outBufferSize = (size_t)unPackSize;
+ if (unPackSize != 0)
+ {
+ *outBuffer = (Byte *)allocMain->Alloc((size_t)unPackSize);
+ if (*outBuffer == 0)
+ res = SZE_OUTOFMEMORY;
+ }
+ if (res == SZ_OK)
+ {
+ size_t outRealSize;
+ res = SzDecode(db->Database.PackSizes +
+ db->FolderStartPackStreamIndex[folderIndex], folder,
+ #ifdef _LZMA_IN_CB
+ inStream,
+ #else
+ inBuffer,
+ #endif
+ *outBuffer, (size_t)unPackSize, &outRealSize, allocTemp);
+ if (res == SZ_OK)
+ {
+ if (outRealSize == (size_t)unPackSize)
+ {
+ if (folder->UnPackCRCDefined)
+ {
+ if (!CrcVerifyDigest(folder->UnPackCRC, *outBuffer, (size_t)unPackSize))
+ res = SZE_FAIL;
+ }
+ }
+ else
+ res = SZE_FAIL;
+ }
+ }
+ }
+ #ifndef _LZMA_IN_CB
+ allocTemp->Free(inBuffer);
+ #endif
+ }
+ if (res == SZ_OK)
+ {
+ UInt32 i;
+ CFileItem *fileItem = db->Database.Files + fileIndex;
+ *offset = 0;
+ for(i = db->FolderStartFileIndex[folderIndex]; i < fileIndex; i++)
+ *offset += (UInt32)db->Database.Files[i].Size;
+ *outSizeProcessed = (size_t)fileItem->Size;
+ if (*offset + *outSizeProcessed > *outBufferSize)
+ return SZE_FAIL;
+ {
+ if (fileItem->IsFileCRCDefined)
+ {
+ if (!CrcVerifyDigest(fileItem->FileCRC, *outBuffer + *offset, *outSizeProcessed))
+ res = SZE_FAIL;
+ }
+ }
+ }
+ return res;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zExtract.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zExtract.h new file mode 100644 index 00000000..4ae2a056 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zExtract.h @@ -0,0 +1,40 @@ +/* 7zExtract.h */
+
+#ifndef __7Z_EXTRACT_H
+#define __7Z_EXTRACT_H
+
+#include "7zIn.h"
+
+/*
+ SzExtract extracts file from archive
+
+ *outBuffer must be 0 before first call for each new archive.
+
+ Extracting cache:
+ If you need to decompress more than one file, you can send
+ these values from previous call:
+ *blockIndex,
+ *outBuffer,
+ *outBufferSize
+ You can consider "*outBuffer" as cache of solid block. If your archive is solid,
+ it will increase decompression speed.
+
+ If you use external function, you can declare these 3 cache variables
+ (blockIndex, outBuffer, outBufferSize) as static in that external function.
+
+ Free *outBuffer and set *outBuffer to 0, if you want to flush cache.
+*/
+
+SZ_RESULT SzExtract(
+ ISzInStream *inStream,
+ CArchiveDatabaseEx *db,
+ UInt32 fileIndex, /* index of file */
+ UInt32 *blockIndex, /* index of solid block */
+ Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */
+ size_t *outBufferSize, /* buffer size for output buffer */
+ size_t *offset, /* offset of stream for required file in *outBuffer */
+ size_t *outSizeProcessed, /* size of file in *outBuffer */
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp);
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zHeader.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zHeader.c new file mode 100644 index 00000000..e26c0143 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zHeader.c @@ -0,0 +1,5 @@ +/* 7zHeader.c */
+
+#include "7zHeader.h"
+
+Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zHeader.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zHeader.h new file mode 100644 index 00000000..7edf640f --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zHeader.h @@ -0,0 +1,55 @@ +/* 7zHeader.h */
+
+#ifndef __7Z_HEADER_H
+#define __7Z_HEADER_H
+
+#include "7zTypes.h"
+
+#define k7zSignatureSize 6
+extern Byte k7zSignature[k7zSignatureSize];
+
+#define k7zMajorVersion 0
+
+#define k7zStartHeaderSize 0x20
+
+enum EIdEnum
+{
+ k7zIdEnd,
+
+ k7zIdHeader,
+
+ k7zIdArchiveProperties,
+
+ k7zIdAdditionalStreamsInfo,
+ k7zIdMainStreamsInfo,
+ k7zIdFilesInfo,
+
+ k7zIdPackInfo,
+ k7zIdUnPackInfo,
+ k7zIdSubStreamsInfo,
+
+ k7zIdSize,
+ k7zIdCRC,
+
+ k7zIdFolder,
+
+ k7zIdCodersUnPackSize,
+ k7zIdNumUnPackStream,
+
+ k7zIdEmptyStream,
+ k7zIdEmptyFile,
+ k7zIdAnti,
+
+ k7zIdName,
+ k7zIdCreationTime,
+ k7zIdLastAccessTime,
+ k7zIdLastWriteTime,
+ k7zIdWinAttributes,
+ k7zIdComment,
+
+ k7zIdEncodedHeader,
+
+ k7zIdStartPos
+};
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zIn.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zIn.c new file mode 100644 index 00000000..6d910b6c --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zIn.c @@ -0,0 +1,1292 @@ +/* 7zIn.c */
+
+#include "7zIn.h"
+#include "7zCrc.h"
+#include "7zDecode.h"
+
+#define RINOM(x) { if((x) == 0) return SZE_OUTOFMEMORY; }
+
+void SzArDbExInit(CArchiveDatabaseEx *db)
+{
+ SzArchiveDatabaseInit(&db->Database);
+ db->FolderStartPackStreamIndex = 0;
+ db->PackStreamStartPositions = 0;
+ db->FolderStartFileIndex = 0;
+ db->FileIndexToFolderIndexMap = 0;
+}
+
+void SzArDbExFree(CArchiveDatabaseEx *db, void (*freeFunc)(void *))
+{
+ freeFunc(db->FolderStartPackStreamIndex);
+ freeFunc(db->PackStreamStartPositions);
+ freeFunc(db->FolderStartFileIndex);
+ freeFunc(db->FileIndexToFolderIndexMap);
+ SzArchiveDatabaseFree(&db->Database, freeFunc);
+ SzArDbExInit(db);
+}
+
+/*
+CFileSize GetFolderPackStreamSize(int folderIndex, int streamIndex) const
+{
+ return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex];
+}
+
+CFileSize GetFilePackSize(int fileIndex) const
+{
+ int folderIndex = FileIndexToFolderIndexMap[fileIndex];
+ if (folderIndex >= 0)
+ {
+ const CFolder &folderInfo = Folders[folderIndex];
+ if (FolderStartFileIndex[folderIndex] == fileIndex)
+ return GetFolderFullPackSize(folderIndex);
+ }
+ return 0;
+}
+*/
+
+
+SZ_RESULT MySzInAlloc(void **p, size_t size, void * (*allocFunc)(size_t size))
+{
+ if (size == 0)
+ *p = 0;
+ else
+ {
+ *p = allocFunc(size);
+ RINOM(*p);
+ }
+ return SZ_OK;
+}
+
+SZ_RESULT SzArDbExFill(CArchiveDatabaseEx *db, void * (*allocFunc)(size_t size))
+{
+ UInt32 startPos = 0;
+ CFileSize startPosSize = 0;
+ UInt32 i;
+ UInt32 folderIndex = 0;
+ UInt32 indexInFolder = 0;
+ RINOK(MySzInAlloc((void **)&db->FolderStartPackStreamIndex, db->Database.NumFolders * sizeof(UInt32), allocFunc));
+ for(i = 0; i < db->Database.NumFolders; i++)
+ {
+ db->FolderStartPackStreamIndex[i] = startPos;
+ startPos += db->Database.Folders[i].NumPackStreams;
+ }
+
+ RINOK(MySzInAlloc((void **)&db->PackStreamStartPositions, db->Database.NumPackStreams * sizeof(CFileSize), allocFunc));
+
+ for(i = 0; i < db->Database.NumPackStreams; i++)
+ {
+ db->PackStreamStartPositions[i] = startPosSize;
+ startPosSize += db->Database.PackSizes[i];
+ }
+
+ RINOK(MySzInAlloc((void **)&db->FolderStartFileIndex, db->Database.NumFolders * sizeof(UInt32), allocFunc));
+ RINOK(MySzInAlloc((void **)&db->FileIndexToFolderIndexMap, db->Database.NumFiles * sizeof(UInt32), allocFunc));
+
+ for (i = 0; i < db->Database.NumFiles; i++)
+ {
+ CFileItem *file = db->Database.Files + i;
+ int emptyStream = !file->HasStream;
+ if (emptyStream && indexInFolder == 0)
+ {
+ db->FileIndexToFolderIndexMap[i] = (UInt32)-1;
+ continue;
+ }
+ if (indexInFolder == 0)
+ {
+ /*
+ v3.13 incorrectly worked with empty folders
+ v4.07: Loop for skipping empty folders
+ */
+ while(1)
+ {
+ if (folderIndex >= db->Database.NumFolders)
+ return SZE_ARCHIVE_ERROR;
+ db->FolderStartFileIndex[folderIndex] = i;
+ if (db->Database.Folders[folderIndex].NumUnPackStreams != 0)
+ break;
+ folderIndex++;
+ }
+ }
+ db->FileIndexToFolderIndexMap[i] = folderIndex;
+ if (emptyStream)
+ continue;
+ indexInFolder++;
+ if (indexInFolder >= db->Database.Folders[folderIndex].NumUnPackStreams)
+ {
+ folderIndex++;
+ indexInFolder = 0;
+ }
+ }
+ return SZ_OK;
+}
+
+
+CFileSize SzArDbGetFolderStreamPos(CArchiveDatabaseEx *db, UInt32 folderIndex, UInt32 indexInFolder)
+{
+ return db->ArchiveInfo.DataStartPosition +
+ db->PackStreamStartPositions[db->FolderStartPackStreamIndex[folderIndex] + indexInFolder];
+}
+
+CFileSize SzArDbGetFolderFullPackSize(CArchiveDatabaseEx *db, UInt32 folderIndex)
+{
+ UInt32 packStreamIndex = db->FolderStartPackStreamIndex[folderIndex];
+ CFolder *folder = db->Database.Folders + folderIndex;
+ CFileSize size = 0;
+ UInt32 i;
+ for (i = 0; i < folder->NumPackStreams; i++)
+ size += db->Database.PackSizes[packStreamIndex + i];
+ return size;
+}
+
+
+/*
+SZ_RESULT SzReadTime(const CObjectVector<CSzByteBuffer> &dataVector,
+ CObjectVector<CFileItem> &files, UInt64 type)
+{
+ CBoolVector boolVector;
+ RINOK(ReadBoolVector2(files.Size(), boolVector))
+
+ CStreamSwitch streamSwitch;
+ RINOK(streamSwitch.Set(this, &dataVector));
+
+ for(int i = 0; i < files.Size(); i++)
+ {
+ CFileItem &file = files[i];
+ CArchiveFileTime fileTime;
+ bool defined = boolVector[i];
+ if (defined)
+ {
+ UInt32 low, high;
+ RINOK(SzReadUInt32(low));
+ RINOK(SzReadUInt32(high));
+ fileTime.dwLowDateTime = low;
+ fileTime.dwHighDateTime = high;
+ }
+ switch(type)
+ {
+ case k7zIdCreationTime:
+ file.IsCreationTimeDefined = defined;
+ if (defined)
+ file.CreationTime = fileTime;
+ break;
+ case k7zIdLastWriteTime:
+ file.IsLastWriteTimeDefined = defined;
+ if (defined)
+ file.LastWriteTime = fileTime;
+ break;
+ case k7zIdLastAccessTime:
+ file.IsLastAccessTimeDefined = defined;
+ if (defined)
+ file.LastAccessTime = fileTime;
+ break;
+ }
+ }
+ return SZ_OK;
+}
+*/
+
+SZ_RESULT SafeReadDirect(ISzInStream *inStream, Byte *data, size_t size)
+{
+ #ifdef _LZMA_IN_CB
+ while (size > 0)
+ {
+ Byte *inBuffer;
+ size_t processedSize;
+ RINOK(inStream->Read(inStream, (void **)&inBuffer, size, &processedSize));
+ if (processedSize == 0 || processedSize > size)
+ return SZE_FAIL;
+ size -= processedSize;
+ do
+ {
+ *data++ = *inBuffer++;
+ }
+ while (--processedSize != 0);
+ }
+ #else
+ size_t processedSize;
+ RINOK(inStream->Read(inStream, data, size, &processedSize));
+ if (processedSize != size)
+ return SZE_FAIL;
+ #endif
+ return SZ_OK;
+}
+
+SZ_RESULT SafeReadDirectByte(ISzInStream *inStream, Byte *data)
+{
+ return SafeReadDirect(inStream, data, 1);
+}
+
+SZ_RESULT SafeReadDirectUInt32(ISzInStream *inStream, UInt32 *value)
+{
+ int i;
+ *value = 0;
+ for (i = 0; i < 4; i++)
+ {
+ Byte b;
+ RINOK(SafeReadDirectByte(inStream, &b));
+ *value |= ((UInt32)b << (8 * i));
+ }
+ return SZ_OK;
+}
+
+SZ_RESULT SafeReadDirectUInt64(ISzInStream *inStream, UInt64 *value)
+{
+ int i;
+ *value = 0;
+ for (i = 0; i < 8; i++)
+ {
+ Byte b;
+ RINOK(SafeReadDirectByte(inStream, &b));
+ *value |= ((UInt32)b << (8 * i));
+ }
+ return SZ_OK;
+}
+
+int TestSignatureCandidate(Byte *testBytes)
+{
+ size_t i;
+ for (i = 0; i < k7zSignatureSize; i++)
+ if (testBytes[i] != k7zSignature[i])
+ return 0;
+ return 1;
+}
+
+typedef struct _CSzState
+{
+ Byte *Data;
+ size_t Size;
+}CSzData;
+
+SZ_RESULT SzReadByte(CSzData *sd, Byte *b)
+{
+ if (sd->Size == 0)
+ return SZE_ARCHIVE_ERROR;
+ sd->Size--;
+ *b = *sd->Data++;
+ return SZ_OK;
+}
+
+SZ_RESULT SzReadBytes(CSzData *sd, Byte *data, size_t size)
+{
+ size_t i;
+ for (i = 0; i < size; i++)
+ {
+ RINOK(SzReadByte(sd, data + i));
+ }
+ return SZ_OK;
+}
+
+SZ_RESULT SzReadUInt32(CSzData *sd, UInt32 *value)
+{
+ int i;
+ *value = 0;
+ for (i = 0; i < 4; i++)
+ {
+ Byte b;
+ RINOK(SzReadByte(sd, &b));
+ *value |= ((UInt32)(b) << (8 * i));
+ }
+ return SZ_OK;
+}
+
+SZ_RESULT SzReadNumber(CSzData *sd, UInt64 *value)
+{
+ Byte firstByte;
+ Byte mask = 0x80;
+ int i;
+ RINOK(SzReadByte(sd, &firstByte));
+ *value = 0;
+ for (i = 0; i < 8; i++)
+ {
+ Byte b;
+ if ((firstByte & mask) == 0)
+ {
+ UInt64 highPart = firstByte & (mask - 1);
+ *value += (highPart << (8 * i));
+ return SZ_OK;
+ }
+ RINOK(SzReadByte(sd, &b));
+ *value |= ((UInt64)b << (8 * i));
+ mask >>= 1;
+ }
+ return SZ_OK;
+}
+
+SZ_RESULT SzReadSize(CSzData *sd, CFileSize *value)
+{
+ UInt64 value64;
+ RINOK(SzReadNumber(sd, &value64));
+ *value = (CFileSize)value64;
+ return SZ_OK;
+}
+
+SZ_RESULT SzReadNumber32(CSzData *sd, UInt32 *value)
+{
+ UInt64 value64;
+ RINOK(SzReadNumber(sd, &value64));
+ if (value64 >= 0x80000000)
+ return SZE_NOTIMPL;
+ if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 2)))
+ return SZE_NOTIMPL;
+ *value = (UInt32)value64;
+ return SZ_OK;
+}
+
+SZ_RESULT SzReadID(CSzData *sd, UInt64 *value)
+{
+ return SzReadNumber(sd, value);
+}
+
+SZ_RESULT SzSkeepDataSize(CSzData *sd, UInt64 size)
+{
+ if (size > sd->Size)
+ return SZE_ARCHIVE_ERROR;
+ sd->Size -= (size_t)size;
+ sd->Data += (size_t)size;
+ return SZ_OK;
+}
+
+SZ_RESULT SzSkeepData(CSzData *sd)
+{
+ UInt64 size;
+ RINOK(SzReadNumber(sd, &size));
+ return SzSkeepDataSize(sd, size);
+}
+
+SZ_RESULT SzReadArchiveProperties(CSzData *sd)
+{
+ while(1)
+ {
+ UInt64 type;
+ RINOK(SzReadID(sd, &type));
+ if (type == k7zIdEnd)
+ break;
+ SzSkeepData(sd);
+ }
+ return SZ_OK;
+}
+
+SZ_RESULT SzWaitAttribute(CSzData *sd, UInt64 attribute)
+{
+ while(1)
+ {
+ UInt64 type;
+ RINOK(SzReadID(sd, &type));
+ if (type == attribute)
+ return SZ_OK;
+ if (type == k7zIdEnd)
+ return SZE_ARCHIVE_ERROR;
+ RINOK(SzSkeepData(sd));
+ }
+}
+
+SZ_RESULT SzReadBoolVector(CSzData *sd, size_t numItems, Byte **v, void * (*allocFunc)(size_t size))
+{
+ Byte b = 0;
+ Byte mask = 0;
+ size_t i;
+ RINOK(MySzInAlloc((void **)v, numItems * sizeof(Byte), allocFunc));
+ for(i = 0; i < numItems; i++)
+ {
+ if (mask == 0)
+ {
+ RINOK(SzReadByte(sd, &b));
+ mask = 0x80;
+ }
+ (*v)[i] = (Byte)(((b & mask) != 0) ? 1 : 0);
+ mask >>= 1;
+ }
+ return SZ_OK;
+}
+
+SZ_RESULT SzReadBoolVector2(CSzData *sd, size_t numItems, Byte **v, void * (*allocFunc)(size_t size))
+{
+ Byte allAreDefined;
+ size_t i;
+ RINOK(SzReadByte(sd, &allAreDefined));
+ if (allAreDefined == 0)
+ return SzReadBoolVector(sd, numItems, v, allocFunc);
+ RINOK(MySzInAlloc((void **)v, numItems * sizeof(Byte), allocFunc));
+ for(i = 0; i < numItems; i++)
+ (*v)[i] = 1;
+ return SZ_OK;
+}
+
+SZ_RESULT SzReadHashDigests(
+ CSzData *sd,
+ size_t numItems,
+ Byte **digestsDefined,
+ UInt32 **digests,
+ void * (*allocFunc)(size_t size))
+{
+ size_t i;
+ RINOK(SzReadBoolVector2(sd, numItems, digestsDefined, allocFunc));
+ RINOK(MySzInAlloc((void **)digests, numItems * sizeof(UInt32), allocFunc));
+ for(i = 0; i < numItems; i++)
+ if ((*digestsDefined)[i])
+ {
+ RINOK(SzReadUInt32(sd, (*digests) + i));
+ }
+ return SZ_OK;
+}
+
+SZ_RESULT SzReadPackInfo(
+ CSzData *sd,
+ CFileSize *dataOffset,
+ UInt32 *numPackStreams,
+ CFileSize **packSizes,
+ Byte **packCRCsDefined,
+ UInt32 **packCRCs,
+ void * (*allocFunc)(size_t size))
+{
+ UInt32 i;
+ RINOK(SzReadSize(sd, dataOffset));
+ RINOK(SzReadNumber32(sd, numPackStreams));
+
+ RINOK(SzWaitAttribute(sd, k7zIdSize));
+
+ RINOK(MySzInAlloc((void **)packSizes, (size_t)*numPackStreams * sizeof(CFileSize), allocFunc));
+
+ for(i = 0; i < *numPackStreams; i++)
+ {
+ RINOK(SzReadSize(sd, (*packSizes) + i));
+ }
+
+ while(1)
+ {
+ UInt64 type;
+ RINOK(SzReadID(sd, &type));
+ if (type == k7zIdEnd)
+ break;
+ if (type == k7zIdCRC)
+ {
+ RINOK(SzReadHashDigests(sd, (size_t)*numPackStreams, packCRCsDefined, packCRCs, allocFunc));
+ continue;
+ }
+ RINOK(SzSkeepData(sd));
+ }
+ if (*packCRCsDefined == 0)
+ {
+ RINOK(MySzInAlloc((void **)packCRCsDefined, (size_t)*numPackStreams * sizeof(Byte), allocFunc));
+ RINOK(MySzInAlloc((void **)packCRCs, (size_t)*numPackStreams * sizeof(UInt32), allocFunc));
+ for(i = 0; i < *numPackStreams; i++)
+ {
+ (*packCRCsDefined)[i] = 0;
+ (*packCRCs)[i] = 0;
+ }
+ }
+ return SZ_OK;
+}
+
+SZ_RESULT SzReadSwitch(CSzData *sd)
+{
+ Byte external;
+ RINOK(SzReadByte(sd, &external));
+ return (external == 0) ? SZ_OK: SZE_ARCHIVE_ERROR;
+}
+
+SZ_RESULT SzGetNextFolderItem(CSzData *sd, CFolder *folder, void * (*allocFunc)(size_t size))
+{
+ UInt32 numCoders;
+ UInt32 numBindPairs;
+ UInt32 numPackedStreams;
+ UInt32 i;
+ UInt32 numInStreams = 0;
+ UInt32 numOutStreams = 0;
+ RINOK(SzReadNumber32(sd, &numCoders));
+ folder->NumCoders = numCoders;
+
+ RINOK(MySzInAlloc((void **)&folder->Coders, (size_t)numCoders * sizeof(CCoderInfo), allocFunc));
+
+ for (i = 0; i < numCoders; i++)
+ SzCoderInfoInit(folder->Coders + i);
+
+ for (i = 0; i < numCoders; i++)
+ {
+ Byte mainByte;
+ CCoderInfo *coder = folder->Coders + i;
+ {
+ RINOK(SzReadByte(sd, &mainByte));
+ coder->MethodID.IDSize = (Byte)(mainByte & 0xF);
+ RINOK(SzReadBytes(sd, coder->MethodID.ID, coder->MethodID.IDSize));
+ if ((mainByte & 0x10) != 0)
+ {
+ RINOK(SzReadNumber32(sd, &coder->NumInStreams));
+ RINOK(SzReadNumber32(sd, &coder->NumOutStreams));
+ }
+ else
+ {
+ coder->NumInStreams = 1;
+ coder->NumOutStreams = 1;
+ }
+ if ((mainByte & 0x20) != 0)
+ {
+ UInt64 propertiesSize = 0;
+ RINOK(SzReadNumber(sd, &propertiesSize));
+ if (!SzByteBufferCreate(&coder->Properties, (size_t)propertiesSize, allocFunc))
+ return SZE_OUTOFMEMORY;
+ RINOK(SzReadBytes(sd, coder->Properties.Items, (size_t)propertiesSize));
+ }
+ }
+ while ((mainByte & 0x80) != 0)
+ {
+ RINOK(SzReadByte(sd, &mainByte));
+ RINOK(SzSkeepDataSize(sd, (mainByte & 0xF)));
+ if ((mainByte & 0x10) != 0)
+ {
+ UInt32 n;
+ RINOK(SzReadNumber32(sd, &n));
+ RINOK(SzReadNumber32(sd, &n));
+ }
+ if ((mainByte & 0x20) != 0)
+ {
+ UInt64 propertiesSize = 0;
+ RINOK(SzReadNumber(sd, &propertiesSize));
+ RINOK(SzSkeepDataSize(sd, propertiesSize));
+ }
+ }
+ numInStreams += (UInt32)coder->NumInStreams;
+ numOutStreams += (UInt32)coder->NumOutStreams;
+ }
+
+ numBindPairs = numOutStreams - 1;
+ folder->NumBindPairs = numBindPairs;
+
+
+ RINOK(MySzInAlloc((void **)&folder->BindPairs, (size_t)numBindPairs * sizeof(CBindPair), allocFunc));
+
+ for (i = 0; i < numBindPairs; i++)
+ {
+ CBindPair *bindPair = folder->BindPairs + i;;
+ RINOK(SzReadNumber32(sd, &bindPair->InIndex));
+ RINOK(SzReadNumber32(sd, &bindPair->OutIndex));
+ }
+
+ numPackedStreams = numInStreams - (UInt32)numBindPairs;
+
+ folder->NumPackStreams = numPackedStreams;
+ RINOK(MySzInAlloc((void **)&folder->PackStreams, (size_t)numPackedStreams * sizeof(UInt32), allocFunc));
+
+ if (numPackedStreams == 1)
+ {
+ UInt32 j;
+ UInt32 pi = 0;
+ for (j = 0; j < numInStreams; j++)
+ if (SzFolderFindBindPairForInStream(folder, j) < 0)
+ {
+ folder->PackStreams[pi++] = j;
+ break;
+ }
+ }
+ else
+ for(i = 0; i < numPackedStreams; i++)
+ {
+ RINOK(SzReadNumber32(sd, folder->PackStreams + i));
+ }
+ return SZ_OK;
+}
+
+SZ_RESULT SzReadUnPackInfo(
+ CSzData *sd,
+ UInt32 *numFolders,
+ CFolder **folders, /* for allocFunc */
+ void * (*allocFunc)(size_t size),
+ ISzAlloc *allocTemp)
+{
+ UInt32 i;
+ RINOK(SzWaitAttribute(sd, k7zIdFolder));
+ RINOK(SzReadNumber32(sd, numFolders));
+ {
+ RINOK(SzReadSwitch(sd));
+
+
+ RINOK(MySzInAlloc((void **)folders, (size_t)*numFolders * sizeof(CFolder), allocFunc));
+
+ for(i = 0; i < *numFolders; i++)
+ SzFolderInit((*folders) + i);
+
+ for(i = 0; i < *numFolders; i++)
+ {
+ RINOK(SzGetNextFolderItem(sd, (*folders) + i, allocFunc));
+ }
+ }
+
+ RINOK(SzWaitAttribute(sd, k7zIdCodersUnPackSize));
+
+ for(i = 0; i < *numFolders; i++)
+ {
+ UInt32 j;
+ CFolder *folder = (*folders) + i;
+ UInt32 numOutStreams = SzFolderGetNumOutStreams(folder);
+
+ RINOK(MySzInAlloc((void **)&folder->UnPackSizes, (size_t)numOutStreams * sizeof(CFileSize), allocFunc));
+
+ for(j = 0; j < numOutStreams; j++)
+ {
+ RINOK(SzReadSize(sd, folder->UnPackSizes + j));
+ }
+ }
+
+ while(1)
+ {
+ UInt64 type;
+ RINOK(SzReadID(sd, &type));
+ if (type == k7zIdEnd)
+ return SZ_OK;
+ if (type == k7zIdCRC)
+ {
+ SZ_RESULT res;
+ Byte *crcsDefined = 0;
+ UInt32 *crcs = 0;
+ res = SzReadHashDigests(sd, *numFolders, &crcsDefined, &crcs, allocTemp->Alloc);
+ if (res == SZ_OK)
+ {
+ for(i = 0; i < *numFolders; i++)
+ {
+ CFolder *folder = (*folders) + i;
+ folder->UnPackCRCDefined = crcsDefined[i];
+ folder->UnPackCRC = crcs[i];
+ }
+ }
+ allocTemp->Free(crcs);
+ allocTemp->Free(crcsDefined);
+ RINOK(res);
+ continue;
+ }
+ RINOK(SzSkeepData(sd));
+ }
+}
+
+SZ_RESULT SzReadSubStreamsInfo(
+ CSzData *sd,
+ UInt32 numFolders,
+ CFolder *folders,
+ UInt32 *numUnPackStreams,
+ CFileSize **unPackSizes,
+ Byte **digestsDefined,
+ UInt32 **digests,
+ ISzAlloc *allocTemp)
+{
+ UInt64 type = 0;
+ UInt32 i;
+ UInt32 si = 0;
+ UInt32 numDigests = 0;
+
+ for(i = 0; i < numFolders; i++)
+ folders[i].NumUnPackStreams = 1;
+ *numUnPackStreams = numFolders;
+
+ while(1)
+ {
+ RINOK(SzReadID(sd, &type));
+ if (type == k7zIdNumUnPackStream)
+ {
+ *numUnPackStreams = 0;
+ for(i = 0; i < numFolders; i++)
+ {
+ UInt32 numStreams;
+ RINOK(SzReadNumber32(sd, &numStreams));
+ folders[i].NumUnPackStreams = numStreams;
+ *numUnPackStreams += numStreams;
+ }
+ continue;
+ }
+ if (type == k7zIdCRC || type == k7zIdSize)
+ break;
+ if (type == k7zIdEnd)
+ break;
+ RINOK(SzSkeepData(sd));
+ }
+
+ if (*numUnPackStreams == 0)
+ {
+ *unPackSizes = 0;
+ *digestsDefined = 0;
+ *digests = 0;
+ }
+ else
+ {
+ *unPackSizes = (CFileSize *)allocTemp->Alloc((size_t)*numUnPackStreams * sizeof(CFileSize));
+ RINOM(*unPackSizes);
+ *digestsDefined = (Byte *)allocTemp->Alloc((size_t)*numUnPackStreams * sizeof(Byte));
+ RINOM(*digestsDefined);
+ *digests = (UInt32 *)allocTemp->Alloc((size_t)*numUnPackStreams * sizeof(UInt32));
+ RINOM(*digests);
+ }
+
+ for(i = 0; i < numFolders; i++)
+ {
+ /*
+ v3.13 incorrectly worked with empty folders
+ v4.07: we check that folder is empty
+ */
+ CFileSize sum = 0;
+ UInt32 j;
+ UInt32 numSubstreams = folders[i].NumUnPackStreams;
+ if (numSubstreams == 0)
+ continue;
+ if (type == k7zIdSize)
+ for (j = 1; j < numSubstreams; j++)
+ {
+ CFileSize size;
+ RINOK(SzReadSize(sd, &size));
+ (*unPackSizes)[si++] = size;
+ sum += size;
+ }
+ (*unPackSizes)[si++] = SzFolderGetUnPackSize(folders + i) - sum;
+ }
+ if (type == k7zIdSize)
+ {
+ RINOK(SzReadID(sd, &type));
+ }
+
+ for(i = 0; i < *numUnPackStreams; i++)
+ {
+ (*digestsDefined)[i] = 0;
+ (*digests)[i] = 0;
+ }
+
+
+ for(i = 0; i < numFolders; i++)
+ {
+ UInt32 numSubstreams = folders[i].NumUnPackStreams;
+ if (numSubstreams != 1 || !folders[i].UnPackCRCDefined)
+ numDigests += numSubstreams;
+ }
+
+
+ si = 0;
+ while(1)
+ {
+ if (type == k7zIdCRC)
+ {
+ int digestIndex = 0;
+ Byte *digestsDefined2 = 0;
+ UInt32 *digests2 = 0;
+ SZ_RESULT res = SzReadHashDigests(sd, numDigests, &digestsDefined2, &digests2, allocTemp->Alloc);
+ if (res == SZ_OK)
+ {
+ for (i = 0; i < numFolders; i++)
+ {
+ CFolder *folder = folders + i;
+ UInt32 numSubstreams = folder->NumUnPackStreams;
+ if (numSubstreams == 1 && folder->UnPackCRCDefined)
+ {
+ (*digestsDefined)[si] = 1;
+ (*digests)[si] = folder->UnPackCRC;
+ si++;
+ }
+ else
+ {
+ UInt32 j;
+ for (j = 0; j < numSubstreams; j++, digestIndex++)
+ {
+ (*digestsDefined)[si] = digestsDefined2[digestIndex];
+ (*digests)[si] = digests2[digestIndex];
+ si++;
+ }
+ }
+ }
+ }
+ allocTemp->Free(digestsDefined2);
+ allocTemp->Free(digests2);
+ RINOK(res);
+ }
+ else if (type == k7zIdEnd)
+ return SZ_OK;
+ else
+ {
+ RINOK(SzSkeepData(sd));
+ }
+ RINOK(SzReadID(sd, &type));
+ }
+}
+
+
+SZ_RESULT SzReadStreamsInfo(
+ CSzData *sd,
+ CFileSize *dataOffset,
+ CArchiveDatabase *db,
+ UInt32 *numUnPackStreams,
+ CFileSize **unPackSizes, /* allocTemp */
+ Byte **digestsDefined, /* allocTemp */
+ UInt32 **digests, /* allocTemp */
+ void * (*allocFunc)(size_t size),
+ ISzAlloc *allocTemp)
+{
+ while(1)
+ {
+ UInt64 type;
+ RINOK(SzReadID(sd, &type));
+ if ((UInt64)(int)type != type)
+ return SZE_FAIL;
+ switch((int)type)
+ {
+ case k7zIdEnd:
+ return SZ_OK;
+ case k7zIdPackInfo:
+ {
+ RINOK(SzReadPackInfo(sd, dataOffset, &db->NumPackStreams,
+ &db->PackSizes, &db->PackCRCsDefined, &db->PackCRCs, allocFunc));
+ break;
+ }
+ case k7zIdUnPackInfo:
+ {
+ RINOK(SzReadUnPackInfo(sd, &db->NumFolders, &db->Folders, allocFunc, allocTemp));
+ break;
+ }
+ case k7zIdSubStreamsInfo:
+ {
+ RINOK(SzReadSubStreamsInfo(sd, db->NumFolders, db->Folders,
+ numUnPackStreams, unPackSizes, digestsDefined, digests, allocTemp));
+ break;
+ }
+ default:
+ return SZE_FAIL;
+ }
+ }
+}
+
+Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+SZ_RESULT SzReadFileNames(CSzData *sd, UInt32 numFiles, CFileItem *files,
+ void * (*allocFunc)(size_t size))
+{
+ UInt32 i;
+ for(i = 0; i < numFiles; i++)
+ {
+ UInt32 len = 0;
+ UInt32 pos = 0;
+ CFileItem *file = files + i;
+ while(pos + 2 <= sd->Size)
+ {
+ int numAdds;
+ UInt32 value = (UInt32)(sd->Data[pos] | (((UInt32)sd->Data[pos + 1]) << 8));
+ pos += 2;
+ len++;
+ if (value == 0)
+ break;
+ if (value < 0x80)
+ continue;
+ if (value >= 0xD800 && value < 0xE000)
+ {
+ UInt32 c2;
+ if (value >= 0xDC00)
+ return SZE_ARCHIVE_ERROR;
+ if (pos + 2 > sd->Size)
+ return SZE_ARCHIVE_ERROR;
+ c2 = (UInt32)(sd->Data[pos] | (((UInt32)sd->Data[pos + 1]) << 8));
+ pos += 2;
+ if (c2 < 0xDC00 || c2 >= 0xE000)
+ return SZE_ARCHIVE_ERROR;
+ value = ((value - 0xD800) << 10) | (c2 - 0xDC00);
+ }
+ for (numAdds = 1; numAdds < 5; numAdds++)
+ if (value < (((UInt32)1) << (numAdds * 5 + 6)))
+ break;
+ len += numAdds;
+ }
+
+ RINOK(MySzInAlloc((void **)&file->Name, (size_t)len * sizeof(char), allocFunc));
+
+ len = 0;
+ while(2 <= sd->Size)
+ {
+ int numAdds;
+ UInt32 value = (UInt32)(sd->Data[0] | (((UInt32)sd->Data[1]) << 8));
+ SzSkeepDataSize(sd, 2);
+ if (value < 0x80)
+ {
+ file->Name[len++] = (char)value;
+ if (value == 0)
+ break;
+ continue;
+ }
+ if (value >= 0xD800 && value < 0xE000)
+ {
+ UInt32 c2 = (UInt32)(sd->Data[0] | (((UInt32)sd->Data[1]) << 8));
+ SzSkeepDataSize(sd, 2);
+ value = ((value - 0xD800) << 10) | (c2 - 0xDC00);
+ }
+ for (numAdds = 1; numAdds < 5; numAdds++)
+ if (value < (((UInt32)1) << (numAdds * 5 + 6)))
+ break;
+ file->Name[len++] = (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds)));
+ do
+ {
+ numAdds--;
+ file->Name[len++] = (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F));
+ }
+ while(numAdds > 0);
+
+ len += numAdds;
+ }
+ }
+ return SZ_OK;
+}
+
+SZ_RESULT SzReadHeader2(
+ CSzData *sd,
+ CArchiveDatabaseEx *db, /* allocMain */
+ CFileSize **unPackSizes, /* allocTemp */
+ Byte **digestsDefined, /* allocTemp */
+ UInt32 **digests, /* allocTemp */
+ Byte **emptyStreamVector, /* allocTemp */
+ Byte **emptyFileVector, /* allocTemp */
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp)
+{
+ UInt64 type;
+ UInt32 numUnPackStreams = 0;
+ UInt32 numFiles = 0;
+ CFileItem *files = 0;
+ UInt32 numEmptyStreams = 0;
+ UInt32 i;
+
+ RINOK(SzReadID(sd, &type));
+
+ if (type == k7zIdArchiveProperties)
+ {
+ RINOK(SzReadArchiveProperties(sd));
+ RINOK(SzReadID(sd, &type));
+ }
+
+
+ if (type == k7zIdMainStreamsInfo)
+ {
+ RINOK(SzReadStreamsInfo(sd,
+ &db->ArchiveInfo.DataStartPosition,
+ &db->Database,
+ &numUnPackStreams,
+ unPackSizes,
+ digestsDefined,
+ digests, allocMain->Alloc, allocTemp));
+ db->ArchiveInfo.DataStartPosition += db->ArchiveInfo.StartPositionAfterHeader;
+ RINOK(SzReadID(sd, &type));
+ }
+
+ if (type == k7zIdEnd)
+ return SZ_OK;
+ if (type != k7zIdFilesInfo)
+ return SZE_ARCHIVE_ERROR;
+
+ RINOK(SzReadNumber32(sd, &numFiles));
+ db->Database.NumFiles = numFiles;
+
+ RINOK(MySzInAlloc((void **)&files, (size_t)numFiles * sizeof(CFileItem), allocMain->Alloc));
+
+ db->Database.Files = files;
+ for(i = 0; i < numFiles; i++)
+ SzFileInit(files + i);
+
+ while(1)
+ {
+ UInt64 type;
+ UInt64 size;
+ RINOK(SzReadID(sd, &type));
+ if (type == k7zIdEnd)
+ break;
+ RINOK(SzReadNumber(sd, &size));
+
+ if ((UInt64)(int)type != type)
+ {
+ RINOK(SzSkeepDataSize(sd, size));
+ }
+ else
+ switch((int)type)
+ {
+ case k7zIdName:
+ {
+ RINOK(SzReadSwitch(sd));
+ RINOK(SzReadFileNames(sd, numFiles, files, allocMain->Alloc))
+ break;
+ }
+ case k7zIdEmptyStream:
+ {
+ RINOK(SzReadBoolVector(sd, numFiles, emptyStreamVector, allocTemp->Alloc));
+ numEmptyStreams = 0;
+ for (i = 0; i < numFiles; i++)
+ if ((*emptyStreamVector)[i])
+ numEmptyStreams++;
+ break;
+ }
+ case k7zIdEmptyFile:
+ {
+ RINOK(SzReadBoolVector(sd, numEmptyStreams, emptyFileVector, allocTemp->Alloc));
+ break;
+ }
+ default:
+ {
+ RINOK(SzSkeepDataSize(sd, size));
+ }
+ }
+ }
+
+ {
+ UInt32 emptyFileIndex = 0;
+ UInt32 sizeIndex = 0;
+ for(i = 0; i < numFiles; i++)
+ {
+ CFileItem *file = files + i;
+ file->IsAnti = 0;
+ if (*emptyStreamVector == 0)
+ file->HasStream = 1;
+ else
+ file->HasStream = (Byte)((*emptyStreamVector)[i] ? 0 : 1);
+ if(file->HasStream)
+ {
+ file->IsDirectory = 0;
+ file->Size = (*unPackSizes)[sizeIndex];
+ file->FileCRC = (*digests)[sizeIndex];
+ file->IsFileCRCDefined = (Byte)(*digestsDefined)[sizeIndex];
+ sizeIndex++;
+ }
+ else
+ {
+ if (*emptyFileVector == 0)
+ file->IsDirectory = 1;
+ else
+ file->IsDirectory = (Byte)((*emptyFileVector)[emptyFileIndex] ? 0 : 1);
+ emptyFileIndex++;
+ file->Size = 0;
+ file->IsFileCRCDefined = 0;
+ }
+ }
+ }
+ return SzArDbExFill(db, allocMain->Alloc);
+}
+
+SZ_RESULT SzReadHeader(
+ CSzData *sd,
+ CArchiveDatabaseEx *db,
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp)
+{
+ CFileSize *unPackSizes = 0;
+ Byte *digestsDefined = 0;
+ UInt32 *digests = 0;
+ Byte *emptyStreamVector = 0;
+ Byte *emptyFileVector = 0;
+ SZ_RESULT res = SzReadHeader2(sd, db,
+ &unPackSizes, &digestsDefined, &digests,
+ &emptyStreamVector, &emptyFileVector,
+ allocMain, allocTemp);
+ allocTemp->Free(unPackSizes);
+ allocTemp->Free(digestsDefined);
+ allocTemp->Free(digests);
+ allocTemp->Free(emptyStreamVector);
+ allocTemp->Free(emptyFileVector);
+ return res;
+}
+
+SZ_RESULT SzReadAndDecodePackedStreams2(
+ ISzInStream *inStream,
+ CSzData *sd,
+ CSzByteBuffer *outBuffer,
+ CFileSize baseOffset,
+ CArchiveDatabase *db,
+ CFileSize **unPackSizes,
+ Byte **digestsDefined,
+ UInt32 **digests,
+ #ifndef _LZMA_IN_CB
+ Byte **inBuffer,
+ #endif
+ ISzAlloc *allocTemp)
+{
+
+ UInt32 numUnPackStreams = 0;
+ CFileSize dataStartPos;
+ CFolder *folder;
+ #ifndef _LZMA_IN_CB
+ CFileSize packSize = 0;
+ UInt32 i = 0;
+ #endif
+ CFileSize unPackSize;
+ size_t outRealSize;
+ SZ_RESULT res;
+
+ RINOK(SzReadStreamsInfo(sd, &dataStartPos, db,
+ &numUnPackStreams, unPackSizes, digestsDefined, digests,
+ allocTemp->Alloc, allocTemp));
+
+ dataStartPos += baseOffset;
+ if (db->NumFolders != 1)
+ return SZE_ARCHIVE_ERROR;
+
+ folder = db->Folders;
+ unPackSize = SzFolderGetUnPackSize(folder);
+
+ RINOK(inStream->Seek(inStream, dataStartPos));
+
+ #ifndef _LZMA_IN_CB
+ for (i = 0; i < db->NumPackStreams; i++)
+ packSize += db->PackSizes[i];
+
+ RINOK(MySzInAlloc((void **)inBuffer, (size_t)packSize, allocTemp->Alloc));
+
+ RINOK(SafeReadDirect(inStream, *inBuffer, (size_t)packSize));
+ #endif
+
+ if (!SzByteBufferCreate(outBuffer, (size_t)unPackSize, allocTemp->Alloc))
+ return SZE_OUTOFMEMORY;
+
+ res = SzDecode(db->PackSizes, folder,
+ #ifdef _LZMA_IN_CB
+ inStream,
+ #else
+ *inBuffer,
+ #endif
+ outBuffer->Items, (size_t)unPackSize,
+ &outRealSize, allocTemp);
+ RINOK(res)
+ if (outRealSize != (UInt32)unPackSize)
+ return SZE_FAIL;
+ if (folder->UnPackCRCDefined)
+ if (!CrcVerifyDigest(folder->UnPackCRC, outBuffer->Items, (size_t)unPackSize))
+ return SZE_FAIL;
+ return SZ_OK;
+}
+
+SZ_RESULT SzReadAndDecodePackedStreams(
+ ISzInStream *inStream,
+ CSzData *sd,
+ CSzByteBuffer *outBuffer,
+ CFileSize baseOffset,
+ ISzAlloc *allocTemp)
+{
+ CArchiveDatabase db;
+ CFileSize *unPackSizes = 0;
+ Byte *digestsDefined = 0;
+ UInt32 *digests = 0;
+ #ifndef _LZMA_IN_CB
+ Byte *inBuffer = 0;
+ #endif
+ SZ_RESULT res;
+ SzArchiveDatabaseInit(&db);
+ res = SzReadAndDecodePackedStreams2(inStream, sd, outBuffer, baseOffset,
+ &db, &unPackSizes, &digestsDefined, &digests,
+ #ifndef _LZMA_IN_CB
+ &inBuffer,
+ #endif
+ allocTemp);
+ SzArchiveDatabaseFree(&db, allocTemp->Free);
+ allocTemp->Free(unPackSizes);
+ allocTemp->Free(digestsDefined);
+ allocTemp->Free(digests);
+ #ifndef _LZMA_IN_CB
+ allocTemp->Free(inBuffer);
+ #endif
+ return res;
+}
+
+SZ_RESULT SzArchiveOpen2(
+ ISzInStream *inStream,
+ CArchiveDatabaseEx *db,
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp)
+{
+ Byte signature[k7zSignatureSize];
+ Byte version;
+ UInt32 crcFromArchive;
+ UInt64 nextHeaderOffset;
+ UInt64 nextHeaderSize;
+ UInt32 nextHeaderCRC;
+ UInt32 crc;
+ CFileSize pos = 0;
+ CSzByteBuffer buffer;
+ CSzData sd;
+ SZ_RESULT res;
+
+ RINOK(SafeReadDirect(inStream, signature, k7zSignatureSize));
+
+ if (!TestSignatureCandidate(signature))
+ return SZE_ARCHIVE_ERROR;
+
+ /*
+ db.Clear();
+ db.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition;
+ */
+ RINOK(SafeReadDirectByte(inStream, &version));
+ if (version != k7zMajorVersion)
+ return SZE_ARCHIVE_ERROR;
+ RINOK(SafeReadDirectByte(inStream, &version));
+
+ RINOK(SafeReadDirectUInt32(inStream, &crcFromArchive));
+
+ CrcInit(&crc);
+ RINOK(SafeReadDirectUInt64(inStream, &nextHeaderOffset));
+ CrcUpdateUInt64(&crc, nextHeaderOffset);
+ RINOK(SafeReadDirectUInt64(inStream, &nextHeaderSize));
+ CrcUpdateUInt64(&crc, nextHeaderSize);
+ RINOK(SafeReadDirectUInt32(inStream, &nextHeaderCRC));
+ CrcUpdateUInt32(&crc, nextHeaderCRC);
+
+ pos = k7zStartHeaderSize;
+ db->ArchiveInfo.StartPositionAfterHeader = pos;
+
+ if (CrcGetDigest(&crc) != crcFromArchive)
+ return SZE_ARCHIVE_ERROR;
+
+ if (nextHeaderSize == 0)
+ return SZ_OK;
+
+ RINOK(inStream->Seek(inStream, (CFileSize)(pos + nextHeaderOffset)));
+
+ if (!SzByteBufferCreate(&buffer, (size_t)nextHeaderSize, allocTemp->Alloc))
+ return SZE_OUTOFMEMORY;
+
+ res = SafeReadDirect(inStream, buffer.Items, (size_t)nextHeaderSize);
+ if (res == SZ_OK)
+ {
+ if (CrcVerifyDigest(nextHeaderCRC, buffer.Items, (UInt32)nextHeaderSize))
+ {
+ while (1)
+ {
+ UInt64 type;
+ sd.Data = buffer.Items;
+ sd.Size = buffer.Capacity;
+ res = SzReadID(&sd, &type);
+ if (res != SZ_OK)
+ break;
+ if (type == k7zIdHeader)
+ {
+ res = SzReadHeader(&sd, db, allocMain, allocTemp);
+ break;
+ }
+ if (type != k7zIdEncodedHeader)
+ {
+ res = SZE_ARCHIVE_ERROR;
+ break;
+ }
+ {
+ CSzByteBuffer outBuffer;
+ res = SzReadAndDecodePackedStreams(inStream, &sd, &outBuffer,
+ db->ArchiveInfo.StartPositionAfterHeader,
+ allocTemp);
+ if (res != SZ_OK)
+ {
+ SzByteBufferFree(&outBuffer, allocTemp->Free);
+ break;
+ }
+ SzByteBufferFree(&buffer, allocTemp->Free);
+ buffer.Items = outBuffer.Items;
+ buffer.Capacity = outBuffer.Capacity;
+ }
+ }
+ }
+ }
+ SzByteBufferFree(&buffer, allocTemp->Free);
+ return res;
+}
+
+SZ_RESULT SzArchiveOpen(
+ ISzInStream *inStream,
+ CArchiveDatabaseEx *db,
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp)
+{
+ SZ_RESULT res = SzArchiveOpen2(inStream, db, allocMain, allocTemp);
+ if (res != SZ_OK)
+ SzArDbExFree(db, allocMain->Free);
+ return res;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zIn.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zIn.h new file mode 100644 index 00000000..8ded0ecc --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zIn.h @@ -0,0 +1,55 @@ +/* 7zIn.h */
+
+#ifndef __7Z_IN_H
+#define __7Z_IN_H
+
+#include "7zHeader.h"
+#include "7zItem.h"
+#include "7zAlloc.h"
+
+typedef struct _CInArchiveInfo
+{
+ CFileSize StartPositionAfterHeader;
+ CFileSize DataStartPosition;
+}CInArchiveInfo;
+
+typedef struct _CArchiveDatabaseEx
+{
+ CArchiveDatabase Database;
+ CInArchiveInfo ArchiveInfo;
+ UInt32 *FolderStartPackStreamIndex;
+ CFileSize *PackStreamStartPositions;
+ UInt32 *FolderStartFileIndex;
+ UInt32 *FileIndexToFolderIndexMap;
+}CArchiveDatabaseEx;
+
+void SzArDbExInit(CArchiveDatabaseEx *db);
+void SzArDbExFree(CArchiveDatabaseEx *db, void (*freeFunc)(void *));
+CFileSize SzArDbGetFolderStreamPos(CArchiveDatabaseEx *db, UInt32 folderIndex, UInt32 indexInFolder);
+CFileSize SzArDbGetFolderFullPackSize(CArchiveDatabaseEx *db, UInt32 folderIndex);
+
+typedef struct _ISzInStream
+{
+ #ifdef _LZMA_IN_CB
+ SZ_RESULT (*Read)(
+ void *object, /* pointer to ISzInStream itself */
+ void **buffer, /* out: pointer to buffer with data */
+ size_t maxRequiredSize, /* max required size to read */
+ size_t *processedSize); /* real processed size.
+ processedSize can be less than maxRequiredSize.
+ If processedSize == 0, then there are no more
+ bytes in stream. */
+ #else
+ SZ_RESULT (*Read)(void *object, void *buffer, size_t size, size_t *processedSize);
+ #endif
+ SZ_RESULT (*Seek)(void *object, CFileSize pos);
+} ISzInStream;
+
+
+int SzArchiveOpen(
+ ISzInStream *inStream,
+ CArchiveDatabaseEx *db,
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp);
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zItem.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zItem.c new file mode 100644 index 00000000..5f9a37f6 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zItem.c @@ -0,0 +1,133 @@ +/* 7zItem.c */
+
+#include "7zItem.h"
+#include "7zAlloc.h"
+
+void SzCoderInfoInit(CCoderInfo *coder)
+{
+ SzByteBufferInit(&coder->Properties);
+}
+
+void SzCoderInfoFree(CCoderInfo *coder, void (*freeFunc)(void *p))
+{
+ SzByteBufferFree(&coder->Properties, freeFunc);
+ SzCoderInfoInit(coder);
+}
+
+void SzFolderInit(CFolder *folder)
+{
+ folder->NumCoders = 0;
+ folder->Coders = 0;
+ folder->NumBindPairs = 0;
+ folder->BindPairs = 0;
+ folder->NumPackStreams = 0;
+ folder->PackStreams = 0;
+ folder->UnPackSizes = 0;
+ folder->UnPackCRCDefined = 0;
+ folder->UnPackCRC = 0;
+ folder->NumUnPackStreams = 0;
+}
+
+void SzFolderFree(CFolder *folder, void (*freeFunc)(void *p))
+{
+ UInt32 i;
+ for (i = 0; i < folder->NumCoders; i++)
+ SzCoderInfoFree(&folder->Coders[i], freeFunc);
+ freeFunc(folder->Coders);
+ freeFunc(folder->BindPairs);
+ freeFunc(folder->PackStreams);
+ freeFunc(folder->UnPackSizes);
+ SzFolderInit(folder);
+}
+
+UInt32 SzFolderGetNumOutStreams(CFolder *folder)
+{
+ UInt32 result = 0;
+ UInt32 i;
+ for (i = 0; i < folder->NumCoders; i++)
+ result += folder->Coders[i].NumOutStreams;
+ return result;
+}
+
+int SzFolderFindBindPairForInStream(CFolder *folder, UInt32 inStreamIndex)
+{
+ UInt32 i;
+ for(i = 0; i < folder->NumBindPairs; i++)
+ if (folder->BindPairs[i].InIndex == inStreamIndex)
+ return i;
+ return -1;
+}
+
+
+int SzFolderFindBindPairForOutStream(CFolder *folder, UInt32 outStreamIndex)
+{
+ UInt32 i;
+ for(i = 0; i < folder->NumBindPairs; i++)
+ if (folder->BindPairs[i].OutIndex == outStreamIndex)
+ return i;
+ return -1;
+}
+
+CFileSize SzFolderGetUnPackSize(CFolder *folder)
+{
+ int i = (int)SzFolderGetNumOutStreams(folder);
+ if (i == 0)
+ return 0;
+ for (i--; i >= 0; i--)
+ if (SzFolderFindBindPairForOutStream(folder, i) < 0)
+ return folder->UnPackSizes[i];
+ /* throw 1; */
+ return 0;
+}
+
+/*
+int FindPackStreamArrayIndex(int inStreamIndex) const
+{
+ for(int i = 0; i < PackStreams.Size(); i++)
+ if (PackStreams[i] == inStreamIndex)
+ return i;
+ return -1;
+}
+*/
+
+void SzFileInit(CFileItem *fileItem)
+{
+ fileItem->IsFileCRCDefined = 0;
+ fileItem->HasStream = 1;
+ fileItem->IsDirectory = 0;
+ fileItem->IsAnti = 0;
+ fileItem->Name = 0;
+}
+
+void SzFileFree(CFileItem *fileItem, void (*freeFunc)(void *p))
+{
+ freeFunc(fileItem->Name);
+ SzFileInit(fileItem);
+}
+
+void SzArchiveDatabaseInit(CArchiveDatabase *db)
+{
+ db->NumPackStreams = 0;
+ db->PackSizes = 0;
+ db->PackCRCsDefined = 0;
+ db->PackCRCs = 0;
+ db->NumFolders = 0;
+ db->Folders = 0;
+ db->NumFiles = 0;
+ db->Files = 0;
+}
+
+void SzArchiveDatabaseFree(CArchiveDatabase *db, void (*freeFunc)(void *))
+{
+ UInt32 i;
+ for (i = 0; i < db->NumFolders; i++)
+ SzFolderFree(&db->Folders[i], freeFunc);
+ for (i = 0; i < db->NumFiles; i++)
+ SzFileFree(&db->Files[i], freeFunc);
+ freeFunc(db->PackSizes);
+ freeFunc(db->PackCRCsDefined);
+ freeFunc(db->PackCRCs);
+ freeFunc(db->Folders);
+ freeFunc(db->Files);
+ SzArchiveDatabaseInit(db);
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zItem.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zItem.h new file mode 100644 index 00000000..e59b73f0 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zItem.h @@ -0,0 +1,90 @@ +/* 7zItem.h */
+
+#ifndef __7Z_ITEM_H
+#define __7Z_ITEM_H
+
+#include "7zMethodID.h"
+#include "7zHeader.h"
+#include "7zBuffer.h"
+
+typedef struct _CCoderInfo
+{
+ UInt32 NumInStreams;
+ UInt32 NumOutStreams;
+ CMethodID MethodID;
+ CSzByteBuffer Properties;
+}CCoderInfo;
+
+void SzCoderInfoInit(CCoderInfo *coder);
+void SzCoderInfoFree(CCoderInfo *coder, void (*freeFunc)(void *p));
+
+typedef struct _CBindPair
+{
+ UInt32 InIndex;
+ UInt32 OutIndex;
+}CBindPair;
+
+typedef struct _CFolder
+{
+ UInt32 NumCoders;
+ CCoderInfo *Coders;
+ UInt32 NumBindPairs;
+ CBindPair *BindPairs;
+ UInt32 NumPackStreams;
+ UInt32 *PackStreams;
+ CFileSize *UnPackSizes;
+ int UnPackCRCDefined;
+ UInt32 UnPackCRC;
+
+ UInt32 NumUnPackStreams;
+}CFolder;
+
+void SzFolderInit(CFolder *folder);
+CFileSize SzFolderGetUnPackSize(CFolder *folder);
+int SzFolderFindBindPairForInStream(CFolder *folder, UInt32 inStreamIndex);
+UInt32 SzFolderGetNumOutStreams(CFolder *folder);
+CFileSize SzFolderGetUnPackSize(CFolder *folder);
+
+/* #define CArchiveFileTime UInt64 */
+
+typedef struct _CFileItem
+{
+ /*
+ CArchiveFileTime LastWriteTime;
+ CFileSize StartPos;
+ UInt32 Attributes;
+ */
+ CFileSize Size;
+ UInt32 FileCRC;
+ char *Name;
+
+ Byte IsFileCRCDefined;
+ Byte HasStream;
+ Byte IsDirectory;
+ Byte IsAnti;
+ /*
+ int AreAttributesDefined;
+ int IsLastWriteTimeDefined;
+ int IsStartPosDefined;
+ */
+}CFileItem;
+
+void SzFileInit(CFileItem *fileItem);
+
+typedef struct _CArchiveDatabase
+{
+ UInt32 NumPackStreams;
+ CFileSize *PackSizes;
+ Byte *PackCRCsDefined;
+ UInt32 *PackCRCs;
+ UInt32 NumFolders;
+ CFolder *Folders;
+ UInt32 NumFiles;
+ CFileItem *Files;
+}CArchiveDatabase;
+
+void SzArchiveDatabaseInit(CArchiveDatabase *db);
+void SzArchiveDatabaseFree(CArchiveDatabase *db, void (*freeFunc)(void *));
+
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zMain.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zMain.c new file mode 100644 index 00000000..6b496da9 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zMain.c @@ -0,0 +1,223 @@ +/*
+7zMain.c
+Test application for 7z Decoder
+LZMA SDK 4.26 Copyright (c) 1999-2005 Igor Pavlov (2005-08-02)
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "7zCrc.h"
+#include "7zIn.h"
+#include "7zExtract.h"
+
+typedef struct _CFileInStream
+{
+ ISzInStream InStream;
+ FILE *File;
+} CFileInStream;
+
+#ifdef _LZMA_IN_CB
+
+#define kBufferSize (1 << 12)
+Byte g_Buffer[kBufferSize];
+
+SZ_RESULT SzFileReadImp(void *object, void **buffer, size_t maxRequiredSize, size_t *processedSize)
+{
+ CFileInStream *s = (CFileInStream *)object;
+ size_t processedSizeLoc;
+ if (maxRequiredSize > kBufferSize)
+ maxRequiredSize = kBufferSize;
+ processedSizeLoc = fread(g_Buffer, 1, maxRequiredSize, s->File);
+ *buffer = g_Buffer;
+ if (processedSize != 0)
+ *processedSize = processedSizeLoc;
+ return SZ_OK;
+}
+
+#else
+
+SZ_RESULT SzFileReadImp(void *object, void *buffer, size_t size, size_t *processedSize)
+{
+ CFileInStream *s = (CFileInStream *)object;
+ size_t processedSizeLoc = fread(buffer, 1, size, s->File);
+ if (processedSize != 0)
+ *processedSize = processedSizeLoc;
+ return SZ_OK;
+}
+
+#endif
+
+SZ_RESULT SzFileSeekImp(void *object, CFileSize pos)
+{
+ CFileInStream *s = (CFileInStream *)object;
+ int res = fseek(s->File, (long)pos, SEEK_SET);
+ if (res == 0)
+ return SZ_OK;
+ return SZE_FAIL;
+}
+
+void PrintError(char *sz)
+{
+ printf("\nERROR: %s\n", sz);
+}
+
+int main(int numargs, char *args[])
+{
+ CFileInStream archiveStream;
+ CArchiveDatabaseEx db;
+ SZ_RESULT res;
+ ISzAlloc allocImp;
+ ISzAlloc allocTempImp;
+
+ printf("\n7z ANSI-C Decoder 4.30 Copyright (c) 1999-2005 Igor Pavlov 2005-11-20\n");
+ if (numargs == 1)
+ {
+ printf(
+ "\nUsage: 7zDec <command> <archive_name>\n\n"
+ "<Commands>\n"
+ " e: Extract files from archive\n"
+ " l: List contents of archive\n"
+ " t: Test integrity of archive\n");
+ return 0;
+ }
+ if (numargs < 3)
+ {
+ PrintError("incorrect command");
+ return 1;
+ }
+
+ archiveStream.File = fopen(args[2], "rb");
+ if (archiveStream.File == 0)
+ {
+ PrintError("can not open input file");
+ return 1;
+ }
+
+ archiveStream.InStream.Read = SzFileReadImp;
+ archiveStream.InStream.Seek = SzFileSeekImp;
+
+ allocImp.Alloc = SzAlloc;
+ allocImp.Free = SzFree;
+
+ allocTempImp.Alloc = SzAllocTemp;
+ allocTempImp.Free = SzFreeTemp;
+
+ InitCrcTable();
+ SzArDbExInit(&db);
+ res = SzArchiveOpen(&archiveStream.InStream, &db, &allocImp, &allocTempImp);
+ if (res == SZ_OK)
+ {
+ char *command = args[1];
+ int listCommand = 0;
+ int testCommand = 0;
+ int extractCommand = 0;
+ if (strcmp(command, "l") == 0)
+ listCommand = 1;
+ if (strcmp(command, "t") == 0)
+ testCommand = 1;
+ else if (strcmp(command, "e") == 0)
+ extractCommand = 1;
+
+ if (listCommand)
+ {
+ UInt32 i;
+ for (i = 0; i < db.Database.NumFiles; i++)
+ {
+ CFileItem *f = db.Database.Files + i;
+ printf("%10d %s\n", (int)f->Size, f->Name);
+ }
+ }
+ else if (testCommand || extractCommand)
+ {
+ UInt32 i;
+
+ // if you need cache, use these 3 variables.
+ // if you use external function, you can make these variable as static.
+ UInt32 blockIndex = 0xFFFFFFFF; // it can have any value before first call (if outBuffer = 0)
+ Byte *outBuffer = 0; // it must be 0 before first call for each new archive.
+ size_t outBufferSize = 0; // it can have any value before first call (if outBuffer = 0)
+
+ printf("\n");
+ for (i = 0; i < db.Database.NumFiles; i++)
+ {
+ size_t offset;
+ size_t outSizeProcessed;
+ CFileItem *f = db.Database.Files + i;
+ if (f->IsDirectory)
+ printf("Directory ");
+ else
+ printf(testCommand ?
+ "Testing ":
+ "Extracting");
+ printf(" %s", f->Name);
+ if (f->IsDirectory)
+ {
+ printf("\n");
+ continue;
+ }
+ res = SzExtract(&archiveStream.InStream, &db, i,
+ &blockIndex, &outBuffer, &outBufferSize,
+ &offset, &outSizeProcessed,
+ &allocImp, &allocTempImp);
+ if (res != SZ_OK)
+ break;
+ if (!testCommand)
+ {
+ FILE *outputHandle;
+ UInt32 processedSize;
+ char *fileName = f->Name;
+ size_t nameLen = strlen(f->Name);
+ for (; nameLen > 0; nameLen--)
+ if (f->Name[nameLen - 1] == '/')
+ {
+ fileName = f->Name + nameLen;
+ break;
+ }
+
+ outputHandle = fopen(fileName, "wb+");
+ if (outputHandle == 0)
+ {
+ PrintError("can not open output file");
+ res = SZE_FAIL;
+ break;
+ }
+ processedSize = fwrite(outBuffer + offset, 1, outSizeProcessed, outputHandle);
+ if (processedSize != outSizeProcessed)
+ {
+ PrintError("can not write output file");
+ res = SZE_FAIL;
+ break;
+ }
+ if (fclose(outputHandle))
+ {
+ PrintError("can not close output file");
+ res = SZE_FAIL;
+ break;
+ }
+ }
+ printf("\n");
+ }
+ allocImp.Free(outBuffer);
+ }
+ else
+ {
+ PrintError("incorrect command");
+ res = SZE_FAIL;
+ }
+ }
+ SzArDbExFree(&db, allocImp.Free);
+
+ fclose(archiveStream.File);
+ if (res == SZ_OK)
+ {
+ printf("\nEverything is Ok\n");
+ return 0;
+ }
+ if (res == SZE_OUTOFMEMORY)
+ PrintError("can not allocate memory");
+ else
+ printf("\nERROR #%d\n", res);
+ return 1;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zMethodID.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zMethodID.c new file mode 100644 index 00000000..9daf39c2 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zMethodID.c @@ -0,0 +1,14 @@ +/* 7zMethodID.c */
+
+#include "7zMethodID.h"
+
+int AreMethodsEqual(CMethodID *a1, CMethodID *a2)
+{
+ int i;
+ if (a1->IDSize != a2->IDSize)
+ return 0;
+ for (i = 0; i < a1->IDSize; i++)
+ if (a1->ID[i] != a2->ID[i])
+ return 0;
+ return 1;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zMethodID.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zMethodID.h new file mode 100644 index 00000000..4d886899 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zMethodID.h @@ -0,0 +1,18 @@ +/* 7zMethodID.h */
+
+#ifndef __7Z_METHOD_ID_H
+#define __7Z_METHOD_ID_H
+
+#include "7zTypes.h"
+
+#define kMethodIDSize 15
+
+typedef struct _CMethodID
+{
+ Byte ID[kMethodIDSize];
+ Byte IDSize;
+} CMethodID;
+
+int AreMethodsEqual(CMethodID *a1, CMethodID *a2);
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zTypes.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zTypes.h new file mode 100644 index 00000000..28adc729 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7zTypes.h @@ -0,0 +1,61 @@ +/* 7zTypes.h */
+
+#ifndef __COMMON_TYPES_H
+#define __COMMON_TYPES_H
+
+#ifndef UInt32
+#ifdef _LZMA_UINT32_IS_ULONG
+#define UInt32 unsigned long
+#else
+#define UInt32 unsigned int
+#endif
+#endif
+
+#ifndef Byte
+#define Byte unsigned char
+#endif
+
+#ifndef UInt16
+#define UInt16 unsigned short
+#endif
+
+/* #define _SZ_NO_INT_64 */
+/* define it your compiler doesn't support long long int */
+
+#ifdef _SZ_NO_INT_64
+#define UInt64 unsigned long
+#else
+#ifdef _MSC_VER
+#define UInt64 unsigned __int64
+#else
+#define UInt64 unsigned long long int
+#endif
+#endif
+
+
+/* #define _SZ_FILE_SIZE_64 */
+/* Use _SZ_FILE_SIZE_64 if you need support for files larger than 4 GB*/
+
+#ifndef CFileSize
+#ifdef _SZ_FILE_SIZE_64
+#define CFileSize UInt64
+#else
+#define CFileSize UInt32
+#endif
+#endif
+
+#define SZ_RESULT int
+
+#define SZ_OK (0)
+#define SZE_DATA_ERROR (1)
+#define SZE_OUTOFMEMORY (2)
+#define SZE_CRC_ERROR (3)
+
+#define SZE_NOTIMPL (4)
+#define SZE_FAIL (5)
+
+#define SZE_ARCHIVE_ERROR (6)
+
+#define RINOK(x) { int __result_ = (x); if(__result_ != 0) return __result_; }
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7z_C.dsp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7z_C.dsp new file mode 100644 index 00000000..d83b30e3 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7z_C.dsp @@ -0,0 +1,178 @@ +# Microsoft Developer Studio Project File - Name="7z_C" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=7z_C - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "7z_C.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "7z_C.mak" CFG="7z_C - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "7z_C - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "7z_C - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "7z_C - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W4 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_LZMA_PROB32" /D "_LZMA_IN_CB" /YX /FD /c
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"Release/7zDec.exe"
+
+!ELSEIF "$(CFG)" == "7z_C - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_LZMA_PROB32" /D "_LZMA_IN_CB" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"Debug/7zDec.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "7z_C - Win32 Release"
+# Name "7z_C - Win32 Debug"
+# Begin Group "LZMA"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\LZMA_C\LzmaDecode.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LZMA_C\LzmaDecode.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\7zAlloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zAlloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zBuffer.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zCrc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zCrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zDecode.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zDecode.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zExtract.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zExtract.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zHeader.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zHeader.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zIn.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zIn.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zItem.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zMain.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zMethodID.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zMethodID.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zTypes.h
+# End Source File
+# End Target
+# End Project
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7z_C.dsw b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7z_C.dsw new file mode 100644 index 00000000..f1ee72bf --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/7z_C.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "7z_C"=.\7z_C.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/makefile b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/makefile new file mode 100644 index 00000000..eafbd057 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/makefile @@ -0,0 +1,55 @@ +PROG = 7zDec.exe
+
+!IFNDEF O
+!IFDEF CPU
+O=$(CPU)
+!ELSE
+O=O
+!ENDIF
+!ENDIF
+
+CFLAGS = $(CFLAGS) -nologo -c -Fo$O/ -GS-
+CFLAGS_O1 = $(CFLAGS) -O1
+CFLAGS_O2 = $(CFLAGS) -O2
+
+LFLAGS = $(LFLAGS) -nologo -OPT:NOWIN98
+
+PROGPATH = $O\$(PROG)
+
+COMPL_O1 = $(CPP) $(CFLAGS_O1) $**
+COMPL_O2 = $(CPP) $(CFLAGS_O2) $**
+COMPL = $(CPP) $(CFLAGS_O1) $**
+
+
+7Z_OBJS = \
+ $O\7zAlloc.obj \
+ $O\7zBuffer.obj \
+ $O\7zCrc.obj \
+ $O\7zDecode.obj \
+ $O\7zExtract.obj \
+ $O\7zHeader.obj \
+ $O\7zIn.obj \
+ $O\7zItem.obj \
+ $O\7zMain.obj \
+ $O\7zMethodID.obj \
+
+OBJS = \
+ $(7Z_OBJS) \
+ $O\LzmaDecode.obj \
+
+all: $(PROGPATH)
+
+clean:
+ -del /Q $(PROGPATH) $O\*.exe $O\*.dll $O\*.obj $O\*.lib $O\*.exp $O\*.res $O\*.pch
+
+$O:
+ if not exist "$O" mkdir "$O"
+
+$(PROGPATH): $O $(OBJS)
+ link $(LFLAGS) -out:$(PROGPATH) $(OBJS) $(LIBS)
+
+
+$(7Z_OBJS): $(*B).c
+ $(COMPL)
+$O\LzmaDecode.obj: ../../Compress/LZMA_C/$(*B).c
+ $(COMPL_O2)
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/makefile.gcc b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/makefile.gcc new file mode 100644 index 00000000..cc8bebf7 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Archive/7z_C/makefile.gcc @@ -0,0 +1,50 @@ +PROG = 7zDec
+CXX = g++
+LIB =
+RM = rm -f
+CFLAGS = -c -O2 -Wall
+
+OBJS = 7zAlloc.o 7zBuffer.o 7zCrc.o 7zDecode.o 7zExtract.o 7zHeader.o 7zIn.o 7zItem.o 7zMain.o 7zMethodID.o LzmaDecode.o
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(CXX) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIB)
+
+7zAlloc.o: 7zAlloc.c
+ $(CXX) $(CFLAGS) 7zAlloc.c
+
+7zBuffer.o: 7zBuffer.c
+ $(CXX) $(CFLAGS) 7zBuffer.c
+
+7zCrc.o: 7zCrc.c
+ $(CXX) $(CFLAGS) 7zCrc.c
+
+7zDecode.o: 7zDecode.c
+ $(CXX) $(CFLAGS) 7zDecode.c
+
+7zExtract.o: 7zExtract.c
+ $(CXX) $(CFLAGS) 7zExtract.c
+
+7zHeader.o: 7zHeader.c
+ $(CXX) $(CFLAGS) 7zHeader.c
+
+7zIn.o: 7zIn.c
+ $(CXX) $(CFLAGS) 7zIn.c
+
+7zItem.o: 7zItem.c
+ $(CXX) $(CFLAGS) 7zItem.c
+
+7zMain.o: 7zMain.c
+ $(CXX) $(CFLAGS) 7zMain.c
+
+7zMethodID.o: 7zMethodID.c
+ $(CXX) $(CFLAGS) 7zMethodID.c
+
+LzmaDecode.o: ../../Compress/LZMA_C/LzmaDecode.c
+ $(CXX) $(CFLAGS) ../../Compress/LZMA_C/LzmaDecode.c
+
+
+clean:
+ -$(RM) $(PROG) $(OBJS)
+
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/FileStreams.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/FileStreams.cpp new file mode 100644 index 00000000..7a32c6e7 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/FileStreams.cpp @@ -0,0 +1,251 @@ +// FileStreams.cpp
+
+#include "StdAfx.h"
+
+#ifndef _WIN32
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#endif
+
+#include "FileStreams.h"
+
+static inline HRESULT ConvertBoolToHRESULT(bool result)
+{
+ // return result ? S_OK: E_FAIL;
+ #ifdef _WIN32
+ return result ? S_OK: (::GetLastError());
+ #else
+ return result ? S_OK: E_FAIL;
+ #endif
+}
+
+bool CInFileStream::Open(LPCTSTR fileName)
+{
+ return File.Open(fileName);
+}
+
+#ifdef _WIN32
+#ifndef _UNICODE
+bool CInFileStream::Open(LPCWSTR fileName)
+{
+ return File.Open(fileName);
+}
+#endif
+#endif
+
+STDMETHODIMP CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ #ifdef _WIN32
+
+ UInt32 realProcessedSize;
+ bool result = File.ReadPart(data, size, realProcessedSize);
+ if(processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return ConvertBoolToHRESULT(result);
+
+ #else
+
+ if(processedSize != NULL)
+ *processedSize = 0;
+ ssize_t res = File.Read(data, (size_t)size);
+ if (res == -1)
+ return E_FAIL;
+ if(processedSize != NULL)
+ *processedSize = (UInt32)res;
+ return S_OK;
+
+ #endif
+}
+
+#ifndef _WIN32_WCE
+STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ #ifdef _WIN32
+ UInt32 realProcessedSize;
+ BOOL res = ::ReadFile(GetStdHandle(STD_INPUT_HANDLE),
+ data, size, (DWORD *)&realProcessedSize, NULL);
+ if(processedSize != NULL)
+ *processedSize = realProcessedSize;
+ if (res == FALSE && GetLastError() == ERROR_BROKEN_PIPE)
+ return S_OK;
+ return ConvertBoolToHRESULT(res != FALSE);
+
+ #else
+
+ if(processedSize != NULL)
+ *processedSize = 0;
+ ssize_t res;
+ do
+ {
+ res = read(0, data, (size_t)size);
+ }
+ while (res < 0 && (errno == EINTR));
+ if (res == -1)
+ return E_FAIL;
+ if(processedSize != NULL)
+ *processedSize = (UInt32)res;
+ return S_OK;
+
+ #endif
+}
+
+#endif
+
+STDMETHODIMP CInFileStream::Seek(Int64 offset, UInt32 seekOrigin,
+ UInt64 *newPosition)
+{
+ if(seekOrigin >= 3)
+ return STG_E_INVALIDFUNCTION;
+
+ #ifdef _WIN32
+
+ UInt64 realNewPosition;
+ bool result = File.Seek(offset, seekOrigin, realNewPosition);
+ if(newPosition != NULL)
+ *newPosition = realNewPosition;
+ return ConvertBoolToHRESULT(result);
+
+ #else
+
+ off_t res = File.Seek(offset, seekOrigin);
+ if (res == -1)
+ return E_FAIL;
+ if(newPosition != NULL)
+ *newPosition = (UInt64)res;
+ return S_OK;
+
+ #endif
+}
+
+STDMETHODIMP CInFileStream::GetSize(UInt64 *size)
+{
+ return ConvertBoolToHRESULT(File.GetLength(*size));
+}
+
+
+//////////////////////////
+// COutFileStream
+
+bool COutFileStream::Create(LPCTSTR fileName, bool createAlways)
+{
+ return File.Create(fileName, createAlways);
+}
+
+#ifdef _WIN32
+#ifndef _UNICODE
+bool COutFileStream::Create(LPCWSTR fileName, bool createAlways)
+{
+ return File.Create(fileName, createAlways);
+}
+#endif
+#endif
+
+STDMETHODIMP COutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ #ifdef _WIN32
+
+ UInt32 realProcessedSize;
+ bool result = File.WritePart(data, size, realProcessedSize);
+ if(processedSize != NULL)
+ *processedSize = realProcessedSize;
+ return ConvertBoolToHRESULT(result);
+
+ #else
+
+ if(processedSize != NULL)
+ *processedSize = 0;
+ ssize_t res = File.Write(data, (size_t)size);
+ if (res == -1)
+ return E_FAIL;
+ if(processedSize != NULL)
+ *processedSize = (UInt32)res;
+ return S_OK;
+
+ #endif
+}
+
+STDMETHODIMP COutFileStream::Seek(Int64 offset, UInt32 seekOrigin,
+ UInt64 *newPosition)
+{
+ if(seekOrigin >= 3)
+ return STG_E_INVALIDFUNCTION;
+ #ifdef _WIN32
+
+ UInt64 realNewPosition;
+ bool result = File.Seek(offset, seekOrigin, realNewPosition);
+ if(newPosition != NULL)
+ *newPosition = realNewPosition;
+ return ConvertBoolToHRESULT(result);
+
+ #else
+
+ off_t res = File.Seek(offset, seekOrigin);
+ if (res == -1)
+ return E_FAIL;
+ if(newPosition != NULL)
+ *newPosition = (UInt64)res;
+ return S_OK;
+
+ #endif
+}
+
+STDMETHODIMP COutFileStream::SetSize(Int64 newSize)
+{
+ #ifdef _WIN32
+ UInt64 currentPos;
+ if(!File.Seek(0, FILE_CURRENT, currentPos))
+ return E_FAIL;
+ bool result = File.SetLength(newSize);
+ UInt64 currentPos2;
+ result = result && File.Seek(currentPos, currentPos2);
+ return result ? S_OK : E_FAIL;
+ #else
+ return E_FAIL;
+ #endif
+}
+
+#ifndef _WIN32_WCE
+STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if(processedSize != NULL)
+ *processedSize = 0;
+
+ #ifdef _WIN32
+ UInt32 realProcessedSize;
+ BOOL res = TRUE;
+ if (size > 0)
+ {
+ // Seems that Windows doesn't like big amounts writing to stdout.
+ // So we limit portions by 32KB.
+ UInt32 sizeTemp = (1 << 15);
+ if (sizeTemp > size)
+ sizeTemp = size;
+ res = ::WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),
+ data, sizeTemp, (DWORD *)&realProcessedSize, NULL);
+ size -= realProcessedSize;
+ data = (const void *)((const Byte *)data + realProcessedSize);
+ if(processedSize != NULL)
+ *processedSize += realProcessedSize;
+ }
+ return ConvertBoolToHRESULT(res != FALSE);
+
+ #else
+
+ ssize_t res;
+ do
+ {
+ res = write(1, data, (size_t)size);
+ }
+ while (res < 0 && (errno == EINTR));
+ if (res == -1)
+ return E_FAIL;
+ if(processedSize != NULL)
+ *processedSize = (UInt32)res;
+ return S_OK;
+
+ return S_OK;
+ #endif
+}
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/FileStreams.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/FileStreams.h new file mode 100644 index 00000000..e6494f67 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/FileStreams.h @@ -0,0 +1,98 @@ +// FileStreams.h
+
+#ifndef __FILESTREAMS_H
+#define __FILESTREAMS_H
+
+#ifdef _WIN32
+#include "../../Windows/FileIO.h"
+#else
+#include "../../Common/C_FileIO.h"
+#endif
+
+#include "../IStream.h"
+#include "../../Common/MyCom.h"
+
+class CInFileStream:
+ public IInStream,
+ public IStreamGetSize,
+ public CMyUnknownImp
+{
+public:
+ #ifdef _WIN32
+ NWindows::NFile::NIO::CInFile File;
+ #else
+ NC::NFile::NIO::CInFile File;
+ #endif
+ CInFileStream() {}
+ virtual ~CInFileStream() {}
+
+ bool Open(LPCTSTR fileName);
+ #ifdef _WIN32
+ #ifndef _UNICODE
+ bool Open(LPCWSTR fileName);
+ #endif
+ #endif
+
+ MY_UNKNOWN_IMP2(IInStream, IStreamGetSize)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+
+ STDMETHOD(GetSize)(UInt64 *size);
+};
+
+#ifndef _WIN32_WCE
+class CStdInFileStream:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+public:
+ // HANDLE File;
+ // CStdInFileStream() File(INVALID_HANDLE_VALUE): {}
+ // void Open() { File = GetStdHandle(STD_INPUT_HANDLE); };
+ MY_UNKNOWN_IMP
+
+ virtual ~CStdInFileStream() {}
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+};
+#endif
+
+class COutFileStream:
+ public IOutStream,
+ public CMyUnknownImp
+{
+public:
+ #ifdef _WIN32
+ NWindows::NFile::NIO::COutFile File;
+ #else
+ NC::NFile::NIO::COutFile File;
+ #endif
+ virtual ~COutFileStream() {}
+ bool Create(LPCTSTR fileName, bool createAlways);
+ #ifdef _WIN32
+ #ifndef _UNICODE
+ bool Create(LPCWSTR fileName, bool createAlways);
+ #endif
+ #endif
+
+ MY_UNKNOWN_IMP1(IOutStream)
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+ STDMETHOD(SetSize)(Int64 newSize);
+};
+
+#ifndef _WIN32_WCE
+class CStdOutFileStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+
+ virtual ~CStdOutFileStream() {}
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+#endif
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/InBuffer.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/InBuffer.cpp new file mode 100644 index 00000000..17280b5b --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/InBuffer.cpp @@ -0,0 +1,80 @@ +// InBuffer.cpp
+
+#include "StdAfx.h"
+
+#include "InBuffer.h"
+
+#include "../../Common/Alloc.h"
+
+CInBuffer::CInBuffer():
+ _buffer(0),
+ _bufferLimit(0),
+ _bufferBase(0),
+ _stream(0),
+ _bufferSize(0)
+{}
+
+bool CInBuffer::Create(UInt32 bufferSize)
+{
+ const UInt32 kMinBlockSize = 1;
+ if (bufferSize < kMinBlockSize)
+ bufferSize = kMinBlockSize;
+ if (_bufferBase != 0 && _bufferSize == bufferSize)
+ return true;
+ Free();
+ _bufferSize = bufferSize;
+ _bufferBase = (Byte *)::MidAlloc(bufferSize);
+ return (_bufferBase != 0);
+}
+
+void CInBuffer::Free()
+{
+ ::MidFree(_bufferBase);
+ _bufferBase = 0;
+}
+
+void CInBuffer::SetStream(ISequentialInStream *stream)
+{
+ _stream = stream;
+}
+
+void CInBuffer::Init()
+{
+ _processedSize = 0;
+ _buffer = _bufferBase;
+ _bufferLimit = _buffer;
+ _wasFinished = false;
+ #ifdef _NO_EXCEPTIONS
+ ErrorCode = S_OK;
+ #endif
+}
+
+bool CInBuffer::ReadBlock()
+{
+ #ifdef _NO_EXCEPTIONS
+ if (ErrorCode != S_OK)
+ return false;
+ #endif
+ if (_wasFinished)
+ return false;
+ _processedSize += (_buffer - _bufferBase);
+ UInt32 numProcessedBytes;
+ HRESULT result = _stream->Read(_bufferBase, _bufferSize, &numProcessedBytes);
+ #ifdef _NO_EXCEPTIONS
+ ErrorCode = result;
+ #else
+ if (result != S_OK)
+ throw CInBufferException(result);
+ #endif
+ _buffer = _bufferBase;
+ _bufferLimit = _buffer + numProcessedBytes;
+ _wasFinished = (numProcessedBytes == 0);
+ return (!_wasFinished);
+}
+
+Byte CInBuffer::ReadBlock2()
+{
+ if(!ReadBlock())
+ return 0xFF;
+ return *_buffer++;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/InBuffer.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/InBuffer.h new file mode 100644 index 00000000..a59ecefa --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/InBuffer.h @@ -0,0 +1,76 @@ +// InBuffer.h
+
+#ifndef __INBUFFER_H
+#define __INBUFFER_H
+
+#include "../IStream.h"
+#include "../../Common/MyCom.h"
+
+#ifndef _NO_EXCEPTIONS
+class CInBufferException
+{
+public:
+ HRESULT ErrorCode;
+ CInBufferException(HRESULT errorCode): ErrorCode(errorCode) {}
+};
+#endif
+
+class CInBuffer
+{
+ Byte *_buffer;
+ Byte *_bufferLimit;
+ Byte *_bufferBase;
+ CMyComPtr<ISequentialInStream> _stream;
+ UInt64 _processedSize;
+ UInt32 _bufferSize;
+ bool _wasFinished;
+
+ bool ReadBlock();
+ Byte ReadBlock2();
+
+public:
+ #ifdef _NO_EXCEPTIONS
+ HRESULT ErrorCode;
+ #endif
+
+ CInBuffer();
+ ~CInBuffer() { Free(); }
+
+ bool Create(UInt32 bufferSize);
+ void Free();
+
+ void SetStream(ISequentialInStream *stream);
+ void Init();
+ void ReleaseStream() { _stream.Release(); }
+
+ bool ReadByte(Byte &b)
+ {
+ if(_buffer >= _bufferLimit)
+ if(!ReadBlock())
+ return false;
+ b = *_buffer++;
+ return true;
+ }
+ Byte ReadByte()
+ {
+ if(_buffer >= _bufferLimit)
+ return ReadBlock2();
+ return *_buffer++;
+ }
+ void ReadBytes(void *data, UInt32 size, UInt32 &processedSize)
+ {
+ for(processedSize = 0; processedSize < size; processedSize++)
+ if (!ReadByte(((Byte *)data)[processedSize]))
+ return;
+ }
+ bool ReadBytes(void *data, UInt32 size)
+ {
+ UInt32 processedSize;
+ ReadBytes(data, size, processedSize);
+ return (processedSize == size);
+ }
+ UInt64 GetProcessedSize() const { return _processedSize + (_buffer - _bufferBase); }
+ bool WasFinished() const { return _wasFinished; }
+};
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/OutBuffer.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/OutBuffer.cpp new file mode 100644 index 00000000..e76e6f4d --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/OutBuffer.cpp @@ -0,0 +1,117 @@ +// OutByte.cpp
+
+#include "StdAfx.h"
+
+#include "OutBuffer.h"
+
+#include "../../Common/Alloc.h"
+
+bool COutBuffer::Create(UInt32 bufferSize)
+{
+ const UInt32 kMinBlockSize = 1;
+ if (bufferSize < kMinBlockSize)
+ bufferSize = kMinBlockSize;
+ if (_buffer != 0 && _bufferSize == bufferSize)
+ return true;
+ Free();
+ _bufferSize = bufferSize;
+ _buffer = (Byte *)::MidAlloc(bufferSize);
+ return (_buffer != 0);
+}
+
+void COutBuffer::Free()
+{
+ ::MidFree(_buffer);
+ _buffer = 0;
+}
+
+void COutBuffer::SetStream(ISequentialOutStream *stream)
+{
+ _stream = stream;
+}
+
+void COutBuffer::Init()
+{
+ _streamPos = 0;
+ _limitPos = _bufferSize;
+ _pos = 0;
+ _processedSize = 0;
+ _overDict = false;
+ #ifdef _NO_EXCEPTIONS
+ ErrorCode = S_OK;
+ #endif
+}
+
+UInt64 COutBuffer::GetProcessedSize() const
+{
+ UInt64 res = _processedSize + _pos - _streamPos;
+ if (_streamPos > _pos)
+ res += _bufferSize;
+ return res;
+}
+
+
+HRESULT COutBuffer::FlushPart()
+{
+ // _streamPos < _bufferSize
+ UInt32 size = (_streamPos >= _pos) ? (_bufferSize - _streamPos) : (_pos - _streamPos);
+ HRESULT result = S_OK;
+ #ifdef _NO_EXCEPTIONS
+ if (ErrorCode != S_OK)
+ result = ErrorCode;
+ #endif
+ if (_buffer2 != 0)
+ {
+ memmove(_buffer2, _buffer + _streamPos, size);
+ _buffer2 += size;
+ }
+
+ if (_stream != 0
+ #ifdef _NO_EXCEPTIONS
+ && (ErrorCode != S_OK)
+ #endif
+ )
+ {
+ UInt32 processedSize = 0;
+ result = _stream->Write(_buffer + _streamPos, size, &processedSize);
+ size = processedSize;
+ }
+ _streamPos += size;
+ if (_streamPos == _bufferSize)
+ _streamPos = 0;
+ if (_pos == _bufferSize)
+ {
+ _overDict = true;
+ _pos = 0;
+ }
+ _limitPos = (_streamPos > _pos) ? _streamPos : _bufferSize;
+ _processedSize += size;
+ return result;
+}
+
+HRESULT COutBuffer::Flush()
+{
+ #ifdef _NO_EXCEPTIONS
+ if (ErrorCode != S_OK)
+ return ErrorCode;
+ #endif
+
+ while(_streamPos != _pos)
+ {
+ HRESULT result = FlushPart();
+ if (result != S_OK)
+ return result;
+ }
+ return S_OK;
+}
+
+void COutBuffer::FlushWithCheck()
+{
+ HRESULT result = FlushPart();
+ #ifdef _NO_EXCEPTIONS
+ ErrorCode = result;
+ #else
+ if (result != S_OK)
+ throw COutBufferException(result);
+ #endif
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/OutBuffer.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/OutBuffer.h new file mode 100644 index 00000000..37eefbdf --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/OutBuffer.h @@ -0,0 +1,64 @@ +// OutBuffer.h
+
+#ifndef __OUTBUFFER_H
+#define __OUTBUFFER_H
+
+#include "../IStream.h"
+#include "../../Common/MyCom.h"
+
+#ifndef _NO_EXCEPTIONS
+struct COutBufferException
+{
+ HRESULT ErrorCode;
+ COutBufferException(HRESULT errorCode): ErrorCode(errorCode) {}
+};
+#endif
+
+class COutBuffer
+{
+protected:
+ Byte *_buffer;
+ UInt32 _pos;
+ UInt32 _limitPos;
+ UInt32 _streamPos;
+ UInt32 _bufferSize;
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _processedSize;
+ Byte *_buffer2;
+ bool _overDict;
+
+ HRESULT FlushPart();
+ void FlushWithCheck();
+public:
+ #ifdef _NO_EXCEPTIONS
+ HRESULT ErrorCode;
+ #endif
+
+ COutBuffer(): _buffer(0), _pos(0), _stream(0), _buffer2(0) {}
+ ~COutBuffer() { Free(); }
+
+ bool Create(UInt32 bufferSize);
+ void Free();
+
+ void SetMemStream(Byte *buffer) { _buffer2 = buffer; }
+ void SetStream(ISequentialOutStream *stream);
+ void Init();
+ HRESULT Flush();
+ void ReleaseStream() { _stream.Release(); }
+
+ void WriteByte(Byte b)
+ {
+ _buffer[_pos++] = b;
+ if(_pos == _limitPos)
+ FlushWithCheck();
+ }
+ void WriteBytes(const void *data, size_t size)
+ {
+ for (size_t i = 0; i < size; i++)
+ WriteByte(((const Byte *)data)[i]);
+ }
+
+ UInt64 GetProcessedSize() const;
+};
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/StdAfx.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/StdAfx.h new file mode 100644 index 00000000..d7d9211b --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/StdAfx.h @@ -0,0 +1,9 @@ +// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../Common/MyWindows.h"
+#include "../../Common/NewHandler.h"
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/StreamUtils.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/StreamUtils.cpp new file mode 100644 index 00000000..712a7858 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/StreamUtils.cpp @@ -0,0 +1,44 @@ +// StreamUtils.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyCom.h"
+#include "StreamUtils.h"
+
+HRESULT ReadStream(ISequentialInStream *stream, void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != 0)
+ *processedSize = 0;
+ while(size != 0)
+ {
+ UInt32 processedSizeLoc;
+ HRESULT res = stream->Read(data, size, &processedSizeLoc);
+ if (processedSize != 0)
+ *processedSize += processedSizeLoc;
+ data = (Byte *)((Byte *)data + processedSizeLoc);
+ size -= processedSizeLoc;
+ RINOK(res);
+ if (processedSizeLoc == 0)
+ return S_OK;
+ }
+ return S_OK;
+}
+
+HRESULT WriteStream(ISequentialOutStream *stream, const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize != 0)
+ *processedSize = 0;
+ while(size != 0)
+ {
+ UInt32 processedSizeLoc;
+ HRESULT res = stream->Write(data, size, &processedSizeLoc);
+ if (processedSize != 0)
+ *processedSize += processedSizeLoc;
+ data = (const void *)((const Byte *)data + processedSizeLoc);
+ size -= processedSizeLoc;
+ RINOK(res);
+ if (processedSizeLoc == 0)
+ break;
+ }
+ return S_OK;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/StreamUtils.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/StreamUtils.h new file mode 100644 index 00000000..c8cd8cef --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Common/StreamUtils.h @@ -0,0 +1,11 @@ +// StreamUtils.h
+
+#ifndef __STREAMUTILS_H
+#define __STREAMUTILS_H
+
+#include "../IStream.h"
+
+HRESULT ReadStream(ISequentialInStream *stream, void *data, UInt32 size, UInt32 *processedSize);
+HRESULT WriteStream(ISequentialOutStream *stream, const void *data, UInt32 size, UInt32 *processedSize);
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/ARM.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/ARM.cpp new file mode 100644 index 00000000..1a52ea9e --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/ARM.cpp @@ -0,0 +1,16 @@ +// ARM.cpp
+
+#include "StdAfx.h"
+#include "ARM.h"
+
+#include "BranchARM.c"
+
+UInt32 CBC_ARM_Encoder::SubFilter(Byte *data, UInt32 size)
+{
+ return ::ARM_Convert(data, size, _bufferPos, 1);
+}
+
+UInt32 CBC_ARM_Decoder::SubFilter(Byte *data, UInt32 size)
+{
+ return ::ARM_Convert(data, size, _bufferPos, 0);
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/ARM.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/ARM.h new file mode 100644 index 00000000..83c91e31 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/ARM.h @@ -0,0 +1,10 @@ +// ARM.h
+
+#ifndef __ARM_H
+#define __ARM_H
+
+#include "BranchCoder.h"
+
+MyClassA(BC_ARM, 0x05, 1)
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/ARMThumb.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/ARMThumb.cpp new file mode 100644 index 00000000..83f5d9b8 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/ARMThumb.cpp @@ -0,0 +1,16 @@ +// ARMThumb.cpp
+
+#include "StdAfx.h"
+#include "ARMThumb.h"
+
+#include "BranchARMThumb.c"
+
+UInt32 CBC_ARMThumb_Encoder::SubFilter(Byte *data, UInt32 size)
+{
+ return ::ARMThumb_Convert(data, size, _bufferPos, 1);
+}
+
+UInt32 CBC_ARMThumb_Decoder::SubFilter(Byte *data, UInt32 size)
+{
+ return ::ARMThumb_Convert(data, size, _bufferPos, 0);
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/ARMThumb.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/ARMThumb.h new file mode 100644 index 00000000..f59c737b --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/ARMThumb.h @@ -0,0 +1,10 @@ +// ARMThumb.h
+
+#ifndef __ARMTHUMB_H
+#define __ARMTHUMB_H
+
+#include "BranchCoder.h"
+
+MyClassA(BC_ARMThumb, 0x07, 1)
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchARM.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchARM.c new file mode 100644 index 00000000..53680ef4 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchARM.c @@ -0,0 +1,26 @@ +// BranchARM.c
+
+#include "BranchARM.h"
+
+UInt32 ARM_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding)
+{
+ UInt32 i;
+ for (i = 0; i + 4 <= size; i += 4)
+ {
+ if (data[i + 3] == 0xEB)
+ {
+ UInt32 src = (data[i + 2] << 16) | (data[i + 1] << 8) | (data[i + 0]);
+ src <<= 2;
+ UInt32 dest;
+ if (encoding)
+ dest = nowPos + i + 8 + src;
+ else
+ dest = src - (nowPos + i + 8);
+ dest >>= 2;
+ data[i + 2] = (dest >> 16);
+ data[i + 1] = (dest >> 8);
+ data[i + 0] = dest;
+ }
+ }
+ return i;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchARM.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchARM.h new file mode 100644 index 00000000..63e55dc8 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchARM.h @@ -0,0 +1,10 @@ +// BranchARM.h
+
+#ifndef __BRANCH_ARM_H
+#define __BRANCH_ARM_H
+
+#include "Common/Types.h"
+
+UInt32 ARM_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding);
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchARMThumb.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchARMThumb.c new file mode 100644 index 00000000..6d0f5ba1 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchARMThumb.c @@ -0,0 +1,35 @@ +// BranchARMThumb.c
+
+#include "BranchARMThumb.h"
+
+UInt32 ARMThumb_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding)
+{
+ UInt32 i;
+ for (i = 0; i + 4 <= size; i += 2)
+ {
+ if ((data[i + 1] & 0xF8) == 0xF0 &&
+ (data[i + 3] & 0xF8) == 0xF8)
+ {
+ UInt32 src =
+ ((data[i + 1] & 0x7) << 19) |
+ (data[i + 0] << 11) |
+ ((data[i + 3] & 0x7) << 8) |
+ (data[i + 2]);
+
+ src <<= 1;
+ UInt32 dest;
+ if (encoding)
+ dest = nowPos + i + 4 + src;
+ else
+ dest = src - (nowPos + i + 4);
+ dest >>= 1;
+
+ data[i + 1] = 0xF0 | ((dest >> 19) & 0x7);
+ data[i + 0] = (dest >> 11);
+ data[i + 3] = 0xF8 | ((dest >> 8) & 0x7);
+ data[i + 2] = (dest);
+ i += 2;
+ }
+ }
+ return i;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchARMThumb.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchARMThumb.h new file mode 100644 index 00000000..032d94da --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchARMThumb.h @@ -0,0 +1,10 @@ +// BranchARMThumb.h
+
+#ifndef __BRANCH_ARM_THUMB_H
+#define __BRANCH_ARM_THUMB_H
+
+#include "Common/Types.h"
+
+UInt32 ARMThumb_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding);
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchCoder.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchCoder.cpp new file mode 100644 index 00000000..68e938bd --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchCoder.cpp @@ -0,0 +1,18 @@ +// BranchCoder.cpp
+
+#include "StdAfx.h"
+#include "BranchCoder.h"
+
+STDMETHODIMP CBranchConverter::Init()
+{
+ _bufferPos = 0;
+ SubInit();
+ return S_OK;
+}
+
+STDMETHODIMP_(UInt32) CBranchConverter::Filter(Byte *data, UInt32 size)
+{
+ UInt32 processedSize = SubFilter(data, size);
+ _bufferPos += processedSize;
+ return processedSize;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchCoder.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchCoder.h new file mode 100644 index 00000000..b64562df --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchCoder.h @@ -0,0 +1,54 @@ +// BranchCoder.h
+
+#ifndef __BRANCH_CODER_H
+#define __BRANCH_CODER_H
+
+#include "Common/MyCom.h"
+#include "Common/Types.h"
+#include "Common/Alloc.h"
+
+#include "../../ICoder.h"
+
+class CBranchConverter:
+ public ICompressFilter,
+ public CMyUnknownImp
+{
+protected:
+ UInt32 _bufferPos;
+ virtual void SubInit() {}
+ virtual UInt32 SubFilter(Byte *data, UInt32 size) = 0;
+public:
+ MY_UNKNOWN_IMP;
+ STDMETHOD(Init)();
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size);
+};
+
+#define MyClassEncoderA(Name) class C ## Name: public CBranchConverter \
+ { public: UInt32 SubFilter(Byte *data, UInt32 size); };
+
+#define MyClassDecoderA(Name) class C ## Name: public CBranchConverter \
+ { public: UInt32 SubFilter(Byte *data, UInt32 size); };
+
+#define MyClassEncoderB(Name, ADD_ITEMS, ADD_INIT) class C ## Name: public CBranchConverter, public ADD_ITEMS \
+ { public: UInt32 SubFilter(Byte *data, UInt32 size); ADD_INIT};
+
+#define MyClassDecoderB(Name, ADD_ITEMS, ADD_INIT) class C ## Name: public CBranchConverter, public ADD_ITEMS \
+ { public: UInt32 SubFilter(Byte *data, UInt32 size); ADD_INIT};
+
+#define MyClass2b(Name, id, subId, encodingId) \
+DEFINE_GUID(CLSID_CCompressConvert ## Name, \
+0x23170F69, 0x40C1, 0x278B, 0x03, 0x03, id, subId, 0x00, 0x00, encodingId, 0x00);
+
+#define MyClassA(Name, id, subId) \
+MyClass2b(Name ## _Encoder, id, subId, 0x01) \
+MyClassEncoderA(Name ## _Encoder) \
+MyClass2b(Name ## _Decoder, id, subId, 0x00) \
+MyClassDecoderA(Name ## _Decoder)
+
+#define MyClassB(Name, id, subId, ADD_ITEMS, ADD_INIT) \
+MyClass2b(Name ## _Encoder, id, subId, 0x01) \
+MyClassEncoderB(Name ## _Encoder, ADD_ITEMS, ADD_INIT) \
+MyClass2b(Name ## _Decoder, id, subId, 0x00) \
+MyClassDecoderB(Name ## _Decoder, ADD_ITEMS, ADD_INIT)
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchIA64.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchIA64.c new file mode 100644 index 00000000..8571aac1 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchIA64.c @@ -0,0 +1,65 @@ +// BranchIA64.c
+
+#include "BranchIA64.h"
+
+const Byte kBranchTable[32] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 4, 4, 6, 6, 0, 0, 7, 7,
+ 4, 4, 0, 0, 4, 4, 0, 0
+};
+
+UInt32 IA64_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding)
+{
+ UInt32 i;
+ for (i = 0; i + 16 <= size; i += 16)
+ {
+ UInt32 instrTemplate = data[i] & 0x1F;
+ UInt32 mask = kBranchTable[instrTemplate];
+ UInt32 bitPos = 5;
+ for (int slot = 0; slot < 3; slot++, bitPos += 41)
+ {
+ if (((mask >> slot) & 1) == 0)
+ continue;
+ UInt32 bytePos = (bitPos >> 3);
+ UInt32 bitRes = bitPos & 0x7;
+ // UInt64 instruction = *(UInt64 *)(data + i + bytePos);
+ UInt64 instruction = 0;
+ int j;
+ for (j = 0; j < 6; j++)
+ instruction += (UInt64)(data[i + j + bytePos]) << (8 * j);
+
+ UInt64 instNorm = instruction >> bitRes;
+ if (((instNorm >> 37) & 0xF) == 0x5
+ && ((instNorm >> 9) & 0x7) == 0
+ // && (instNorm & 0x3F)== 0
+ )
+ {
+ UInt32 src = UInt32((instNorm >> 13) & 0xFFFFF);
+ src |= ((instNorm >> 36) & 1) << 20;
+
+ src <<= 4;
+
+ UInt32 dest;
+ if (encoding)
+ dest = nowPos + i + src;
+ else
+ dest = src - (nowPos + i);
+
+ dest >>= 4;
+
+ instNorm &= ~(UInt64(0x8FFFFF) << 13);
+ instNorm |= (UInt64(dest & 0xFFFFF) << 13);
+ instNorm |= (UInt64(dest & 0x100000) << (36 - 20));
+
+ instruction &= (1 << bitRes) - 1;
+ instruction |= (instNorm << bitRes);
+ // *(UInt64 *)(data + i + bytePos) = instruction;
+ for (j = 0; j < 6; j++)
+ data[i + j + bytePos] = Byte(instruction >> (8 * j));
+ }
+ }
+ }
+ return i;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchIA64.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchIA64.h new file mode 100644 index 00000000..2e96c137 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchIA64.h @@ -0,0 +1,10 @@ +// BranchIA64.h
+
+#ifndef __BRANCH_IA64_H
+#define __BRANCH_IA64_H
+
+#include "Common/Types.h"
+
+UInt32 IA64_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding);
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchPPC.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchPPC.c new file mode 100644 index 00000000..407bae61 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchPPC.c @@ -0,0 +1,36 @@ +// BranchPPC.c
+
+#include "BranchPPC.h"
+
+UInt32 PPC_B_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding)
+{
+ UInt32 i;
+ for (i = 0; i + 4 <= size; i += 4)
+ {
+ // PowerPC branch 6(48) 24(Offset) 1(Abs) 1(Link)
+ if ((data[i] >> 2) == 0x12 &&
+ (
+ (data[i + 3] & 3) == 1
+ // || (data[i+3] & 3) == 3
+ )
+ )
+ {
+ UInt32 src = ((data[i + 0] & 3) << 24) |
+ (data[i + 1] << 16) |
+ (data[i + 2] << 8) |
+ (data[i + 3] & (~3));
+
+ UInt32 dest;
+ if (encoding)
+ dest = nowPos + i + src;
+ else
+ dest = src - (nowPos + i);
+ data[i + 0] = 0x48 | ((dest >> 24) & 0x3);
+ data[i + 1] = (dest >> 16);
+ data[i + 2] = (dest >> 8);
+ data[i + 3] &= 0x3;
+ data[i + 3] |= dest;
+ }
+ }
+ return i;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchPPC.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchPPC.h new file mode 100644 index 00000000..405efbb1 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchPPC.h @@ -0,0 +1,10 @@ +// BranchPPC.h
+
+#ifndef __BRANCH_PPC_H
+#define __BRANCH_PPC_H
+
+#include "Common/Types.h"
+
+UInt32 PPC_B_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding);
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchSPARC.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchSPARC.c new file mode 100644 index 00000000..abbf1d75 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchSPARC.c @@ -0,0 +1,36 @@ +// BranchSPARC.c
+
+#include "BranchSPARC.h"
+
+UInt32 SPARC_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding)
+{
+ UInt32 i;
+ for (i = 0; i + 4 <= size; i += 4)
+ {
+ if (data[i] == 0x40 && (data[i + 1] & 0xC0) == 0x00 ||
+ data[i] == 0x7F && (data[i + 1] & 0xC0) == 0xC0)
+ {
+ UInt32 src =
+ ((UInt32)data[i + 0] << 24) |
+ ((UInt32)data[i + 1] << 16) |
+ ((UInt32)data[i + 2] << 8) |
+ ((UInt32)data[i + 3]);
+
+ src <<= 2;
+ UInt32 dest;
+ if (encoding)
+ dest = nowPos + i + src;
+ else
+ dest = src - (nowPos + i);
+ dest >>= 2;
+
+ dest = (((0 - ((dest >> 22) & 1)) << 22) & 0x3FFFFFFF) | (dest & 0x3FFFFF) | 0x40000000;
+
+ data[i + 0] = (Byte)(dest >> 24);
+ data[i + 1] = (Byte)(dest >> 16);
+ data[i + 2] = (Byte)(dest >> 8);
+ data[i + 3] = (Byte)dest;
+ }
+ }
+ return i;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchSPARC.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchSPARC.h new file mode 100644 index 00000000..431bac58 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchSPARC.h @@ -0,0 +1,10 @@ +// BranchSPARC.h
+
+#ifndef __BRANCH_SPARC_H
+#define __BRANCH_SPARC_H
+
+#include "Common/Types.h"
+
+UInt32 SPARC_B_Convert(Byte *data, UInt32 size, UInt32 nowPos, int encoding);
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchX86.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchX86.c new file mode 100644 index 00000000..2d2c03d2 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchX86.c @@ -0,0 +1,101 @@ +/* BranchX86.c */
+
+#include "BranchX86.h"
+
+/*
+static int inline Test86MSByte(Byte b)
+{
+ return (b == 0 || b == 0xFF);
+}
+*/
+#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)
+
+const int kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0};
+const Byte kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3};
+
+/*
+void x86_Convert_Init(UInt32 *prevMask, UInt32 *prevPos)
+{
+ *prevMask = 0;
+ *prevPos = (UInt32)(-5);
+}
+*/
+
+UInt32 x86_Convert(Byte *buffer, UInt32 endPos, UInt32 nowPos,
+ UInt32 *prevMask, UInt32 *prevPos, int encoding)
+{
+ UInt32 bufferPos = 0;
+ UInt32 limit;
+
+ if (endPos < 5)
+ return 0;
+
+ if (nowPos - *prevPos > 5)
+ *prevPos = nowPos - 5;
+
+ limit = endPos - 5;
+ while(bufferPos <= limit)
+ {
+ Byte b = buffer[bufferPos];
+ UInt32 offset;
+ if (b != 0xE8 && b != 0xE9)
+ {
+ bufferPos++;
+ continue;
+ }
+ offset = (nowPos + bufferPos - *prevPos);
+ *prevPos = (nowPos + bufferPos);
+ if (offset > 5)
+ *prevMask = 0;
+ else
+ {
+ UInt32 i;
+ for (i = 0; i < offset; i++)
+ {
+ *prevMask &= 0x77;
+ *prevMask <<= 1;
+ }
+ }
+ b = buffer[bufferPos + 4];
+ if (Test86MSByte(b) && kMaskToAllowedStatus[(*prevMask >> 1) & 0x7] &&
+ (*prevMask >> 1) < 0x10)
+ {
+ UInt32 src =
+ ((UInt32)(b) << 24) |
+ ((UInt32)(buffer[bufferPos + 3]) << 16) |
+ ((UInt32)(buffer[bufferPos + 2]) << 8) |
+ (buffer[bufferPos + 1]);
+
+ UInt32 dest;
+ while(1)
+ {
+ UInt32 index;
+ if (encoding)
+ dest = (nowPos + bufferPos + 5) + src;
+ else
+ dest = src - (nowPos + bufferPos + 5);
+ if (*prevMask == 0)
+ break;
+ index = kMaskToBitNumber[*prevMask >> 1];
+ b = (Byte)(dest >> (24 - index * 8));
+ if (!Test86MSByte(b))
+ break;
+ src = dest ^ ((1 << (32 - index * 8)) - 1);
+ }
+ buffer[bufferPos + 4] = (Byte)(~(((dest >> 24) & 1) - 1));
+ buffer[bufferPos + 3] = (Byte)(dest >> 16);
+ buffer[bufferPos + 2] = (Byte)(dest >> 8);
+ buffer[bufferPos + 1] = (Byte)dest;
+ bufferPos += 5;
+ *prevMask = 0;
+ }
+ else
+ {
+ bufferPos++;
+ *prevMask |= 1;
+ if (Test86MSByte(b))
+ *prevMask |= 0x10;
+ }
+ }
+ return bufferPos;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchX86.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchX86.h new file mode 100644 index 00000000..879fd50e --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/BranchX86.h @@ -0,0 +1,19 @@ +/* BranchX86.h */
+
+#ifndef __BRANCHX86_H
+#define __BRANCHX86_H
+
+#ifndef UInt32
+#define UInt32 unsigned int
+#endif
+
+#ifndef Byte
+#define Byte unsigned char
+#endif
+
+#define x86_Convert_Init(prevMask, prevPos) { prevMask = 0; prevPos = (UInt32)(-5); }
+
+UInt32 x86_Convert(Byte *buffer, UInt32 endPos, UInt32 nowPos,
+ UInt32 *prevMask, UInt32 *prevPos, int encoding);
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/IA64.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/IA64.cpp new file mode 100644 index 00000000..a579c408 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/IA64.cpp @@ -0,0 +1,16 @@ +// IA64.cpp
+
+#include "StdAfx.h"
+#include "IA64.h"
+
+#include "BranchIA64.c"
+
+UInt32 CBC_IA64_Encoder::SubFilter(Byte *data, UInt32 size)
+{
+ return ::IA64_Convert(data, size, _bufferPos, 1);
+}
+
+UInt32 CBC_IA64_Decoder::SubFilter(Byte *data, UInt32 size)
+{
+ return ::IA64_Convert(data, size, _bufferPos, 0);
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/IA64.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/IA64.h new file mode 100644 index 00000000..f47d5e4b --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/IA64.h @@ -0,0 +1,10 @@ +// IA64.h
+
+#ifndef __IA64_H
+#define __IA64_H
+
+#include "BranchCoder.h"
+
+MyClassA(BC_IA64, 0x04, 1)
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/PPC.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/PPC.cpp new file mode 100644 index 00000000..c191f519 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/PPC.cpp @@ -0,0 +1,17 @@ +// PPC.cpp
+
+#include "StdAfx.h"
+#include "PPC.h"
+
+#include "Windows/Defs.h"
+#include "BranchPPC.c"
+
+UInt32 CBC_PPC_B_Encoder::SubFilter(Byte *data, UInt32 size)
+{
+ return ::PPC_B_Convert(data, size, _bufferPos, 1);
+}
+
+UInt32 CBC_PPC_B_Decoder::SubFilter(Byte *data, UInt32 size)
+{
+ return ::PPC_B_Convert(data, size, _bufferPos, 0);
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/PPC.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/PPC.h new file mode 100644 index 00000000..e2fbb409 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/PPC.h @@ -0,0 +1,10 @@ +// PPC.h
+
+#ifndef __PPC_H
+#define __PPC_H
+
+#include "BranchCoder.h"
+
+MyClassA(BC_PPC_B, 0x02, 5)
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/SPARC.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/SPARC.cpp new file mode 100644 index 00000000..552551db --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/SPARC.cpp @@ -0,0 +1,17 @@ +// SPARC.cpp
+
+#include "StdAfx.h"
+#include "SPARC.h"
+
+#include "Windows/Defs.h"
+#include "BranchSPARC.c"
+
+UInt32 CBC_SPARC_Encoder::SubFilter(Byte *data, UInt32 size)
+{
+ return ::SPARC_Convert(data, size, _bufferPos, 1);
+}
+
+UInt32 CBC_SPARC_Decoder::SubFilter(Byte *data, UInt32 size)
+{
+ return ::SPARC_Convert(data, size, _bufferPos, 0);
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/SPARC.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/SPARC.h new file mode 100644 index 00000000..1e2c8afe --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/SPARC.h @@ -0,0 +1,10 @@ +// SPARC.h
+
+#ifndef __SPARC_H
+#define __SPARC_H
+
+#include "BranchCoder.h"
+
+MyClassA(BC_SPARC, 0x08, 5)
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/StdAfx.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/StdAfx.h new file mode 100644 index 00000000..83fdd22d --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/StdAfx.h @@ -0,0 +1,8 @@ +// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/x86.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/x86.cpp new file mode 100644 index 00000000..929484ad --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/x86.cpp @@ -0,0 +1,18 @@ +// x86.cpp
+
+#include "StdAfx.h"
+#include "x86.h"
+
+#include "Windows/Defs.h"
+
+#include "BranchX86.c"
+
+UInt32 CBCJ_x86_Encoder::SubFilter(Byte *data, UInt32 size)
+{
+ return ::x86_Convert(data, size, _bufferPos, &_prevMask, &_prevPos, 1);
+}
+
+UInt32 CBCJ_x86_Decoder::SubFilter(Byte *data, UInt32 size)
+{
+ return ::x86_Convert(data, size, _bufferPos, &_prevMask, &_prevPos, 0);
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/x86.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/x86.h new file mode 100644 index 00000000..85882d91 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/x86.h @@ -0,0 +1,19 @@ +// x86.h
+
+#ifndef __X86_H
+#define __X86_H
+
+#include "BranchCoder.h"
+#include "BranchX86.h"
+
+struct CBranch86
+{
+ UInt32 _prevMask;
+ UInt32 _prevPos;
+ void x86Init() { x86_Convert_Init(_prevMask, _prevPos); }
+};
+
+MyClassB(BCJ_x86, 0x01, 3, CBranch86 ,
+ virtual void SubInit() { x86Init(); })
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/x86_2.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/x86_2.cpp new file mode 100644 index 00000000..fc87bd93 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/x86_2.cpp @@ -0,0 +1,412 @@ +// x86_2.cpp
+
+#include "StdAfx.h"
+#include "x86_2.h"
+
+#include "../../../Common/Alloc.h"
+
+static const int kBufferSize = 1 << 17;
+
+inline bool IsJcc(Byte b0, Byte b1)
+{
+ return (b0 == 0x0F && (b1 & 0xF0) == 0x80);
+}
+
+#ifndef EXTRACT_ONLY
+
+static bool inline Test86MSByte(Byte b)
+{
+ return (b == 0 || b == 0xFF);
+}
+
+bool CBCJ2_x86_Encoder::Create()
+{
+ if (!_mainStream.Create(1 << 16))
+ return false;
+ if (!_callStream.Create(1 << 20))
+ return false;
+ if (!_jumpStream.Create(1 << 20))
+ return false;
+ if (!_rangeEncoder.Create(1 << 20))
+ return false;
+ if (_buffer == 0)
+ {
+ _buffer = (Byte *)MidAlloc(kBufferSize);
+ if (_buffer == 0)
+ return false;
+ }
+ return true;
+}
+
+CBCJ2_x86_Encoder::~CBCJ2_x86_Encoder()
+{
+ ::MidFree(_buffer);
+}
+
+HRESULT CBCJ2_x86_Encoder::Flush()
+{
+ RINOK(_mainStream.Flush());
+ RINOK(_callStream.Flush());
+ RINOK(_jumpStream.Flush());
+ _rangeEncoder.FlushData();
+ return _rangeEncoder.FlushStream();
+}
+
+const UInt32 kDefaultLimit = (1 << 24);
+
+HRESULT CBCJ2_x86_Encoder::CodeReal(ISequentialInStream **inStreams,
+ const UInt64 **inSizes,
+ UInt32 numInStreams,
+ ISequentialOutStream **outStreams,
+ const UInt64 **outSizes,
+ UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ if (numInStreams != 1 || numOutStreams != 4)
+ return E_INVALIDARG;
+
+ if (!Create())
+ return E_OUTOFMEMORY;
+
+ bool sizeIsDefined = false;
+ UInt64 inSize;
+ if (inSizes != NULL)
+ if (inSizes[0] != NULL)
+ {
+ inSize = *inSizes[0];
+ if (inSize <= kDefaultLimit)
+ sizeIsDefined = true;
+ }
+
+ ISequentialInStream *inStream = inStreams[0];
+
+ _mainStream.SetStream(outStreams[0]);
+ _mainStream.Init();
+ _callStream.SetStream(outStreams[1]);
+ _callStream.Init();
+ _jumpStream.SetStream(outStreams[2]);
+ _jumpStream.Init();
+ _rangeEncoder.SetStream(outStreams[3]);
+ _rangeEncoder.Init();
+ for (int i = 0; i < 256; i++)
+ _statusE8Encoder[i].Init();
+ _statusE9Encoder.Init();
+ _statusJccEncoder.Init();
+ CCoderReleaser releaser(this);
+
+ CMyComPtr<ICompressGetSubStreamSize> getSubStreamSize;
+ {
+ inStream->QueryInterface(IID_ICompressGetSubStreamSize, (void **)&getSubStreamSize);
+ }
+
+ UInt32 nowPos = 0;
+ UInt64 nowPos64 = 0;
+ UInt32 bufferPos = 0;
+
+ Byte prevByte = 0;
+
+ UInt64 subStreamIndex = 0;
+ UInt64 subStreamStartPos = 0;
+ UInt64 subStreamEndPos = 0;
+
+ while(true)
+ {
+ UInt32 processedSize = 0;
+ while(true)
+ {
+ UInt32 size = kBufferSize - (bufferPos + processedSize);
+ UInt32 processedSizeLoc;
+ if (size == 0)
+ break;
+ RINOK(inStream->Read(_buffer + bufferPos + processedSize, size, &processedSizeLoc));
+ if (processedSizeLoc == 0)
+ break;
+ processedSize += processedSizeLoc;
+ }
+ UInt32 endPos = bufferPos + processedSize;
+
+ if (endPos < 5)
+ {
+ // change it
+ for (bufferPos = 0; bufferPos < endPos; bufferPos++)
+ {
+ Byte b = _buffer[bufferPos];
+ _mainStream.WriteByte(b);
+ if (b == 0xE8)
+ _statusE8Encoder[prevByte].Encode(&_rangeEncoder, 0);
+ else if (b == 0xE9)
+ _statusE9Encoder.Encode(&_rangeEncoder, 0);
+ else if (IsJcc(prevByte, b))
+ _statusJccEncoder.Encode(&_rangeEncoder, 0);
+ prevByte = b;
+ }
+ return Flush();
+ }
+
+ bufferPos = 0;
+
+ UInt32 limit = endPos - 5;
+ while(bufferPos <= limit)
+ {
+ Byte b = _buffer[bufferPos];
+ _mainStream.WriteByte(b);
+ if (b != 0xE8 && b != 0xE9 && !IsJcc(prevByte, b))
+ {
+ bufferPos++;
+ prevByte = b;
+ continue;
+ }
+ Byte nextByte = _buffer[bufferPos + 4];
+ UInt32 src =
+ (UInt32(nextByte) << 24) |
+ (UInt32(_buffer[bufferPos + 3]) << 16) |
+ (UInt32(_buffer[bufferPos + 2]) << 8) |
+ (_buffer[bufferPos + 1]);
+ UInt32 dest = (nowPos + bufferPos + 5) + src;
+ // if (Test86MSByte(nextByte))
+ bool convert;
+ if (getSubStreamSize != NULL)
+ {
+ UInt64 currentPos = (nowPos64 + bufferPos);
+ while (subStreamEndPos < currentPos)
+ {
+ UInt64 subStreamSize;
+ HRESULT result = getSubStreamSize->GetSubStreamSize(subStreamIndex, &subStreamSize);
+ if (result == S_OK)
+ {
+ subStreamStartPos = subStreamEndPos;
+ subStreamEndPos += subStreamSize;
+ subStreamIndex++;
+ }
+ else if (result == S_FALSE || result == E_NOTIMPL)
+ {
+ getSubStreamSize.Release();
+ subStreamStartPos = 0;
+ subStreamEndPos = subStreamStartPos - 1;
+ }
+ else
+ return result;
+ }
+ if (getSubStreamSize == NULL)
+ {
+ if (sizeIsDefined)
+ convert = (dest < inSize);
+ else
+ convert = Test86MSByte(nextByte);
+ }
+ else if (subStreamEndPos - subStreamStartPos > kDefaultLimit)
+ convert = Test86MSByte(nextByte);
+ else
+ {
+ UInt64 dest64 = (currentPos + 5) + Int64(Int32(src));
+ convert = (dest64 >= subStreamStartPos && dest64 < subStreamEndPos);
+ }
+ }
+ else if (sizeIsDefined)
+ convert = (dest < inSize);
+ else
+ convert = Test86MSByte(nextByte);
+ if (convert)
+ {
+ if (b == 0xE8)
+ _statusE8Encoder[prevByte].Encode(&_rangeEncoder, 1);
+ else if (b == 0xE9)
+ _statusE9Encoder.Encode(&_rangeEncoder, 1);
+ else
+ _statusJccEncoder.Encode(&_rangeEncoder, 1);
+
+ bufferPos += 5;
+ if (b == 0xE8)
+ {
+ _callStream.WriteByte((Byte)(dest >> 24));
+ _callStream.WriteByte((Byte)(dest >> 16));
+ _callStream.WriteByte((Byte)(dest >> 8));
+ _callStream.WriteByte((Byte)(dest));
+ }
+ else
+ {
+ _jumpStream.WriteByte((Byte)(dest >> 24));
+ _jumpStream.WriteByte((Byte)(dest >> 16));
+ _jumpStream.WriteByte((Byte)(dest >> 8));
+ _jumpStream.WriteByte((Byte)(dest));
+ }
+ prevByte = nextByte;
+ }
+ else
+ {
+ if (b == 0xE8)
+ _statusE8Encoder[prevByte].Encode(&_rangeEncoder, 0);
+ else if (b == 0xE9)
+ _statusE9Encoder.Encode(&_rangeEncoder, 0);
+ else
+ _statusJccEncoder.Encode(&_rangeEncoder, 0);
+ bufferPos++;
+ prevByte = b;
+ }
+ }
+ nowPos += bufferPos;
+ nowPos64 += bufferPos;
+
+ if (progress != NULL)
+ {
+ RINOK(progress->SetRatioInfo(&nowPos64, NULL));
+ }
+
+ UInt32 i = 0;
+ while(bufferPos < endPos)
+ _buffer[i++] = _buffer[bufferPos++];
+ bufferPos = i;
+ }
+}
+
+STDMETHODIMP CBCJ2_x86_Encoder::Code(ISequentialInStream **inStreams,
+ const UInt64 **inSizes,
+ UInt32 numInStreams,
+ ISequentialOutStream **outStreams,
+ const UInt64 **outSizes,
+ UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ try
+ {
+ return CodeReal(inStreams, inSizes, numInStreams,
+ outStreams, outSizes,numOutStreams, progress);
+ }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+#endif
+
+HRESULT CBCJ2_x86_Decoder::CodeReal(ISequentialInStream **inStreams,
+ const UInt64 **inSizes,
+ UInt32 numInStreams,
+ ISequentialOutStream **outStreams,
+ const UInt64 **outSizes,
+ UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ if (numInStreams != 4 || numOutStreams != 1)
+ return E_INVALIDARG;
+
+ if (!_mainInStream.Create(1 << 16))
+ return E_OUTOFMEMORY;
+ if (!_callStream.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ if (!_jumpStream.Create(1 << 16))
+ return E_OUTOFMEMORY;
+ if (!_rangeDecoder.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ if (!_outStream.Create(1 << 16))
+ return E_OUTOFMEMORY;
+
+ _mainInStream.SetStream(inStreams[0]);
+ _callStream.SetStream(inStreams[1]);
+ _jumpStream.SetStream(inStreams[2]);
+ _rangeDecoder.SetStream(inStreams[3]);
+ _outStream.SetStream(outStreams[0]);
+
+ _mainInStream.Init();
+ _callStream.Init();
+ _jumpStream.Init();
+ _rangeDecoder.Init();
+ _outStream.Init();
+
+ for (int i = 0; i < 256; i++)
+ _statusE8Decoder[i].Init();
+ _statusE9Decoder.Init();
+ _statusJccDecoder.Init();
+
+ CCoderReleaser releaser(this);
+
+ Byte prevByte = 0;
+ UInt32 processedBytes = 0;
+ while(true)
+ {
+ if (processedBytes > (1 << 20) && progress != NULL)
+ {
+ UInt64 nowPos64 = _outStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(NULL, &nowPos64));
+ processedBytes = 0;
+ }
+ processedBytes++;
+ Byte b;
+ if (!_mainInStream.ReadByte(b))
+ return Flush();
+ _outStream.WriteByte(b);
+ if (b != 0xE8 && b != 0xE9 && !IsJcc(prevByte, b))
+ {
+ prevByte = b;
+ continue;
+ }
+ bool status;
+ if (b == 0xE8)
+ status = (_statusE8Decoder[prevByte].Decode(&_rangeDecoder) == 1);
+ else if (b == 0xE9)
+ status = (_statusE9Decoder.Decode(&_rangeDecoder) == 1);
+ else
+ status = (_statusJccDecoder.Decode(&_rangeDecoder) == 1);
+ if (status)
+ {
+ UInt32 src;
+ if (b == 0xE8)
+ {
+ Byte b0;
+ if(!_callStream.ReadByte(b0))
+ return S_FALSE;
+ src = ((UInt32)b0) << 24;
+ if(!_callStream.ReadByte(b0))
+ return S_FALSE;
+ src |= ((UInt32)b0) << 16;
+ if(!_callStream.ReadByte(b0))
+ return S_FALSE;
+ src |= ((UInt32)b0) << 8;
+ if(!_callStream.ReadByte(b0))
+ return S_FALSE;
+ src |= ((UInt32)b0);
+ }
+ else
+ {
+ Byte b0;
+ if(!_jumpStream.ReadByte(b0))
+ return S_FALSE;
+ src = ((UInt32)b0) << 24;
+ if(!_jumpStream.ReadByte(b0))
+ return S_FALSE;
+ src |= ((UInt32)b0) << 16;
+ if(!_jumpStream.ReadByte(b0))
+ return S_FALSE;
+ src |= ((UInt32)b0) << 8;
+ if(!_jumpStream.ReadByte(b0))
+ return S_FALSE;
+ src |= ((UInt32)b0);
+ }
+ UInt32 dest = src - (UInt32(_outStream.GetProcessedSize()) + 4) ;
+ _outStream.WriteByte((Byte)(dest));
+ _outStream.WriteByte((Byte)(dest >> 8));
+ _outStream.WriteByte((Byte)(dest >> 16));
+ _outStream.WriteByte((Byte)(dest >> 24));
+ prevByte = (dest >> 24);
+ processedBytes += 4;
+ }
+ else
+ prevByte = b;
+ }
+}
+
+STDMETHODIMP CBCJ2_x86_Decoder::Code(ISequentialInStream **inStreams,
+ const UInt64 **inSizes,
+ UInt32 numInStreams,
+ ISequentialOutStream **outStreams,
+ const UInt64 **outSizes,
+ UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ try
+ {
+ return CodeReal(inStreams, inSizes, numInStreams,
+ outStreams, outSizes,numOutStreams, progress);
+ }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/x86_2.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/x86_2.h new file mode 100644 index 00000000..9e7780c8 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/Branch/x86_2.h @@ -0,0 +1,133 @@ +// x86_2.h
+
+#ifndef __BRANCH_X86_2_H
+#define __BRANCH_X86_2_H
+
+#include "../../../Common/MyCom.h"
+#include "../RangeCoder/RangeCoderBit.h"
+#include "../../ICoder.h"
+
+// {23170F69-40C1-278B-0303-010100000100}
+#define MyClass2_a(Name, id, subId, encodingId) \
+DEFINE_GUID(CLSID_CCompressConvert ## Name, \
+0x23170F69, 0x40C1, 0x278B, 0x03, 0x03, id, subId, 0x00, 0x00, encodingId, 0x00);
+
+#define MyClass_a(Name, id, subId) \
+MyClass2_a(Name ## _Encoder, id, subId, 0x01) \
+MyClass2_a(Name ## _Decoder, id, subId, 0x00)
+
+MyClass_a(BCJ2_x86, 0x01, 0x1B)
+
+const int kNumMoveBits = 5;
+
+#ifndef EXTRACT_ONLY
+
+class CBCJ2_x86_Encoder:
+ public ICompressCoder2,
+ public CMyUnknownImp
+{
+ Byte *_buffer;
+public:
+ CBCJ2_x86_Encoder(): _buffer(0) {};
+ ~CBCJ2_x86_Encoder();
+ bool Create();
+
+ COutBuffer _mainStream;
+ COutBuffer _callStream;
+ COutBuffer _jumpStream;
+ NCompress::NRangeCoder::CEncoder _rangeEncoder;
+ NCompress::NRangeCoder::CBitEncoder<kNumMoveBits> _statusE8Encoder[256];
+ NCompress::NRangeCoder::CBitEncoder<kNumMoveBits> _statusE9Encoder;
+ NCompress::NRangeCoder::CBitEncoder<kNumMoveBits> _statusJccEncoder;
+
+ HRESULT Flush();
+ void ReleaseStreams()
+ {
+ _mainStream.ReleaseStream();
+ _callStream.ReleaseStream();
+ _jumpStream.ReleaseStream();
+ _rangeEncoder.ReleaseStream();
+ }
+
+ class CCoderReleaser
+ {
+ CBCJ2_x86_Encoder *_coder;
+ public:
+ CCoderReleaser(CBCJ2_x86_Encoder *coder): _coder(coder) {}
+ ~CCoderReleaser() { _coder->ReleaseStreams(); }
+ };
+
+public:
+
+ MY_UNKNOWN_IMP
+
+ HRESULT CodeReal(ISequentialInStream **inStreams,
+ const UInt64 **inSizes,
+ UInt32 numInStreams,
+ ISequentialOutStream **outStreams,
+ const UInt64 **outSizes,
+ UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+ STDMETHOD(Code)(ISequentialInStream **inStreams,
+ const UInt64 **inSizes,
+ UInt32 numInStreams,
+ ISequentialOutStream **outStreams,
+ const UInt64 **outSizes,
+ UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+};
+
+#endif
+
+class CBCJ2_x86_Decoder:
+ public ICompressCoder2,
+ public CMyUnknownImp
+{
+public:
+ CInBuffer _mainInStream;
+ CInBuffer _callStream;
+ CInBuffer _jumpStream;
+ NCompress::NRangeCoder::CDecoder _rangeDecoder;
+ NCompress::NRangeCoder::CBitDecoder<kNumMoveBits> _statusE8Decoder[256];
+ NCompress::NRangeCoder::CBitDecoder<kNumMoveBits> _statusE9Decoder;
+ NCompress::NRangeCoder::CBitDecoder<kNumMoveBits> _statusJccDecoder;
+
+ COutBuffer _outStream;
+
+ void ReleaseStreams()
+ {
+ _mainInStream.ReleaseStream();
+ _callStream.ReleaseStream();
+ _jumpStream.ReleaseStream();
+ _rangeDecoder.ReleaseStream();
+ _outStream.ReleaseStream();
+ }
+
+ HRESULT Flush() { return _outStream.Flush(); }
+ class CCoderReleaser
+ {
+ CBCJ2_x86_Decoder *_coder;
+ public:
+ CCoderReleaser(CBCJ2_x86_Decoder *coder): _coder(coder) {}
+ ~CCoderReleaser() { _coder->ReleaseStreams(); }
+ };
+
+public:
+ MY_UNKNOWN_IMP
+ HRESULT CodeReal(ISequentialInStream **inStreams,
+ const UInt64 **inSizes,
+ UInt32 numInStreams,
+ ISequentialOutStream **outStreams,
+ const UInt64 **outSizes,
+ UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+ STDMETHOD(Code)(ISequentialInStream **inStreams,
+ const UInt64 **inSizes,
+ UInt32 numInStreams,
+ ISequentialOutStream **outStreams,
+ const UInt64 **outSizes,
+ UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+};
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/BinTree/BinTree.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/BinTree/BinTree.h new file mode 100644 index 00000000..19a1de0e --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/BinTree/BinTree.h @@ -0,0 +1,55 @@ +// BinTree.h
+
+#include "../LZInWindow.h"
+#include "../IMatchFinder.h"
+
+namespace BT_NAMESPACE {
+
+typedef UInt32 CIndex;
+const UInt32 kMaxValForNormalize = (UInt32(1) << 31) - 1;
+
+class CMatchFinderBinTree:
+ public IMatchFinder,
+ public IMatchFinderSetCallback,
+ public CLZInWindow,
+ public CMyUnknownImp
+{
+ UInt32 _cyclicBufferPos;
+ UInt32 _cyclicBufferSize; // it must be historySize + 1
+ UInt32 _matchMaxLen;
+ CIndex *_hash;
+ UInt32 _cutValue;
+
+ CMyComPtr<IMatchFinderCallback> m_Callback;
+
+ void Normalize();
+ void FreeThisClassMemory();
+ void FreeMemory();
+
+ MY_UNKNOWN_IMP1(IMatchFinderSetCallback)
+
+ STDMETHOD(Init)(ISequentialInStream *inStream);
+ STDMETHOD_(void, ReleaseStream)();
+ STDMETHOD(MovePos)();
+ STDMETHOD_(Byte, GetIndexByte)(Int32 index);
+ STDMETHOD_(UInt32, GetMatchLen)(Int32 index, UInt32 back, UInt32 limit);
+ STDMETHOD_(UInt32, GetNumAvailableBytes)();
+ STDMETHOD_(const Byte *, GetPointerToCurrentPos)();
+ STDMETHOD(Create)(UInt32 historySize, UInt32 keepAddBufferBefore,
+ UInt32 matchMaxLen, UInt32 keepAddBufferAfter);
+ STDMETHOD_(UInt32, GetLongestMatch)(UInt32 *distances);
+ STDMETHOD_(void, DummyLongestMatch)();
+
+ // IMatchFinderSetCallback
+ STDMETHOD(SetCallback)(IMatchFinderCallback *callback);
+
+ virtual void BeforeMoveBlock();
+ virtual void AfterMoveBlock();
+
+public:
+ CMatchFinderBinTree();
+ virtual ~CMatchFinderBinTree();
+ void SetCutValue(UInt32 cutValue) { _cutValue = cutValue; }
+};
+
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/BinTree/BinTree2.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/BinTree/BinTree2.h new file mode 100644 index 00000000..9dbe35d6 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/BinTree/BinTree2.h @@ -0,0 +1,12 @@ +// BinTree2.h
+
+#ifndef __BINTREE2_H
+#define __BINTREE2_H
+
+#undef BT_NAMESPACE
+#define BT_NAMESPACE NBT2
+
+#include "BinTree.h"
+#include "BinTreeMain.h"
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/BinTree/BinTree3.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/BinTree/BinTree3.h new file mode 100644 index 00000000..9a68669f --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/BinTree/BinTree3.h @@ -0,0 +1,16 @@ +// BinTree3.h
+
+#ifndef __BINTREE3_H
+#define __BINTREE3_H
+
+#undef BT_NAMESPACE
+#define BT_NAMESPACE NBT3
+
+#define HASH_ARRAY_2
+
+#include "BinTree.h"
+#include "BinTreeMain.h"
+
+#undef HASH_ARRAY_2
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/BinTree/BinTree3Z.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/BinTree/BinTree3Z.h new file mode 100644 index 00000000..b77de3d9 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/BinTree/BinTree3Z.h @@ -0,0 +1,16 @@ +// BinTree3Z.h
+
+#ifndef __BINTREE3Z_H
+#define __BINTREE3Z_H
+
+#undef BT_NAMESPACE
+#define BT_NAMESPACE NBT3Z
+
+#define HASH_ZIP
+
+#include "BinTree.h"
+#include "BinTreeMain.h"
+
+#undef HASH_ZIP
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/BinTree/BinTree4.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/BinTree/BinTree4.h new file mode 100644 index 00000000..bdc4a87b --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/BinTree/BinTree4.h @@ -0,0 +1,18 @@ +// BinTree4.h
+
+#ifndef __BINTREE4_H
+#define __BINTREE4_H
+
+#undef BT_NAMESPACE
+#define BT_NAMESPACE NBT4
+
+#define HASH_ARRAY_2
+#define HASH_ARRAY_3
+
+#include "BinTree.h"
+#include "BinTreeMain.h"
+
+#undef HASH_ARRAY_2
+#undef HASH_ARRAY_3
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/BinTree/BinTree4b.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/BinTree/BinTree4b.h new file mode 100644 index 00000000..06f56662 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/BinTree/BinTree4b.h @@ -0,0 +1,20 @@ +// BinTree4b.h
+
+#ifndef __BINTREE4B_H
+#define __BINTREE4B_H
+
+#undef BT_NAMESPACE
+#define BT_NAMESPACE NBT4B
+
+#define HASH_ARRAY_2
+#define HASH_ARRAY_3
+#define HASH_BIG
+
+#include "BinTree.h"
+#include "BinTreeMain.h"
+
+#undef HASH_ARRAY_2
+#undef HASH_ARRAY_3
+#undef HASH_BIG
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/BinTree/BinTreeMain.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/BinTree/BinTreeMain.h new file mode 100644 index 00000000..452466a7 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/BinTree/BinTreeMain.h @@ -0,0 +1,444 @@ +// BinTreeMain.h
+
+#include "../../../../Common/Defs.h"
+#include "../../../../Common/CRC.h"
+#include "../../../../Common/Alloc.h"
+
+namespace BT_NAMESPACE {
+
+#ifdef HASH_ARRAY_2
+ static const UInt32 kHash2Size = 1 << 10;
+ #ifdef HASH_ARRAY_3
+ static const UInt32 kNumHashDirectBytes = 0;
+ static const UInt32 kNumHashBytes = 4;
+ static const UInt32 kHash3Size = 1 << 18;
+ #ifdef HASH_BIG
+ static const UInt32 kHashSize = 1 << 23;
+ #else
+ static const UInt32 kHashSize = 1 << 20;
+ #endif
+ #else
+ static const UInt32 kNumHashDirectBytes = 3;
+ static const UInt32 kNumHashBytes = 3;
+ static const UInt32 kHashSize = 1 << (8 * kNumHashBytes);
+ #endif
+#else
+ #ifdef HASH_ZIP
+ static const UInt32 kNumHashDirectBytes = 0;
+ static const UInt32 kNumHashBytes = 3;
+ static const UInt32 kHashSize = 1 << 16;
+ #else
+ #define THERE_ARE_DIRECT_HASH_BYTES
+ static const UInt32 kNumHashDirectBytes = 2;
+ static const UInt32 kNumHashBytes = 2;
+ static const UInt32 kHashSize = 1 << (8 * kNumHashBytes);
+ #endif
+#endif
+
+static const UInt32 kHashSizeSum = kHashSize
+ #ifdef HASH_ARRAY_2
+ + kHash2Size
+ #ifdef HASH_ARRAY_3
+ + kHash3Size
+ #endif
+ #endif
+ ;
+
+#ifdef HASH_ARRAY_2
+static const UInt32 kHash2Offset = kHashSize;
+#ifdef HASH_ARRAY_3
+static const UInt32 kHash3Offset = kHashSize + kHash2Size;
+#endif
+#endif
+
+CMatchFinderBinTree::CMatchFinderBinTree():
+ _hash(0),
+ _cutValue(0xFF)
+{
+}
+
+void CMatchFinderBinTree::FreeThisClassMemory()
+{
+ BigFree(_hash);
+ _hash = 0;
+}
+
+void CMatchFinderBinTree::FreeMemory()
+{
+ FreeThisClassMemory();
+ CLZInWindow::Free();
+}
+
+CMatchFinderBinTree::~CMatchFinderBinTree()
+{
+ FreeMemory();
+}
+
+STDMETHODIMP CMatchFinderBinTree::Create(UInt32 historySize, UInt32 keepAddBufferBefore,
+ UInt32 matchMaxLen, UInt32 keepAddBufferAfter)
+{
+ UInt32 sizeReserv = (historySize + keepAddBufferBefore +
+ matchMaxLen + keepAddBufferAfter) / 2 + 256;
+ if (CLZInWindow::Create(historySize + keepAddBufferBefore,
+ matchMaxLen + keepAddBufferAfter, sizeReserv))
+ {
+ if (historySize + 256 > kMaxValForNormalize)
+ {
+ FreeMemory();
+ return E_INVALIDARG;
+ }
+ _matchMaxLen = matchMaxLen;
+ UInt32 newCyclicBufferSize = historySize + 1;
+ if (_hash != 0 && newCyclicBufferSize == _cyclicBufferSize)
+ return S_OK;
+ FreeThisClassMemory();
+ _cyclicBufferSize = newCyclicBufferSize; // don't change it
+ _hash = (CIndex *)BigAlloc((kHashSizeSum + _cyclicBufferSize * 2) * sizeof(CIndex));
+ if (_hash != 0)
+ return S_OK;
+ }
+ FreeMemory();
+ return E_OUTOFMEMORY;
+}
+
+static const UInt32 kEmptyHashValue = 0;
+
+STDMETHODIMP CMatchFinderBinTree::Init(ISequentialInStream *stream)
+{
+ RINOK(CLZInWindow::Init(stream));
+ for(UInt32 i = 0; i < kHashSizeSum; i++)
+ _hash[i] = kEmptyHashValue;
+ _cyclicBufferPos = 0;
+ ReduceOffsets(-1);
+ return S_OK;
+}
+
+STDMETHODIMP_(void) CMatchFinderBinTree::ReleaseStream()
+{
+ // ReleaseStream();
+}
+
+#ifdef HASH_ARRAY_2
+#ifdef HASH_ARRAY_3
+inline UInt32 Hash(const Byte *pointer, UInt32 &hash2Value, UInt32 &hash3Value)
+{
+ UInt32 temp = CCRC::Table[pointer[0]] ^ pointer[1];
+ hash2Value = temp & (kHash2Size - 1);
+ hash3Value = (temp ^ (UInt32(pointer[2]) << 8)) & (kHash3Size - 1);
+ return (temp ^ (UInt32(pointer[2]) << 8) ^ (CCRC::Table[pointer[3]] << 5)) &
+ (kHashSize - 1);
+}
+#else // no HASH_ARRAY_3
+inline UInt32 Hash(const Byte *pointer, UInt32 &hash2Value)
+{
+ hash2Value = (CCRC::Table[pointer[0]] ^ pointer[1]) & (kHash2Size - 1);
+ return ((UInt32(pointer[0]) << 16)) | ((UInt32(pointer[1]) << 8)) | pointer[2];
+}
+#endif // HASH_ARRAY_3
+#else // no HASH_ARRAY_2
+#ifdef HASH_ZIP
+inline UInt32 Hash(const Byte *pointer)
+{
+ return ((UInt32(pointer[0]) << 8) ^
+ CCRC::Table[pointer[1]] ^ pointer[2]) & (kHashSize - 1);
+}
+#else // no HASH_ZIP
+inline UInt32 Hash(const Byte *pointer)
+{
+ return pointer[0] ^ (UInt32(pointer[1]) << 8);
+}
+#endif // HASH_ZIP
+#endif // HASH_ARRAY_2
+
+STDMETHODIMP_(UInt32) CMatchFinderBinTree::GetLongestMatch(UInt32 *distances)
+{
+ UInt32 lenLimit;
+ if (_pos + _matchMaxLen <= _streamPos)
+ lenLimit = _matchMaxLen;
+ else
+ {
+ lenLimit = _streamPos - _pos;
+ if(lenLimit < kNumHashBytes)
+ return 0;
+ }
+
+ UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
+ Byte *cur = _buffer + _pos;
+
+ UInt32 maxLen = 0;
+
+ #ifdef HASH_ARRAY_2
+ UInt32 hash2Value;
+ #ifdef HASH_ARRAY_3
+ UInt32 hash3Value;
+ UInt32 hashValue = Hash(cur, hash2Value, hash3Value);
+ #else
+ UInt32 hashValue = Hash(cur, hash2Value);
+ #endif
+ #else
+ UInt32 hashValue = Hash(cur);
+ #endif
+
+ UInt32 curMatch = _hash[hashValue];
+ #ifdef HASH_ARRAY_2
+ UInt32 curMatch2 = _hash[kHash2Offset + hash2Value];
+ #ifdef HASH_ARRAY_3
+ UInt32 curMatch3 = _hash[kHash3Offset + hash3Value];
+ #endif
+ _hash[kHash2Offset + hash2Value] = _pos;
+ distances[2] = 0xFFFFFFFF;
+ if(curMatch2 > matchMinPos)
+ if (_buffer[curMatch2] == cur[0])
+ {
+ distances[2] = _pos - curMatch2 - 1;
+ maxLen = 2;
+ }
+
+ #ifdef HASH_ARRAY_3
+ _hash[kHash3Offset + hash3Value] = _pos;
+ distances[3] = 0xFFFFFFFF;
+ if(curMatch3 > matchMinPos)
+ if (_buffer[curMatch3] == cur[0])
+ {
+ distances[3] = _pos - curMatch3 - 1;
+ maxLen = 3;
+ }
+ #endif
+ #endif
+
+ _hash[hashValue] = _pos;
+
+ CIndex *son = _hash + kHashSizeSum;
+ CIndex *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+ CIndex *ptr1 = son + (_cyclicBufferPos << 1);
+
+ distances[kNumHashBytes] = 0xFFFFFFFF;
+
+ #ifdef THERE_ARE_DIRECT_HASH_BYTES
+ if (lenLimit == kNumHashDirectBytes)
+ {
+ if(curMatch > matchMinPos)
+ while (maxLen < kNumHashDirectBytes)
+ distances[++maxLen] = _pos - curMatch - 1;
+ // We don't need tree in this case
+ }
+ else
+ #endif
+ {
+ UInt32 len0, len1;
+ len0 = len1 = kNumHashDirectBytes;
+ UInt32 count = _cutValue;
+ while(true)
+ {
+ if(curMatch <= matchMinPos || count-- == 0)
+ {
+ *ptr0 = kEmptyHashValue;
+ *ptr1 = kEmptyHashValue;
+ break;
+ }
+ Byte *pb = _buffer + curMatch;
+ UInt32 len = MyMin(len0, len1);
+ do
+ {
+ if (pb[len] != cur[len])
+ break;
+ }
+ while(++len != lenLimit);
+
+ UInt32 delta = _pos - curMatch;
+ while (maxLen < len)
+ distances[++maxLen] = delta - 1;
+
+ UInt32 cyclicPos = (delta <= _cyclicBufferPos) ?
+ (_cyclicBufferPos - delta):
+ (_cyclicBufferPos - delta + _cyclicBufferSize);
+ CIndex *pair = son + (cyclicPos << 1);
+
+ if (len != lenLimit)
+ {
+ if (pb[len] < cur[len])
+ {
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ curMatch = *ptr1;
+ len1 = len;
+ }
+ else
+ {
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ curMatch = *ptr0;
+ len0 = len;
+ }
+ }
+ else
+ {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ break;
+ }
+ }
+ }
+ #ifdef HASH_ARRAY_2
+ #ifdef HASH_ARRAY_3
+ if (distances[4] < distances[3])
+ distances[3] = distances[4];
+ #endif
+ if (distances[3] < distances[2])
+ distances[2] = distances[3];
+ #endif
+ return maxLen;
+}
+
+STDMETHODIMP_(void) CMatchFinderBinTree::DummyLongestMatch()
+{
+ UInt32 lenLimit;
+ if (_pos + _matchMaxLen <= _streamPos)
+ lenLimit = _matchMaxLen;
+ else
+ {
+ lenLimit = _streamPos - _pos;
+ if(lenLimit < kNumHashBytes)
+ return;
+ }
+ UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
+ Byte *cur = _buffer + _pos;
+
+ #ifdef HASH_ARRAY_2
+ UInt32 hash2Value;
+ #ifdef HASH_ARRAY_3
+ UInt32 hash3Value;
+ UInt32 hashValue = Hash(cur, hash2Value, hash3Value);
+ _hash[kHash3Offset + hash3Value] = _pos;
+ #else
+ UInt32 hashValue = Hash(cur, hash2Value);
+ #endif
+ _hash[kHash2Offset + hash2Value] = _pos;
+ #else
+ UInt32 hashValue = Hash(cur);
+ #endif
+
+ UInt32 curMatch = _hash[hashValue];
+ _hash[hashValue] = _pos;
+
+ CIndex *son = _hash + kHashSizeSum;
+ CIndex *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+ CIndex *ptr1 = son + (_cyclicBufferPos << 1);
+
+ #ifdef THERE_ARE_DIRECT_HASH_BYTES
+ if (lenLimit != kNumHashDirectBytes)
+ #endif
+ {
+ UInt32 len0, len1;
+ len0 = len1 = kNumHashDirectBytes;
+ UInt32 count = _cutValue;
+ while(true)
+ {
+ if(curMatch <= matchMinPos || count-- == 0)
+ break;
+ Byte *pb = _buffer + curMatch;
+ UInt32 len = MyMin(len0, len1);
+ do
+ {
+ if (pb[len] != cur[len])
+ break;
+ }
+ while(++len != lenLimit);
+
+ UInt32 delta = _pos - curMatch;
+ UInt32 cyclicPos = (delta <= _cyclicBufferPos) ?
+ (_cyclicBufferPos - delta):
+ (_cyclicBufferPos - delta + _cyclicBufferSize);
+ CIndex *pair = son + (cyclicPos << 1);
+
+ if (len != lenLimit)
+ {
+ if (pb[len] < cur[len])
+ {
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ curMatch = *ptr1;
+ len1 = len;
+ }
+ else
+ {
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ curMatch = *ptr0;
+ len0 = len;
+ }
+ }
+ else
+ {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ return;
+ }
+ }
+ }
+ *ptr0 = kEmptyHashValue;
+ *ptr1 = kEmptyHashValue;
+}
+
+void CMatchFinderBinTree::Normalize()
+{
+ UInt32 subValue = _pos - _cyclicBufferSize;
+ CIndex *items = _hash;
+ UInt32 numItems = (kHashSizeSum + _cyclicBufferSize * 2);
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ UInt32 value = items[i];
+ if (value <= subValue)
+ value = kEmptyHashValue;
+ else
+ value -= subValue;
+ items[i] = value;
+ }
+ ReduceOffsets(subValue);
+}
+
+STDMETHODIMP CMatchFinderBinTree::MovePos()
+{
+ if (++_cyclicBufferPos == _cyclicBufferSize)
+ _cyclicBufferPos = 0;
+ RINOK(CLZInWindow::MovePos());
+ if (_pos == kMaxValForNormalize)
+ Normalize();
+ return S_OK;
+}
+
+STDMETHODIMP_(Byte) CMatchFinderBinTree::GetIndexByte(Int32 index)
+ { return CLZInWindow::GetIndexByte(index); }
+
+STDMETHODIMP_(UInt32) CMatchFinderBinTree::GetMatchLen(Int32 index,
+ UInt32 back, UInt32 limit)
+ { return CLZInWindow::GetMatchLen(index, back, limit); }
+
+STDMETHODIMP_(UInt32) CMatchFinderBinTree::GetNumAvailableBytes()
+ { return CLZInWindow::GetNumAvailableBytes(); }
+
+STDMETHODIMP_(const Byte *) CMatchFinderBinTree::GetPointerToCurrentPos()
+ { return CLZInWindow::GetPointerToCurrentPos(); }
+
+// IMatchFinderSetCallback
+STDMETHODIMP CMatchFinderBinTree::SetCallback(IMatchFinderCallback *callback)
+{
+ m_Callback = callback;
+ return S_OK;
+}
+
+void CMatchFinderBinTree::BeforeMoveBlock()
+{
+ if (m_Callback)
+ m_Callback->BeforeChangingBufferPos();
+ CLZInWindow::BeforeMoveBlock();
+}
+
+void CMatchFinderBinTree::AfterMoveBlock()
+{
+ if (m_Callback)
+ m_Callback->AfterChangingBufferPos();
+ CLZInWindow::AfterMoveBlock();
+}
+
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/HashChain/HC.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/HashChain/HC.h new file mode 100644 index 00000000..53f3e217 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/HashChain/HC.h @@ -0,0 +1,55 @@ +// HC.h
+
+#include "../LZInWindow.h"
+#include "../IMatchFinder.h"
+
+namespace HC_NAMESPACE {
+
+typedef UInt32 CIndex;
+const UInt32 kMaxValForNormalize = (UInt32(1) << 31) - 1;
+
+class CMatchFinderHC:
+ public IMatchFinder,
+ public IMatchFinderSetCallback,
+ public CLZInWindow,
+ public CMyUnknownImp
+{
+ UInt32 _cyclicBufferPos;
+ UInt32 _cyclicBufferSize; // it must be historySize + 1
+ UInt32 _matchMaxLen;
+ CIndex *_hash;
+ UInt32 _cutValue;
+
+ CMyComPtr<IMatchFinderCallback> m_Callback;
+
+ void Normalize();
+ void FreeThisClassMemory();
+ void FreeMemory();
+
+ MY_UNKNOWN_IMP1(IMatchFinderSetCallback)
+
+ STDMETHOD(Init)(ISequentialInStream *inStream);
+ STDMETHOD_(void, ReleaseStream)();
+ STDMETHOD(MovePos)();
+ STDMETHOD_(Byte, GetIndexByte)(Int32 index);
+ STDMETHOD_(UInt32, GetMatchLen)(Int32 index, UInt32 back, UInt32 limit);
+ STDMETHOD_(UInt32, GetNumAvailableBytes)();
+ STDMETHOD_(const Byte *, GetPointerToCurrentPos)();
+ STDMETHOD(Create)(UInt32 historySize, UInt32 keepAddBufferBefore,
+ UInt32 matchMaxLen, UInt32 keepAddBufferAfter);
+ STDMETHOD_(UInt32, GetLongestMatch)(UInt32 *distances);
+ STDMETHOD_(void, DummyLongestMatch)();
+
+ // IMatchFinderSetCallback
+ STDMETHOD(SetCallback)(IMatchFinderCallback *callback);
+
+ virtual void BeforeMoveBlock();
+ virtual void AfterMoveBlock();
+
+public:
+ CMatchFinderHC();
+ virtual ~CMatchFinderHC();
+ void SetCutValue(UInt32 cutValue) { _cutValue = cutValue; }
+};
+
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/HashChain/HC2.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/HashChain/HC2.h new file mode 100644 index 00000000..7211cc50 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/HashChain/HC2.h @@ -0,0 +1,13 @@ +// HC2.h
+
+#ifndef __HC2_H
+#define __HC2_H
+
+#undef HC_NAMESPACE
+#define HC_NAMESPACE NHC2
+
+#include "HCMF.h"
+#include "HCMFMain.h"
+
+#endif
+
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/HashChain/HC3.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/HashChain/HC3.h new file mode 100644 index 00000000..38f05d23 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/HashChain/HC3.h @@ -0,0 +1,17 @@ +// HC3.h
+
+#ifndef __HC3_H
+#define __HC3_H
+
+#undef HC_NAMESPACE
+#define HC_NAMESPACE NHC3
+
+#define HASH_ARRAY_2
+
+#include "HC.h"
+#include "HCMain.h"
+
+#undef HASH_ARRAY_2
+
+#endif
+
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/HashChain/HC4.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/HashChain/HC4.h new file mode 100644 index 00000000..7d4e2117 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/HashChain/HC4.h @@ -0,0 +1,19 @@ +// HC4.h
+
+#ifndef __HC4_H
+#define __HC4_H
+
+#undef HC_NAMESPACE
+#define HC_NAMESPACE NHC4
+
+#define HASH_ARRAY_2
+#define HASH_ARRAY_3
+
+#include "HC.h"
+#include "HCMain.h"
+
+#undef HASH_ARRAY_2
+#undef HASH_ARRAY_3
+
+#endif
+
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/HashChain/HC4b.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/HashChain/HC4b.h new file mode 100644 index 00000000..229e5fdf --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/HashChain/HC4b.h @@ -0,0 +1,21 @@ +// HC4b.h
+
+#ifndef __HC4B__H
+#define __HC4B__H
+
+#undef HC_NAMESPACE
+#define HC_NAMESPACE NHC4b
+
+#define HASH_ARRAY_2
+#define HASH_ARRAY_3
+#define HASH_BIG
+
+#include "HC.h"
+#include "HCMain.h"
+
+#undef HASH_ARRAY_2
+#undef HASH_ARRAY_3
+#undef HASH_BIG
+
+#endif
+
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/HashChain/HCMain.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/HashChain/HCMain.h new file mode 100644 index 00000000..61d932cb --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/HashChain/HCMain.h @@ -0,0 +1,350 @@ +// HC.h
+
+#include "../../../../Common/Defs.h"
+#include "../../../../Common/CRC.h"
+#include "../../../../Common/Alloc.h"
+
+namespace HC_NAMESPACE {
+
+#ifdef HASH_ARRAY_2
+ static const UInt32 kHash2Size = 1 << 10;
+ #ifdef HASH_ARRAY_3
+ static const UInt32 kNumHashDirectBytes = 0;
+ static const UInt32 kNumHashBytes = 4;
+ static const UInt32 kHash3Size = 1 << 18;
+ #ifdef HASH_BIG
+ static const UInt32 kHashSize = 1 << 23;
+ #else
+ static const UInt32 kHashSize = 1 << 20;
+ #endif
+ #else
+ static const UInt32 kNumHashDirectBytes = 0;
+ static const UInt32 kNumHashBytes = 3;
+ static const UInt32 kHashSize = 1 << (16);
+ #endif
+#else
+ #ifdef HASH_ZIP
+ static const UInt32 kNumHashDirectBytes = 0;
+ static const UInt32 kNumHashBytes = 3;
+ static const UInt32 kHashSize = 1 << 16;
+ #else
+ #define THERE_ARE_DIRECT_HASH_BYTES
+ static const UInt32 kNumHashDirectBytes = 2;
+ static const UInt32 kNumHashBytes = 2;
+ static const UInt32 kHashSize = 1 << (8 * kNumHashBytes);
+ #endif
+#endif
+
+static const UInt32 kHashSizeSum = kHashSize
+ #ifdef HASH_ARRAY_2
+ + kHash2Size
+ #ifdef HASH_ARRAY_3
+ + kHash3Size
+ #endif
+ #endif
+ ;
+
+#ifdef HASH_ARRAY_2
+static const UInt32 kHash2Offset = kHashSize;
+#ifdef HASH_ARRAY_3
+static const UInt32 kHash3Offset = kHashSize + kHash2Size;
+#endif
+#endif
+
+CMatchFinderHC::CMatchFinderHC():
+ _hash(0),
+ _cutValue(16)
+{
+}
+
+void CMatchFinderHC::FreeThisClassMemory()
+{
+ BigFree(_hash);
+ _hash = 0;
+}
+
+void CMatchFinderHC::FreeMemory()
+{
+ FreeThisClassMemory();
+ CLZInWindow::Free();
+}
+
+CMatchFinderHC::~CMatchFinderHC()
+{
+ FreeMemory();
+}
+
+STDMETHODIMP CMatchFinderHC::Create(UInt32 historySize, UInt32 keepAddBufferBefore,
+ UInt32 matchMaxLen, UInt32 keepAddBufferAfter)
+{
+ UInt32 sizeReserv = (historySize + keepAddBufferBefore +
+ matchMaxLen + keepAddBufferAfter) / 2 + 256;
+ if (CLZInWindow::Create(historySize + keepAddBufferBefore,
+ matchMaxLen + keepAddBufferAfter, sizeReserv))
+ {
+ if (historySize + 256 > kMaxValForNormalize)
+ {
+ FreeMemory();
+ return E_INVALIDARG;
+ }
+ _matchMaxLen = matchMaxLen;
+ UInt32 newCyclicBufferSize = historySize + 1;
+ if (_hash != 0 && newCyclicBufferSize == _cyclicBufferSize)
+ return S_OK;
+ FreeThisClassMemory();
+ _cyclicBufferSize = newCyclicBufferSize; // don't change it
+ _hash = (CIndex *)BigAlloc((kHashSizeSum + _cyclicBufferSize) * sizeof(CIndex));
+ if (_hash != 0)
+ return S_OK;
+ }
+ FreeMemory();
+ return E_OUTOFMEMORY;
+}
+
+static const UInt32 kEmptyHashValue = 0;
+
+STDMETHODIMP CMatchFinderHC::Init(ISequentialInStream *stream)
+{
+ RINOK(CLZInWindow::Init(stream));
+ for(UInt32 i = 0; i < kHashSizeSum; i++)
+ _hash[i] = kEmptyHashValue;
+ _cyclicBufferPos = 0;
+ ReduceOffsets(-1);
+ return S_OK;
+}
+
+STDMETHODIMP_(void) CMatchFinderHC::ReleaseStream()
+{
+ // ReleaseStream();
+}
+
+#ifdef HASH_ARRAY_2
+#ifdef HASH_ARRAY_3
+inline UInt32 Hash(const Byte *pointer, UInt32 &hash2Value, UInt32 &hash3Value)
+{
+ UInt32 temp = CCRC::Table[pointer[0]] ^ pointer[1];
+ hash2Value = temp & (kHash2Size - 1);
+ hash3Value = (temp ^ (UInt32(pointer[2]) << 8)) & (kHash3Size - 1);
+ return (temp ^ (UInt32(pointer[2]) << 8) ^ (CCRC::Table[pointer[3]] << 5)) &
+ (kHashSize - 1);
+}
+#else // no HASH_ARRAY_3
+inline UInt32 Hash(const Byte *pointer, UInt32 &hash2Value)
+{
+ UInt32 temp = CCRC::Table[pointer[0]] ^ pointer[1];
+ hash2Value = temp & (kHash2Size - 1);
+ return (temp ^ (UInt32(pointer[2]) << 8)) & (kHashSize - 1);;
+}
+#endif // HASH_ARRAY_3
+#else // no HASH_ARRAY_2
+#ifdef HASH_ZIP
+inline UInt32 Hash(const Byte *pointer)
+{
+ return ((UInt32(pointer[0]) << 8) ^
+ CCRC::Table[pointer[1]] ^ pointer[2]) & (kHashSize - 1);
+}
+#else // no HASH_ZIP
+inline UInt32 Hash(const Byte *pointer)
+{
+ return pointer[0] ^ (UInt32(pointer[1]) << 8);
+}
+#endif // HASH_ZIP
+#endif // HASH_ARRAY_2
+
+
+STDMETHODIMP_(UInt32) CMatchFinderHC::GetLongestMatch(UInt32 *distances)
+{
+ UInt32 lenLimit;
+ if (_pos + _matchMaxLen <= _streamPos)
+ lenLimit = _matchMaxLen;
+ else
+ {
+ lenLimit = _streamPos - _pos;
+ if(lenLimit < kNumHashBytes)
+ return 0;
+ }
+
+ UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
+ Byte *cur = _buffer + _pos;
+
+ UInt32 maxLen = 0;
+
+ #ifdef HASH_ARRAY_2
+ UInt32 hash2Value;
+ #ifdef HASH_ARRAY_3
+ UInt32 hash3Value;
+ UInt32 hashValue = Hash(cur, hash2Value, hash3Value);
+ #else
+ UInt32 hashValue = Hash(cur, hash2Value);
+ #endif
+ #else
+ UInt32 hashValue = Hash(cur);
+ #endif
+ #ifdef HASH_ARRAY_2
+
+ UInt32 curMatch2 = _hash[kHash2Offset + hash2Value];
+ _hash[kHash2Offset + hash2Value] = _pos;
+ distances[2] = 0xFFFFFFFF;
+ if(curMatch2 > matchMinPos)
+ if (_buffer[curMatch2] == cur[0])
+ {
+ distances[2] = _pos - curMatch2 - 1;
+ maxLen = 2;
+ }
+
+ #ifdef HASH_ARRAY_3
+
+ UInt32 curMatch3 = _hash[kHash3Offset + hash3Value];
+ _hash[kHash3Offset + hash3Value] = _pos;
+ distances[3] = 0xFFFFFFFF;
+ if(curMatch3 > matchMinPos)
+ if (_buffer[curMatch3] == cur[0])
+ {
+ distances[3] = _pos - curMatch3 - 1;
+ maxLen = 3;
+ }
+
+ #endif
+ #endif
+
+ UInt32 curMatch = _hash[hashValue];
+ _hash[hashValue] = _pos;
+ CIndex *chain = _hash + kHashSizeSum;
+ chain[_cyclicBufferPos] = curMatch;
+ distances[kNumHashBytes] = 0xFFFFFFFF;
+ #ifdef THERE_ARE_DIRECT_HASH_BYTES
+ if (lenLimit == kNumHashDirectBytes)
+ {
+ if(curMatch > matchMinPos)
+ while (maxLen < kNumHashDirectBytes)
+ distances[++maxLen] = _pos - curMatch - 1;
+ }
+ else
+ #endif
+ {
+ UInt32 count = _cutValue;
+ do
+ {
+ if(curMatch <= matchMinPos)
+ break;
+ Byte *pby1 = _buffer + curMatch;
+ UInt32 currentLen = kNumHashDirectBytes;
+ do
+ {
+ if (pby1[currentLen] != cur[currentLen])
+ break;
+ }
+ while(++currentLen != lenLimit);
+
+ UInt32 delta = _pos - curMatch;
+ while (maxLen < currentLen)
+ distances[++maxLen] = delta - 1;
+ if(currentLen == lenLimit)
+ break;
+
+ UInt32 cyclicPos = (delta <= _cyclicBufferPos) ?
+ (_cyclicBufferPos - delta):
+ (_cyclicBufferPos - delta + _cyclicBufferSize);
+
+ curMatch = chain[cyclicPos];
+ }
+ while(--count != 0);
+ }
+ #ifdef HASH_ARRAY_2
+ #ifdef HASH_ARRAY_3
+ if (distances[4] < distances[3])
+ distances[3] = distances[4];
+ #endif
+ if (distances[3] < distances[2])
+ distances[2] = distances[3];
+ #endif
+ return maxLen;
+}
+
+STDMETHODIMP_(void) CMatchFinderHC::DummyLongestMatch()
+{
+ if (_streamPos - _pos < kNumHashBytes)
+ return;
+
+ Byte *cur = _buffer + _pos;
+
+ #ifdef HASH_ARRAY_2
+ UInt32 hash2Value;
+ #ifdef HASH_ARRAY_3
+ UInt32 hash3Value;
+ UInt32 hashValue = Hash(cur, hash2Value, hash3Value);
+ _hash[kHash3Offset + hash3Value] = _pos;
+ #else
+ UInt32 hashValue = Hash(cur, hash2Value);
+ #endif
+ _hash[kHash2Offset + hash2Value] = _pos;
+ #else
+ UInt32 hashValue = Hash(cur);
+ #endif
+
+ _hash[kHashSizeSum + _cyclicBufferPos] = _hash[hashValue];
+ _hash[hashValue] = _pos;
+}
+
+void CMatchFinderHC::Normalize()
+{
+ UInt32 subValue = _pos - _cyclicBufferSize;
+ CIndex *items = _hash;
+ UInt32 numItems = kHashSizeSum + _cyclicBufferSize;
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ UInt32 value = items[i];
+ if (value <= subValue)
+ value = kEmptyHashValue;
+ else
+ value -= subValue;
+ items[i] = value;
+ }
+ ReduceOffsets(subValue);
+}
+
+STDMETHODIMP CMatchFinderHC::MovePos()
+{
+ if (++_cyclicBufferPos == _cyclicBufferSize)
+ _cyclicBufferPos = 0;
+ RINOK(CLZInWindow::MovePos());
+ if (_pos == kMaxValForNormalize)
+ Normalize();
+ return S_OK;
+}
+
+STDMETHODIMP_(Byte) CMatchFinderHC::GetIndexByte(Int32 index)
+ { return CLZInWindow::GetIndexByte(index); }
+
+STDMETHODIMP_(UInt32) CMatchFinderHC::GetMatchLen(Int32 index,
+ UInt32 back, UInt32 limit)
+ { return CLZInWindow::GetMatchLen(index, back, limit); }
+
+STDMETHODIMP_(UInt32) CMatchFinderHC::GetNumAvailableBytes()
+ { return CLZInWindow::GetNumAvailableBytes(); }
+
+STDMETHODIMP_(const Byte *) CMatchFinderHC::GetPointerToCurrentPos()
+ { return CLZInWindow::GetPointerToCurrentPos(); }
+
+// IMatchFinderSetCallback
+STDMETHODIMP CMatchFinderHC::SetCallback(IMatchFinderCallback *callback)
+{
+ m_Callback = callback;
+ return S_OK;
+}
+
+void CMatchFinderHC::BeforeMoveBlock()
+{
+ if (m_Callback)
+ m_Callback->BeforeChangingBufferPos();
+ CLZInWindow::BeforeMoveBlock();
+}
+
+void CMatchFinderHC::AfterMoveBlock()
+{
+ if (m_Callback)
+ m_Callback->AfterChangingBufferPos();
+ CLZInWindow::AfterMoveBlock();
+}
+
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/IMatchFinder.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/IMatchFinder.h new file mode 100644 index 00000000..1d9c88f2 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/IMatchFinder.h @@ -0,0 +1,63 @@ +// MatchFinders/IMatchFinder.h
+
+#ifndef __IMATCHFINDER_H
+#define __IMATCHFINDER_H
+
+// {23170F69-40C1-278A-0000-000200010000}
+DEFINE_GUID(IID_IInWindowStream,
+0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00);
+MIDL_INTERFACE("23170F69-40C1-278A-0000-000200010000")
+IInWindowStream: public IUnknown
+{
+ STDMETHOD(Init)(ISequentialInStream *inStream) PURE;
+ STDMETHOD_(void, ReleaseStream)() PURE;
+ STDMETHOD(MovePos)() PURE;
+ STDMETHOD_(Byte, GetIndexByte)(Int32 index) PURE;
+ STDMETHOD_(UInt32, GetMatchLen)(Int32 index, UInt32 distance, UInt32 limit) PURE;
+ STDMETHOD_(UInt32, GetNumAvailableBytes)() PURE;
+ STDMETHOD_(const Byte *, GetPointerToCurrentPos)() PURE;
+};
+
+// {23170F69-40C1-278A-0000-000200020000}
+DEFINE_GUID(IID_IMatchFinder,
+0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00);
+MIDL_INTERFACE("23170F69-40C1-278A-0000-000200020000")
+IMatchFinder: public IInWindowStream
+{
+ STDMETHOD(Create)(UInt32 historySize, UInt32 keepAddBufferBefore,
+ UInt32 matchMaxLen, UInt32 keepAddBufferAfter) PURE;
+ STDMETHOD_(UInt32, GetLongestMatch)(UInt32 *distances) PURE;
+ STDMETHOD_(void, DummyLongestMatch)() PURE;
+};
+
+// {23170F69-40C1-278A-0000-000200020100}
+DEFINE_GUID(IID_IMatchFinderCallback,
+0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x01, 0x00);
+MIDL_INTERFACE("23170F69-40C1-278A-0000-000200020100")
+IMatchFinderCallback: public IUnknown
+{
+ STDMETHOD(BeforeChangingBufferPos)() PURE;
+ STDMETHOD(AfterChangingBufferPos)() PURE;
+};
+
+// {23170F69-40C1-278A-0000-000200020200}
+DEFINE_GUID(IID_IMatchFinderSetCallback,
+0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x02, 0x00);
+MIDL_INTERFACE("23170F69-40C1-278A-0000-000200020200")
+IMatchFinderSetCallback: public IUnknown
+{
+ STDMETHOD(SetCallback)(IMatchFinderCallback *callback) PURE;
+};
+
+/*
+// {23170F69-40C1-278A-0000-000200030000}
+DEFINE_GUID(IID_IInitMatchFinder,
+0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00);
+MIDL_INTERFACE("23170F69-40C1-278A-0000-000200030000")
+IMatchFinderInit: public IUnknown
+{
+ STDMETHOD(InitMatchFinder)(IMatchFinder *matchFinder) PURE;
+};
+*/
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/LZInWindow.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/LZInWindow.cpp new file mode 100644 index 00000000..a7b7a387 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/LZInWindow.cpp @@ -0,0 +1,102 @@ +// LZInWindow.cpp
+
+#include "StdAfx.h"
+
+#include "LZInWindow.h"
+#include "../../../Common/MyCom.h"
+#include "../../../Common/Alloc.h"
+
+void CLZInWindow::Free()
+{
+ ::BigFree(_bufferBase);
+ _bufferBase = 0;
+}
+
+bool CLZInWindow::Create(UInt32 keepSizeBefore, UInt32 keepSizeAfter, UInt32 keepSizeReserv)
+{
+ _keepSizeBefore = keepSizeBefore;
+ _keepSizeAfter = keepSizeAfter;
+ _keepSizeReserv = keepSizeReserv;
+ UInt32 blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv;
+ if (_bufferBase == 0 || _blockSize != blockSize)
+ {
+ Free();
+ _blockSize = blockSize;
+ if (_blockSize != 0)
+ _bufferBase = (Byte *)::BigAlloc(_blockSize);
+ }
+ _pointerToLastSafePosition = _bufferBase + _blockSize - keepSizeAfter;
+ if (_blockSize == 0)
+ return true;
+ return (_bufferBase != 0);
+}
+
+
+HRESULT CLZInWindow::Init(ISequentialInStream *stream)
+{
+ _stream = stream;
+ _buffer = _bufferBase;
+ _pos = 0;
+ _streamPos = 0;
+ _streamEndWasReached = false;
+ return ReadBlock();
+}
+
+/*
+void CLZInWindow::ReleaseStream()
+{
+ _stream.Release();
+}
+*/
+
+///////////////////////////////////////////
+// ReadBlock
+
+// In State:
+// (_buffer + _streamPos) <= (_bufferBase + _blockSize)
+// Out State:
+// _posLimit <= _blockSize - _keepSizeAfter;
+// if(_streamEndWasReached == false):
+// _streamPos >= _pos + _keepSizeAfter
+// _posLimit = _streamPos - _keepSizeAfter;
+// else
+//
+
+HRESULT CLZInWindow::ReadBlock()
+{
+ if(_streamEndWasReached)
+ return S_OK;
+ while(true)
+ {
+ UInt32 size = UInt32(_bufferBase - _buffer) + _blockSize - _streamPos;
+ if(size == 0)
+ return S_OK;
+ UInt32 numReadBytes;
+ RINOK(_stream->Read(_buffer + _streamPos, size, &numReadBytes));
+ if(numReadBytes == 0)
+ {
+ _posLimit = _streamPos;
+ const Byte *pointerToPostion = _buffer + _posLimit;
+ if(pointerToPostion > _pointerToLastSafePosition)
+ _posLimit = (UInt32)(_pointerToLastSafePosition - _buffer);
+ _streamEndWasReached = true;
+ return S_OK;
+ }
+ _streamPos += numReadBytes;
+ if(_streamPos >= _pos + _keepSizeAfter)
+ {
+ _posLimit = _streamPos - _keepSizeAfter;
+ return S_OK;
+ }
+ }
+}
+
+void CLZInWindow::MoveBlock()
+{
+ BeforeMoveBlock();
+ UInt32 offset = UInt32(_buffer - _bufferBase) + _pos - _keepSizeBefore;
+ UInt32 numBytes = UInt32(_buffer - _bufferBase) + _streamPos - offset;
+ memmove(_bufferBase, _bufferBase + offset, numBytes);
+ _buffer -= offset;
+ AfterMoveBlock();
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/LZInWindow.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/LZInWindow.h new file mode 100644 index 00000000..7dc194f2 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/LZInWindow.h @@ -0,0 +1,84 @@ +// LZInWindow.h
+
+#ifndef __LZ_IN_WINDOW_H
+#define __LZ_IN_WINDOW_H
+
+#include "../../IStream.h"
+
+class CLZInWindow
+{
+ Byte *_bufferBase; // pointer to buffer with data
+ ISequentialInStream *_stream;
+ UInt32 _posLimit; // offset (from _buffer) of first byte when new block reading must be done
+ bool _streamEndWasReached; // if (true) then _streamPos shows real end of stream
+ const Byte *_pointerToLastSafePosition;
+protected:
+ Byte *_buffer; // Pointer to virtual Buffer begin
+ UInt32 _blockSize; // Size of Allocated memory block
+ UInt32 _pos; // offset (from _buffer) of curent byte
+ UInt32 _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos
+ UInt32 _keepSizeAfter; // how many BYTEs must be kept buffer after _pos
+ UInt32 _keepSizeReserv; // how many BYTEs must be kept as reserv
+ UInt32 _streamPos; // offset (from _buffer) of first not read byte from Stream
+
+ virtual void BeforeMoveBlock() {};
+ virtual void AfterMoveBlock() {};
+ void MoveBlock();
+ virtual HRESULT ReadBlock();
+ void Free();
+public:
+ CLZInWindow(): _bufferBase(0) {}
+ virtual ~CLZInWindow() { Free(); }
+
+ bool Create(UInt32 keepSizeBefore, UInt32 keepSizeAfter,
+ UInt32 keepSizeReserv = (1<<17));
+
+ HRESULT Init(ISequentialInStream *stream);
+ // void ReleaseStream();
+
+ Byte *GetBuffer() const { return _buffer; }
+
+ const Byte *GetPointerToCurrentPos() const { return _buffer + _pos; }
+
+ HRESULT MovePos()
+ {
+ _pos++;
+ if (_pos > _posLimit)
+ {
+ const Byte *pointerToPostion = _buffer + _pos;
+ if(pointerToPostion > _pointerToLastSafePosition)
+ MoveBlock();
+ return ReadBlock();
+ }
+ else
+ return S_OK;
+ }
+ Byte GetIndexByte(Int32 index)const
+ { return _buffer[(size_t)_pos + index]; }
+
+ // index + limit have not to exceed _keepSizeAfter;
+ UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit) const
+ {
+ if(_streamEndWasReached)
+ if ((_pos + index) + limit > _streamPos)
+ limit = _streamPos - (_pos + index);
+ distance++;
+ Byte *pby = _buffer + (size_t)_pos + index;
+ UInt32 i;
+ for(i = 0; i < limit && pby[i] == pby[(size_t)i - distance]; i++);
+ return i;
+ }
+
+ UInt32 GetNumAvailableBytes() const { return _streamPos - _pos; }
+
+ void ReduceOffsets(Int32 subValue)
+ {
+ _buffer += subValue;
+ _posLimit -= subValue;
+ _pos -= subValue;
+ _streamPos -= subValue;
+ }
+
+};
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/LZOutWindow.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/LZOutWindow.cpp new file mode 100644 index 00000000..329a7db3 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/LZOutWindow.cpp @@ -0,0 +1,17 @@ +// LZOutWindow.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/Alloc.h"
+#include "LZOutWindow.h"
+
+void CLZOutWindow::Init(bool solid)
+{
+ if(!solid)
+ COutBuffer::Init();
+ #ifdef _NO_EXCEPTIONS
+ ErrorCode = S_OK;
+ #endif
+}
+
+
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/LZOutWindow.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/LZOutWindow.h new file mode 100644 index 00000000..ba38c5e2 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/LZOutWindow.h @@ -0,0 +1,64 @@ +// LZOutWindow.h
+
+#ifndef __LZ_OUT_WINDOW_H
+#define __LZ_OUT_WINDOW_H
+
+#include "../../IStream.h"
+#include "../../Common/OutBuffer.h"
+
+/*
+#ifndef _NO_EXCEPTIONS
+class CLZOutWindowException
+{
+public:
+ HRESULT ErrorCode;
+ CLZOutWindowException(HRESULT errorCode): ErrorCode(errorCode) {}
+};
+#endif
+*/
+typedef COutBufferException CLZOutWindowException;
+
+class CLZOutWindow: public COutBuffer
+{
+public:
+ void Init(bool solid = false);
+
+ // distance >= 0, len > 0,
+ bool CopyBlock(UInt32 distance, UInt32 len)
+ {
+ UInt32 pos = _pos - distance - 1;
+ if (pos >= _bufferSize)
+ {
+ if (!_overDict)
+ return false;
+ pos += _bufferSize;
+ }
+ do
+ {
+ if (pos == _bufferSize)
+ pos = 0;
+ _buffer[_pos++] = _buffer[pos++];
+ if (_pos == _limitPos)
+ FlushWithCheck();
+ }
+ while(--len != 0);
+ return true;
+ }
+
+ void PutByte(Byte b)
+ {
+ _buffer[_pos++] = b;
+ if (_pos == _limitPos)
+ FlushWithCheck();
+ }
+
+ Byte GetByte(UInt32 distance) const
+ {
+ UInt32 pos = _pos - distance - 1;
+ if (pos >= _bufferSize)
+ pos += _bufferSize;
+ return _buffer[pos];
+ }
+};
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/Patricia/Pat.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/Patricia/Pat.h new file mode 100644 index 00000000..2d0ce6d0 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/Patricia/Pat.h @@ -0,0 +1,318 @@ +// Pat.h
+
+// #ifndef __PATRICIA__H
+// #define __PATRICIA__H
+
+#include "../../../../Common/MyCom.h"
+#include "../../../../Common/Types.h"
+#include "../LZInWindow.h"
+
+namespace PAT_NAMESPACE {
+
+struct CNode;
+
+typedef CNode *CNodePointer;
+
+// #define __AUTO_REMOVE
+
+// #define __NODE_4_BITS
+// #define __NODE_3_BITS
+// #define __NODE_2_BITS
+// #define __NODE_2_BITS_PADDING
+
+// #define __HASH_3
+
+
+typedef UInt32 CIndex;
+
+#ifdef __NODE_4_BITS
+ typedef UInt32 CIndex2;
+ typedef UInt32 CSameBitsType;
+#else
+#ifdef __NODE_3_BITS
+ typedef UInt32 CIndex2;
+ typedef UInt32 CSameBitsType;
+#else
+
+ typedef UInt32 CIndex;
+ typedef UInt32 CSameBitsType;
+
+ typedef CIndex CIndex2;
+#endif
+#endif
+
+const UInt32 kNumBitsInIndex = sizeof(CIndex) * 8;
+const UInt32 kMatchStartValue = UInt32(1) << (kNumBitsInIndex - 1);
+// don't change kMatchStartValue definition, since it is used in
+// PatMain.h:
+
+typedef CIndex CMatchPointer;
+
+const UInt32 kDescendantEmptyValue = kMatchStartValue - 1;
+
+union CDescendant
+{
+ CIndex NodePointer;
+ CMatchPointer MatchPointer;
+ bool IsEmpty() const { return NodePointer == kDescendantEmptyValue; }
+ bool IsNode() const { return NodePointer < kDescendantEmptyValue; }
+ bool IsMatch() const { return NodePointer > kDescendantEmptyValue; }
+ void MakeEmpty() { NodePointer = kDescendantEmptyValue; }
+};
+
+#undef MY_BYTE_SIZE
+
+#ifdef __NODE_4_BITS
+ #define MY_BYTE_SIZE 8
+ const UInt32 kNumSubBits = 4;
+#else
+#ifdef __NODE_3_BITS
+ #define MY_BYTE_SIZE 9
+ const UInt32 kNumSubBits = 3;
+#else
+ #define MY_BYTE_SIZE 8
+ #ifdef __NODE_2_BITS
+ const UInt32 kNumSubBits = 2;
+ #else
+ const UInt32 kNumSubBits = 1;
+ #endif
+#endif
+#endif
+
+const UInt32 kNumSubNodes = 1 << kNumSubBits;
+const UInt32 kSubNodesMask = kNumSubNodes - 1;
+
+struct CNode
+{
+ CIndex2 LastMatch;
+ CSameBitsType NumSameBits;
+ union
+ {
+ CDescendant Descendants[kNumSubNodes];
+ UInt32 NextFreeNode;
+ };
+ #ifdef __NODE_2_BITS
+ #ifdef __NODE_2_BITS_PADDING
+ UInt32 Padding[2];
+ #endif
+ #endif
+};
+
+#undef kIDNumBitsByte
+#undef kIDNumBitsString
+
+#ifdef __NODE_4_BITS
+ #define kIDNumBitsByte 0x30
+ #define kIDNumBitsString TEXT("4")
+#else
+#ifdef __NODE_3_BITS
+ #define kIDNumBitsByte 0x20
+ #define kIDNumBitsString TEXT("3")
+#else
+#ifdef __NODE_2_BITS
+ #define kIDNumBitsByte 0x10
+ #define kIDNumBitsString TEXT("2")
+#else
+ #define kIDNumBitsByte 0x00
+ #define kIDNumBitsString TEXT("1")
+#endif
+#endif
+#endif
+
+#undef kIDManualRemoveByte
+#undef kIDManualRemoveString
+
+#ifdef __AUTO_REMOVE
+ #define kIDManualRemoveByte 0x00
+ #define kIDManualRemoveString TEXT("")
+#else
+ #define kIDManualRemoveByte 0x08
+ #define kIDManualRemoveString TEXT("R")
+#endif
+
+#undef kIDHash3Byte
+#undef kIDHash3String
+
+#ifdef __HASH_3
+ #define kIDHash3Byte 0x04
+ #define kIDHash3String TEXT("H")
+#else
+ #define kIDHash3Byte 0x00
+ #define kIDHash3String TEXT("")
+#endif
+
+#undef kIDUse3BytesByte
+#undef kIDUse3BytesString
+
+#define kIDUse3BytesByte 0x00
+#define kIDUse3BytesString TEXT("")
+
+#undef kIDPaddingByte
+#undef kIDPaddingString
+
+#ifdef __NODE_2_BITS_PADDING
+ #define kIDPaddingByte 0x01
+ #define kIDPaddingString TEXT("P")
+#else
+ #define kIDPaddingByte 0x00
+ #define kIDPaddingString TEXT("")
+#endif
+
+
+// #undef kIDString
+// #define kIDString TEXT("Compress.MatchFinderPat") kIDNumBitsString kIDManualRemoveString kIDUse3BytesString kIDPaddingString kIDHash3String
+
+// {23170F69-40C1-278C-01XX-0000000000}
+
+DEFINE_GUID(PAT_CLSID,
+0x23170F69, 0x40C1, 0x278C, 0x01,
+kIDNumBitsByte |
+kIDManualRemoveByte | kIDHash3Byte | kIDUse3BytesByte | kIDPaddingByte,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+
+// III(PAT_NAMESPACE)
+
+class CPatricia:
+ public IMatchFinder,
+ public IMatchFinderSetCallback,
+ public CMyUnknownImp,
+ CLZInWindow
+{
+ MY_UNKNOWN_IMP1(IMatchFinderSetCallback)
+
+ STDMETHOD(Init)(ISequentialInStream *aStream);
+ STDMETHOD_(void, ReleaseStream)();
+ STDMETHOD(MovePos)();
+ STDMETHOD_(Byte, GetIndexByte)(Int32 index);
+ STDMETHOD_(UInt32, GetMatchLen)(Int32 index, UInt32 back, UInt32 limit);
+ STDMETHOD_(UInt32, GetNumAvailableBytes)();
+ STDMETHOD(Create)(UInt32 historySize,
+ UInt32 keepAddBufferBefore, UInt32 matchMaxLen,
+ UInt32 keepAddBufferAfter);
+ STDMETHOD_(UInt32, GetLongestMatch)(UInt32 *distances);
+ STDMETHOD_(void, DummyLongestMatch)();
+ STDMETHOD_(const Byte *, GetPointerToCurrentPos)();
+
+ void FreeMemory();
+public:
+ CPatricia();
+ ~CPatricia();
+
+ UInt32 _sizeHistory;
+ UInt32 _matchMaxLen;
+
+ CDescendant *m_HashDescendants;
+ #ifdef __HASH_3
+ CDescendant *m_Hash2Descendants;
+ #endif
+
+ CNode *m_Nodes;
+
+ UInt32 m_FreeNode;
+ UInt32 m_FreeNodeMax;
+
+ #ifdef __AUTO_REMOVE
+ UInt32 m_NumUsedNodes;
+ UInt32 m_NumNodes;
+ #else
+ bool m_SpecialRemoveMode;
+ #endif
+
+ bool m_SpecialMode;
+ UInt32 m_NumNotChangedCycles;
+ UInt32 *m_TmpBacks;
+
+ CMyComPtr<IMatchFinderCallback> m_Callback;
+
+ virtual void BeforeMoveBlock();
+ virtual void AfterMoveBlock();
+
+ // IMatchFinderSetCallback
+ STDMETHOD(SetCallback)(IMatchFinderCallback *callback);
+
+ void ChangeLastMatch(UInt32 hashValue);
+
+ #ifdef __AUTO_REMOVE
+ void TestRemoveDescendant(CDescendant &descendant, UInt32 limitPos);
+ void TestRemoveNodes();
+ void RemoveNode(UInt32 index);
+ void TestRemoveAndNormalizeDescendant(CDescendant &descendant,
+ UInt32 limitPos, UInt32 subValue);
+ void TestRemoveNodesAndNormalize();
+ #else
+ void NormalizeDescendant(CDescendant &descendant, UInt32 subValue);
+ void Normalize();
+ void RemoveMatch();
+ #endif
+private:
+ void AddInternalNode(CNodePointer aNode, CIndex *aNodePointerPointer,
+ Byte aByte, Byte aByteXOR, UInt32 aNumSameBits, UInt32 aPos)
+ {
+ while((aByteXOR & kSubNodesMask) == 0)
+ {
+ aByteXOR >>= kNumSubBits;
+ aByte >>= kNumSubBits;
+ aNumSameBits -= kNumSubBits;
+ }
+ // Insert New Node
+ CNodePointer aNewNode = &m_Nodes[m_FreeNode];
+ UInt32 aNodeIndex = *aNodePointerPointer;
+ *aNodePointerPointer = m_FreeNode;
+ m_FreeNode = aNewNode->NextFreeNode;
+ #ifdef __AUTO_REMOVE
+ m_NumUsedNodes++;
+ #endif
+ if (m_FreeNode > m_FreeNodeMax)
+ {
+ m_FreeNodeMax = m_FreeNode;
+ m_Nodes[m_FreeNode].NextFreeNode = m_FreeNode + 1;
+ }
+
+ UInt32 aBitsNew = aByte & kSubNodesMask;
+ UInt32 aBitsOld = (aByte ^ aByteXOR) & kSubNodesMask;
+ for (UInt32 i = 0; i < kNumSubNodes; i++)
+ aNewNode->Descendants[i].NodePointer = kDescendantEmptyValue;
+ aNewNode->Descendants[aBitsNew].MatchPointer = aPos + kMatchStartValue;
+ aNewNode->Descendants[aBitsOld].NodePointer = aNodeIndex;
+ aNewNode->NumSameBits = CSameBitsType(aNode->NumSameBits - aNumSameBits);
+ aNewNode->LastMatch = aPos;
+
+ aNode->NumSameBits = CSameBitsType(aNumSameBits - kNumSubBits);
+ }
+
+ void AddLeafNode(CNodePointer aNode, Byte aByte, Byte aByteXOR,
+ UInt32 aNumSameBits, UInt32 aPos, UInt32 aDescendantIndex)
+ {
+ for(;(aByteXOR & kSubNodesMask) == 0; aNumSameBits += kNumSubBits)
+ {
+ aByte >>= kNumSubBits;
+ aByteXOR >>= kNumSubBits;
+ }
+ UInt32 aNewNodeIndex = m_FreeNode;
+ CNodePointer aNewNode = &m_Nodes[m_FreeNode];
+ m_FreeNode = aNewNode->NextFreeNode;
+ #ifdef __AUTO_REMOVE
+ m_NumUsedNodes++;
+ #endif
+ if (m_FreeNode > m_FreeNodeMax)
+ {
+ m_FreeNodeMax = m_FreeNode;
+ m_Nodes[m_FreeNode].NextFreeNode = m_FreeNode + 1;
+ }
+
+ UInt32 aBitsNew = (aByte & kSubNodesMask);
+ UInt32 aBitsOld = (aByte ^ aByteXOR) & kSubNodesMask;
+ for (UInt32 i = 0; i < kNumSubNodes; i++)
+ aNewNode->Descendants[i].NodePointer = kDescendantEmptyValue;
+ aNewNode->Descendants[aBitsNew].MatchPointer = aPos + kMatchStartValue;
+ aNewNode->Descendants[aBitsOld].MatchPointer =
+ aNode->Descendants[aDescendantIndex].MatchPointer;
+ aNewNode->NumSameBits = CSameBitsType(aNumSameBits);
+ aNewNode->LastMatch = aPos;
+ aNode->Descendants[aDescendantIndex].NodePointer = aNewNodeIndex;
+ }
+};
+
+}
+
+// #endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/Patricia/Pat2.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/Patricia/Pat2.h new file mode 100644 index 00000000..0c97164d --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/Patricia/Pat2.h @@ -0,0 +1,22 @@ +// Pat2.h
+
+#ifndef __PAT2__H
+#define __PAT2__H
+
+#undef PAT_CLSID
+#define PAT_CLSID CLSID_CMatchFinderPat2
+
+#undef PAT_NAMESPACE
+#define PAT_NAMESPACE NPat2
+
+#define __AUTO_REMOVE
+#define __NODE_2_BITS
+
+#include "Pat.h"
+#include "PatMain.h"
+
+#undef __AUTO_REMOVE
+#undef __NODE_2_BITS
+
+#endif
+
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/Patricia/Pat2H.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/Patricia/Pat2H.h new file mode 100644 index 00000000..c3a374fa --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/Patricia/Pat2H.h @@ -0,0 +1,24 @@ +// Pat2H.h
+
+#ifndef __PAT2H__H
+#define __PAT2H__H
+
+#undef PAT_CLSID
+#define PAT_CLSID CLSID_CMatchFinderPat2H
+
+#undef PAT_NAMESPACE
+#define PAT_NAMESPACE NPat2H
+
+#define __AUTO_REMOVE
+#define __NODE_2_BITS
+#define __HASH_3
+
+#include "Pat.h"
+#include "PatMain.h"
+
+#undef __AUTO_REMOVE
+#undef __NODE_2_BITS
+#undef __HASH_3
+
+#endif
+
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/Patricia/Pat2R.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/Patricia/Pat2R.h new file mode 100644 index 00000000..2c6267e8 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/Patricia/Pat2R.h @@ -0,0 +1,20 @@ +// Pat2R.h
+
+#ifndef __PAT2R__H
+#define __PAT2R__H
+
+#undef PAT_CLSID
+#define PAT_CLSID CLSID_CMatchFinderPat2R
+
+#undef PAT_NAMESPACE
+#define PAT_NAMESPACE NPat2R
+
+#define __NODE_2_BITS
+
+#include "Pat.h"
+#include "PatMain.h"
+
+#undef __NODE_2_BITS
+
+#endif
+
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/Patricia/Pat3H.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/Patricia/Pat3H.h new file mode 100644 index 00000000..96bdccd4 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/Patricia/Pat3H.h @@ -0,0 +1,24 @@ +// Pat3H.h
+
+#ifndef __PAT3H__H
+#define __PAT3H__H
+
+#undef PAT_CLSID
+#define PAT_CLSID CLSID_CMatchFinderPat3H
+
+#undef PAT_NAMESPACE
+#define PAT_NAMESPACE NPat3H
+
+#define __AUTO_REMOVE
+#define __NODE_3_BITS
+#define __HASH_3
+
+#include "Pat.h"
+#include "PatMain.h"
+
+#undef __AUTO_REMOVE
+#undef __NODE_3_BITS
+#undef __HASH_3
+
+#endif
+
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/Patricia/Pat4H.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/Patricia/Pat4H.h new file mode 100644 index 00000000..ff5fdbf4 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/Patricia/Pat4H.h @@ -0,0 +1,24 @@ +// Pat4H.h
+
+#ifndef __PAT4H__H
+#define __PAT4H__H
+
+#undef PAT_CLSID
+#define PAT_CLSID CLSID_CMatchFinderPat4H
+
+#undef PAT_NAMESPACE
+#define PAT_NAMESPACE NPat4H
+
+#define __AUTO_REMOVE
+#define __NODE_4_BITS
+#define __HASH_3
+
+#include "Pat.h"
+#include "PatMain.h"
+
+#undef __AUTO_REMOVE
+#undef __NODE_4_BITS
+#undef __HASH_3
+
+#endif
+
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/Patricia/PatMain.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/Patricia/PatMain.h new file mode 100644 index 00000000..028f16ba --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/Patricia/PatMain.h @@ -0,0 +1,989 @@ +// PatMain.h
+
+#include "../../../../Common/Defs.h"
+#include "../../../../Common/Alloc.h"
+
+namespace PAT_NAMESPACE {
+
+STDMETHODIMP CPatricia::SetCallback(IMatchFinderCallback *callback)
+{
+ m_Callback = callback;
+ return S_OK;
+}
+
+void CPatricia::BeforeMoveBlock()
+{
+ if (m_Callback)
+ m_Callback->BeforeChangingBufferPos();
+ CLZInWindow::BeforeMoveBlock();
+}
+
+void CPatricia::AfterMoveBlock()
+{
+ if (m_Callback)
+ m_Callback->AfterChangingBufferPos();
+ CLZInWindow::AfterMoveBlock();
+}
+
+const UInt32 kMatchStartValue2 = 2;
+const UInt32 kDescendantEmptyValue2 = kMatchStartValue2 - 1;
+const UInt32 kDescendantsNotInitilized2 = kDescendantEmptyValue2 - 1;
+
+#ifdef __HASH_3
+
+static const UInt32 kNumHashBytes = 3;
+static const UInt32 kHashSize = 1 << (8 * kNumHashBytes);
+
+static const UInt32 kNumHash2Bytes = 2;
+static const UInt32 kHash2Size = 1 << (8 * kNumHash2Bytes);
+static const UInt32 kPrevHashSize = kNumHash2Bytes;
+
+#else
+
+static const UInt32 kNumHashBytes = 2;
+static const UInt32 kHashSize = 1 << (8 * kNumHashBytes);
+static const UInt32 kPrevHashSize = 0;
+
+#endif
+
+
+CPatricia::CPatricia():
+ m_HashDescendants(0),
+ #ifdef __HASH_3
+ m_Hash2Descendants(0),
+ #endif
+ m_Nodes(0),
+ m_TmpBacks(0)
+{
+}
+
+CPatricia::~CPatricia()
+{
+ FreeMemory();
+}
+
+void CPatricia::FreeMemory()
+{
+ MyFree(m_TmpBacks);
+ m_TmpBacks = 0;
+
+ ::BigFree(m_Nodes);
+ m_Nodes = 0;
+
+ ::BigFree(m_HashDescendants);
+ m_HashDescendants = 0;
+
+ #ifdef __HASH_3
+
+ ::BigFree(m_Hash2Descendants);
+ m_Hash2Descendants = 0;
+
+ CLZInWindow::Free();
+
+ #endif
+}
+
+STDMETHODIMP CPatricia::Create(UInt32 historySize, UInt32 keepAddBufferBefore,
+ UInt32 matchMaxLen, UInt32 keepAddBufferAfter)
+{
+ FreeMemory();
+ int kNumBitsInNumSameBits = sizeof(CSameBitsType) * 8;
+ if (kNumBitsInNumSameBits < 32 && ((matchMaxLen * MY_BYTE_SIZE) > ((UInt32)1 << kNumBitsInNumSameBits)))
+ return E_INVALIDARG;
+
+ const UInt32 kAlignMask = (1 << 16) - 1;
+ UInt32 windowReservSize = historySize;
+ windowReservSize += kAlignMask;
+ windowReservSize &= ~(kAlignMask);
+
+ const UInt32 kMinReservSize = (1 << 19);
+ if (windowReservSize < kMinReservSize)
+ windowReservSize = kMinReservSize;
+ windowReservSize += 256;
+
+ if (!CLZInWindow::Create(historySize + keepAddBufferBefore,
+ matchMaxLen + keepAddBufferAfter, windowReservSize))
+ return E_OUTOFMEMORY;
+
+ _sizeHistory = historySize;
+ _matchMaxLen = matchMaxLen;
+ m_HashDescendants = (CDescendant *)BigAlloc(kHashSize * sizeof(CDescendant));
+ if (m_HashDescendants == 0)
+ {
+ FreeMemory();
+ return E_OUTOFMEMORY;
+ }
+
+ #ifdef __HASH_3
+ m_Hash2Descendants = (CDescendant *)BigAlloc(kHash2Size * sizeof(CDescendant));
+ if (m_Hash2Descendants == 0)
+ {
+ FreeMemory();
+ return E_OUTOFMEMORY;
+ }
+ #endif
+
+ #ifdef __AUTO_REMOVE
+
+ #ifdef __HASH_3
+ m_NumNodes = historySize + _sizeHistory * 4 / 8 + (1 << 19);
+ #else
+ m_NumNodes = historySize + _sizeHistory * 4 / 8 + (1 << 10);
+ #endif
+
+ #else
+
+ UInt32 m_NumNodes = historySize;
+
+ #endif
+
+ const UInt32 kMaxNumNodes = UInt32(1) << (sizeof(CIndex) * 8 - 1);
+ if (m_NumNodes + 32 > kMaxNumNodes)
+ return E_INVALIDARG;
+
+ // m_Nodes = (CNode *)::BigAlloc((m_NumNodes + 2) * sizeof(CNode));
+ m_Nodes = (CNode *)::BigAlloc((m_NumNodes + 12) * sizeof(CNode));
+ if (m_Nodes == 0)
+ {
+ FreeMemory();
+ return E_OUTOFMEMORY;
+ }
+
+ m_TmpBacks = (UInt32 *)MyAlloc((_matchMaxLen + 1) * sizeof(UInt32));
+ if (m_TmpBacks == 0)
+ {
+ FreeMemory();
+ return E_OUTOFMEMORY;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CPatricia::Init(ISequentialInStream *aStream)
+{
+ RINOK(CLZInWindow::Init(aStream));
+
+ // memset(m_HashDescendants, 0xFF, kHashSize * sizeof(m_HashDescendants[0]));
+
+ #ifdef __HASH_3
+ for (UInt32 i = 0; i < kHash2Size; i++)
+ m_Hash2Descendants[i].MatchPointer = kDescendantsNotInitilized2;
+ #else
+ for (UInt32 i = 0; i < kHashSize; i++)
+ m_HashDescendants[i].MakeEmpty();
+ #endif
+
+ m_Nodes[0].NextFreeNode = 1;
+ m_FreeNode = 0;
+ m_FreeNodeMax = 0;
+ #ifdef __AUTO_REMOVE
+ m_NumUsedNodes = 0;
+ #else
+ m_SpecialRemoveMode = false;
+ #endif
+ m_SpecialMode = false;
+ return S_OK;
+}
+
+STDMETHODIMP_(void) CPatricia::ReleaseStream()
+{
+ // CLZInWindow::ReleaseStream();
+}
+
+// pos = _pos + kNumHashBytes
+// fullCurrentLimit = currentLimit + kNumHashBytes
+// fullMatchLen = matchLen + kNumHashBytes
+
+void CPatricia::ChangeLastMatch(UInt32 hashValue)
+{
+ UInt32 pos = _pos + kNumHashBytes - 1;
+ UInt32 descendantIndex;
+ const Byte *currentBytePointer = _buffer + pos;
+ UInt32 numLoadedBits = 0;
+ Byte curByte = 0; // = 0 to disable warning of GCC
+ CNodePointer node = &m_Nodes[m_HashDescendants[hashValue].NodePointer];
+
+ while(true)
+ {
+ UInt32 numSameBits = node->NumSameBits;
+ if(numSameBits > 0)
+ {
+ if (numLoadedBits < numSameBits)
+ {
+ numSameBits -= numLoadedBits;
+ currentBytePointer += (numSameBits / MY_BYTE_SIZE);
+ numSameBits %= MY_BYTE_SIZE;
+ curByte = *currentBytePointer++;
+ numLoadedBits = MY_BYTE_SIZE;
+ }
+ curByte >>= numSameBits;
+ numLoadedBits -= numSameBits;
+ }
+ if(numLoadedBits == 0)
+ {
+ curByte = *currentBytePointer++;
+ numLoadedBits = MY_BYTE_SIZE;
+ }
+ descendantIndex = (curByte & kSubNodesMask);
+ node->LastMatch = pos;
+ numLoadedBits -= kNumSubBits;
+ curByte >>= kNumSubBits;
+ if(node->Descendants[descendantIndex].IsNode())
+ node = &m_Nodes[node->Descendants[descendantIndex].NodePointer];
+ else
+ break;
+ }
+ node->Descendants[descendantIndex].MatchPointer = pos + kMatchStartValue;
+}
+
+UInt32 CPatricia::GetLongestMatch(UInt32 *distances)
+{
+ UInt32 fullCurrentLimit;
+ if (_pos + _matchMaxLen <= _streamPos)
+ fullCurrentLimit = _matchMaxLen;
+ else
+ {
+ fullCurrentLimit = _streamPos - _pos;
+ if(fullCurrentLimit < kNumHashBytes)
+ return 0;
+ }
+ UInt32 pos = _pos + kNumHashBytes;
+
+ #ifdef __HASH_3
+ UInt32 hash2Value = ((UInt32(_buffer[_pos])) << 8) | _buffer[_pos + 1];
+ UInt32 hashValue = (hash2Value << 8) | _buffer[_pos + 2];
+ CDescendant &hash2Descendant = m_Hash2Descendants[hash2Value];
+ CDescendant &hashDescendant = m_HashDescendants[hashValue];
+ if(hash2Descendant.MatchPointer <= kDescendantEmptyValue2)
+ {
+ if(hash2Descendant.MatchPointer == kDescendantsNotInitilized2)
+ {
+ UInt32 base = hashValue & 0xFFFF00;
+ for (UInt32 i = 0; i < 0x100; i++)
+ m_HashDescendants[base + i].MakeEmpty();
+ }
+ hash2Descendant.MatchPointer = pos + kMatchStartValue2;
+ hashDescendant.MatchPointer = pos + kMatchStartValue;
+ return 0;
+ }
+
+ distances[kNumHash2Bytes] = pos - (hash2Descendant.MatchPointer - kMatchStartValue2) - 1;
+ hash2Descendant.MatchPointer = pos + kMatchStartValue2;
+ #ifdef __AUTO_REMOVE
+ if (distances[kNumHash2Bytes] >= _sizeHistory)
+ {
+ if (hashDescendant.IsNode())
+ RemoveNode(hashDescendant.NodePointer);
+ hashDescendant.MatchPointer = pos + kMatchStartValue;
+ return 0;
+ }
+ #endif
+ if (fullCurrentLimit == kNumHash2Bytes)
+ return kNumHash2Bytes;
+
+ #else
+ UInt32 hashValue = UInt32(GetIndexByte(1)) | (UInt32(GetIndexByte(0)) << 8);
+ CDescendant &hashDescendant = m_HashDescendants[hashValue];
+ #endif
+
+
+ if(m_SpecialMode)
+ {
+ if(hashDescendant.IsMatch())
+ m_NumNotChangedCycles = 0;
+ if(m_NumNotChangedCycles >= _sizeHistory - 1)
+ {
+ ChangeLastMatch(hashValue);
+ m_NumNotChangedCycles = 0;
+ }
+ if(GetIndexByte(fullCurrentLimit - 1) == GetIndexByte(fullCurrentLimit - 2))
+ {
+ if(hashDescendant.IsMatch())
+ hashDescendant.MatchPointer = pos + kMatchStartValue;
+ else
+ m_NumNotChangedCycles++;
+ for(UInt32 i = kNumHashBytes; i <= fullCurrentLimit; i++)
+ distances[i] = 0;
+ return fullCurrentLimit;
+ }
+ else if(m_NumNotChangedCycles > 0)
+ ChangeLastMatch(hashValue);
+ m_SpecialMode = false;
+ }
+
+ if(hashDescendant.IsEmpty())
+ {
+ hashDescendant.MatchPointer = pos + kMatchStartValue;
+ return kPrevHashSize;
+ }
+
+ UInt32 currentLimit = fullCurrentLimit - kNumHashBytes;
+
+ if(hashDescendant.IsMatch())
+ {
+ CMatchPointer matchPointer = hashDescendant.MatchPointer;
+ UInt32 backReal = pos - (matchPointer - kMatchStartValue);
+ UInt32 back = backReal - 1;
+ #ifdef __AUTO_REMOVE
+ if (back >= _sizeHistory)
+ {
+ hashDescendant.MatchPointer = pos + kMatchStartValue;
+ return kPrevHashSize;
+ }
+ #endif
+
+ UInt32 matchLen;
+ distances += kNumHashBytes;
+ Byte *buffer = _buffer + pos;
+ for(matchLen = 0; true; matchLen++)
+ {
+ *distances++ = back;
+ if (matchLen == currentLimit)
+ {
+ hashDescendant.MatchPointer = pos + kMatchStartValue;
+ return kNumHashBytes + matchLen;
+ }
+ if (buffer[matchLen] != buffer[(size_t)matchLen - backReal])
+ break;
+ }
+
+ // UInt32 matchLen = GetMatchLen(kNumHashBytes, back, currentLimit);
+
+ UInt32 fullMatchLen = matchLen + kNumHashBytes;
+ hashDescendant.NodePointer = m_FreeNode;
+ CNodePointer node = &m_Nodes[m_FreeNode];
+ m_FreeNode = node->NextFreeNode;
+ #ifdef __AUTO_REMOVE
+ m_NumUsedNodes++;
+ #endif
+ if (m_FreeNode > m_FreeNodeMax)
+ {
+ m_FreeNodeMax = m_FreeNode;
+ m_Nodes[m_FreeNode].NextFreeNode = m_FreeNode + 1;
+ }
+
+ for (UInt32 i = 0; i < kNumSubNodes; i++)
+ node->Descendants[i].NodePointer = kDescendantEmptyValue;
+ node->LastMatch = pos;
+
+ Byte byteNew = GetIndexByte(fullMatchLen);
+ Byte byteOld = GetIndexByte(fullMatchLen - backReal);
+ Byte bitsNew, bitsOld;
+ UInt32 numSameBits = matchLen * MY_BYTE_SIZE;
+ while (true)
+ {
+ bitsNew = (byteNew & kSubNodesMask);
+ bitsOld = (byteOld & kSubNodesMask);
+ if(bitsNew != bitsOld)
+ break;
+ byteNew >>= kNumSubBits;
+ byteOld >>= kNumSubBits;
+ numSameBits += kNumSubBits;
+ }
+ node->NumSameBits = CSameBitsType(numSameBits);
+ node->Descendants[bitsNew].MatchPointer = pos + kMatchStartValue;
+ node->Descendants[bitsOld].MatchPointer = matchPointer;
+ return fullMatchLen;
+ }
+ const Byte *baseCurrentBytePointer = _buffer + pos;
+ const Byte *currentBytePointer = baseCurrentBytePointer;
+ UInt32 numLoadedBits = 0;
+ Byte curByte = 0;
+ CIndex *nodePointerPointer = &hashDescendant.NodePointer;
+ CNodePointer node = &m_Nodes[*nodePointerPointer];
+ distances += kNumHashBytes;
+ const Byte *bytePointerLimit = baseCurrentBytePointer + currentLimit;
+ const Byte *currentAddingOffset = _buffer;
+
+ #ifdef __AUTO_REMOVE
+ UInt32 lowPos;
+ if (pos > _sizeHistory)
+ lowPos = pos - _sizeHistory;
+ else
+ lowPos = 0;
+ #endif
+
+ while(true)
+ {
+ #ifdef __AUTO_REMOVE
+ if (node->LastMatch < lowPos)
+ {
+ RemoveNode(*nodePointerPointer);
+ *nodePointerPointer = pos + kMatchStartValue;
+ if (currentBytePointer == baseCurrentBytePointer)
+ return kPrevHashSize;
+ return kNumHashBytes + (UInt32)(currentBytePointer - baseCurrentBytePointer - 1);
+ }
+ #endif
+ if(numLoadedBits == 0)
+ {
+ *distances++ = pos - node->LastMatch - 1;
+ if(currentBytePointer >= bytePointerLimit)
+ {
+ for (UInt32 i = 0; i < kNumSubNodes; i++)
+ node->Descendants[i].MatchPointer = pos + kMatchStartValue;
+ node->LastMatch = pos;
+ node->NumSameBits = 0;
+ return fullCurrentLimit;
+ }
+ curByte = (*currentBytePointer++);
+ currentAddingOffset++;
+ numLoadedBits = MY_BYTE_SIZE;
+ }
+ UInt32 numSameBits = node->NumSameBits;
+ if(numSameBits > 0)
+ {
+ Byte byteXOR = ((*(currentAddingOffset + node->LastMatch -1)) >>
+ (MY_BYTE_SIZE - numLoadedBits)) ^ curByte;
+ while(numLoadedBits <= numSameBits)
+ {
+ if(byteXOR != 0)
+ {
+ AddInternalNode(node, nodePointerPointer, curByte, byteXOR,
+ numSameBits, pos);
+ return kNumHashBytes + (UInt32)(currentBytePointer - baseCurrentBytePointer - 1);
+ }
+ *distances++ = pos - node->LastMatch - 1;
+ numSameBits -= numLoadedBits;
+ if(currentBytePointer >= bytePointerLimit)
+ {
+ for (UInt32 i = 0; i < kNumSubNodes; i++)
+ node->Descendants[i].MatchPointer = pos + kMatchStartValue;
+ node->LastMatch = pos;
+ node->NumSameBits = CSameBitsType(node->NumSameBits - numSameBits);
+ return fullCurrentLimit;
+ }
+ numLoadedBits = MY_BYTE_SIZE;
+ curByte = (*currentBytePointer++);
+ byteXOR = curByte ^ (*(currentAddingOffset + node->LastMatch));
+ currentAddingOffset++;
+ }
+ if((byteXOR & ((1 << numSameBits) - 1)) != 0)
+ {
+ AddInternalNode(node, nodePointerPointer, curByte, byteXOR,
+ numSameBits, pos);
+ return kNumHashBytes + (UInt32)(currentBytePointer - baseCurrentBytePointer - 1);
+ }
+ curByte >>= numSameBits;
+ numLoadedBits -= numSameBits;
+ }
+ UInt32 descendantIndex = (curByte & kSubNodesMask);
+ numLoadedBits -= kNumSubBits;
+ nodePointerPointer = &node->Descendants[descendantIndex].NodePointer;
+ UInt32 nextNodeIndex = *nodePointerPointer;
+ node->LastMatch = pos;
+ if (nextNodeIndex < kDescendantEmptyValue)
+ {
+ curByte >>= kNumSubBits;
+ node = &m_Nodes[nextNodeIndex];
+ }
+ else if (nextNodeIndex == kDescendantEmptyValue)
+ {
+ node->Descendants[descendantIndex].MatchPointer = pos + kMatchStartValue;
+ return kNumHashBytes + (UInt32)(currentBytePointer - baseCurrentBytePointer - 1);
+ }
+ else
+ break;
+ }
+
+ UInt32 descendantIndex = (curByte & kSubNodesMask);
+ curByte >>= kNumSubBits;
+ CMatchPointer matchPointer = node->Descendants[descendantIndex].MatchPointer;
+ CMatchPointer realMatchPointer;
+ realMatchPointer = matchPointer - kMatchStartValue;
+
+ #ifdef __AUTO_REMOVE
+ if (realMatchPointer < lowPos)
+ {
+ node->Descendants[descendantIndex].MatchPointer = pos + kMatchStartValue;
+ return kNumHashBytes + (UInt32)(currentBytePointer - baseCurrentBytePointer - 1);
+ }
+ #endif
+
+ Byte byteXOR;
+ UInt32 numSameBits = 0;
+ if(numLoadedBits != 0)
+ {
+ Byte matchByte = *(currentAddingOffset + realMatchPointer -1);
+ matchByte >>= (MY_BYTE_SIZE - numLoadedBits);
+ byteXOR = matchByte ^ curByte;
+ if(byteXOR != 0)
+ {
+ AddLeafNode(node, curByte, byteXOR, numSameBits, pos, descendantIndex);
+ return kNumHashBytes + (UInt32)(currentBytePointer - baseCurrentBytePointer - 1);
+ }
+ numSameBits += numLoadedBits;
+ }
+
+ const Byte *matchBytePointer = _buffer + realMatchPointer +
+ (currentBytePointer - baseCurrentBytePointer);
+ for(; currentBytePointer < bytePointerLimit; numSameBits += MY_BYTE_SIZE)
+ {
+ curByte = (*currentBytePointer++);
+ *distances++ = pos - realMatchPointer - 1;
+ byteXOR = curByte ^ (*matchBytePointer++);
+ if(byteXOR != 0)
+ {
+ AddLeafNode(node, curByte, byteXOR, numSameBits, pos, descendantIndex);
+ return kNumHashBytes + (UInt32)(currentBytePointer - baseCurrentBytePointer - 1);
+ }
+ }
+ *distances = pos - realMatchPointer - 1;
+ node->Descendants[descendantIndex].MatchPointer = pos + kMatchStartValue;
+
+ if(*distances == 0)
+ {
+ m_SpecialMode = true;
+ m_NumNotChangedCycles = 0;
+ }
+ return fullCurrentLimit;
+}
+
+STDMETHODIMP_(void) CPatricia::DummyLongestMatch()
+{
+ GetLongestMatch(m_TmpBacks);
+}
+
+
+// ------------------------------------
+// Remove Match
+
+typedef Byte CRemoveDataWord;
+
+static const int kSizeRemoveDataWordInBits = MY_BYTE_SIZE * sizeof(CRemoveDataWord);
+
+#ifndef __AUTO_REMOVE
+
+void CPatricia::RemoveMatch()
+{
+ if(m_SpecialRemoveMode)
+ {
+ if(GetIndexByte(_matchMaxLen - 1 - _sizeHistory) ==
+ GetIndexByte(_matchMaxLen - _sizeHistory))
+ return;
+ m_SpecialRemoveMode = false;
+ }
+ UInt32 pos = _pos + kNumHashBytes - _sizeHistory;
+
+ #ifdef __HASH_3
+ const Byte *pp = _buffer + _pos - _sizeHistory;
+ UInt32 hash2Value = ((UInt32(pp[0])) << 8) | pp[1];
+ UInt32 hashValue = (hash2Value << 8) | pp[2];
+ CDescendant &hashDescendant = m_HashDescendants[hashValue];
+ CDescendant &hash2Descendant = m_Hash2Descendants[hash2Value];
+ if (hash2Descendant >= kMatchStartValue2)
+ if(hash2Descendant.MatchPointer == pos + kMatchStartValue2)
+ hash2Descendant.MatchPointer = kDescendantEmptyValue2;
+ #else
+ UInt32 hashValue = UInt32(GetIndexByte(1 - _sizeHistory)) |
+ (UInt32(GetIndexByte(0 - _sizeHistory)) << 8);
+ CDescendant &hashDescendant = m_HashDescendants[hashValue];
+ #endif
+
+ if(hashDescendant.IsEmpty())
+ return;
+ if(hashDescendant.IsMatch())
+ {
+ if(hashDescendant.MatchPointer == pos + kMatchStartValue)
+ hashDescendant.MakeEmpty();
+ return;
+ }
+
+ UInt32 descendantIndex;
+ const CRemoveDataWord *currentPointer = (const CRemoveDataWord *)(_buffer + pos);
+ UInt32 numLoadedBits = 0;
+ CRemoveDataWord curWord = 0; // = 0 to disable GCC warning
+
+ CIndex *nodePointerPointer = &hashDescendant.NodePointer;
+
+ CNodePointer node = &m_Nodes[hashDescendant.NodePointer];
+
+ while(true)
+ {
+ if(numLoadedBits == 0)
+ {
+ curWord = *currentPointer++;
+ numLoadedBits = kSizeRemoveDataWordInBits;
+ }
+ UInt32 numSameBits = node->NumSameBits;
+ if(numSameBits > 0)
+ {
+ if (numLoadedBits <= numSameBits)
+ {
+ numSameBits -= numLoadedBits;
+ currentPointer += (numSameBits / kSizeRemoveDataWordInBits);
+ numSameBits %= kSizeRemoveDataWordInBits;
+ curWord = *currentPointer++;
+ numLoadedBits = kSizeRemoveDataWordInBits;
+ }
+ curWord >>= numSameBits;
+ numLoadedBits -= numSameBits;
+ }
+ descendantIndex = (curWord & kSubNodesMask);
+ numLoadedBits -= kNumSubBits;
+ curWord >>= kNumSubBits;
+ UInt32 nextNodeIndex = node->Descendants[descendantIndex].NodePointer;
+ if (nextNodeIndex < kDescendantEmptyValue)
+ {
+ nodePointerPointer = &node->Descendants[descendantIndex].NodePointer;
+ node = &m_Nodes[nextNodeIndex];
+ }
+ else
+ break;
+ }
+ if (node->Descendants[descendantIndex].MatchPointer != pos + kMatchStartValue)
+ {
+ const Byte *currentBytePointer = _buffer + _pos - _sizeHistory;
+ const Byte *currentBytePointerLimit = currentBytePointer + _matchMaxLen;
+ for(;currentBytePointer < currentBytePointerLimit; currentBytePointer++)
+ if(*currentBytePointer != *(currentBytePointer+1))
+ return;
+ m_SpecialRemoveMode = true;
+ return;
+ }
+
+ UInt32 numNodes = 0, numMatches = 0;
+
+ UInt32 i;
+ for (i = 0; i < kNumSubNodes; i++)
+ {
+ UInt32 nodeIndex = node->Descendants[i].NodePointer;
+ if (nodeIndex < kDescendantEmptyValue)
+ numNodes++;
+ else if (nodeIndex > kDescendantEmptyValue)
+ numMatches++;
+ }
+ numMatches -= 1;
+ if (numNodes + numMatches > 1)
+ {
+ node->Descendants[descendantIndex].MakeEmpty();
+ return;
+ }
+ if(numNodes == 1)
+ {
+ UInt32 i;
+ for (i = 0; i < kNumSubNodes; i++)
+ if (node->Descendants[i].IsNode())
+ break;
+ UInt32 nextNodeIndex = node->Descendants[i].NodePointer;
+ CNodePointer nextNode = &m_Nodes[nextNodeIndex];
+ nextNode->NumSameBits += node->NumSameBits + kNumSubBits;
+ *node = *nextNode;
+
+ nextNode->NextFreeNode = m_FreeNode;
+ m_FreeNode = nextNodeIndex;
+ return;
+ }
+ UInt32 matchPointer = 0; // = 0 to disable GCC warning
+ for (i = 0; i < kNumSubNodes; i++)
+ if (node->Descendants[i].IsMatch() && i != descendantIndex)
+ {
+ matchPointer = node->Descendants[i].MatchPointer;
+ break;
+ }
+ node->NextFreeNode = m_FreeNode;
+ m_FreeNode = *nodePointerPointer;
+ *nodePointerPointer = matchPointer;
+}
+#endif
+
+
+// Commented code is more correct, but it gives warning
+// on GCC: (1 << 32)
+// So we use kMatchStartValue twice:
+// kMatchStartValue = UInt32(1) << (kNumBitsInIndex - 1);
+// must be defined in Pat.h
+/*
+const UInt32 kNormalizeStartPos = (UInt32(1) << (kNumBitsInIndex)) -
+ kMatchStartValue - kNumHashBytes - 1;
+*/
+const UInt32 kNormalizeStartPos = kMatchStartValue - kNumHashBytes - 1;
+
+STDMETHODIMP CPatricia::MovePos()
+{
+ #ifndef __AUTO_REMOVE
+ if(_pos >= _sizeHistory)
+ RemoveMatch();
+ #endif
+ RINOK(CLZInWindow::MovePos());
+ #ifdef __AUTO_REMOVE
+ if (m_NumUsedNodes >= m_NumNodes)
+ TestRemoveNodes();
+ #endif
+ if (_pos >= kNormalizeStartPos)
+ {
+ #ifdef __AUTO_REMOVE
+ TestRemoveNodesAndNormalize();
+ #else
+ Normalize();
+ #endif
+ }
+ return S_OK;
+}
+
+#ifndef __AUTO_REMOVE
+
+void CPatricia::NormalizeDescendant(CDescendant &descendant, UInt32 subValue)
+{
+ if (descendant.IsEmpty())
+ return;
+ if (descendant.IsMatch())
+ descendant.MatchPointer = descendant.MatchPointer - subValue;
+ else
+ {
+ CNode &node = m_Nodes[descendant.NodePointer];
+ node.LastMatch = node.LastMatch - subValue;
+ for (UInt32 i = 0; i < kNumSubNodes; i++)
+ NormalizeDescendant(node.Descendants[i], subValue);
+ }
+}
+
+void CPatricia::Normalize()
+{
+ UInt32 subValue = _pos - _sizeHistory;
+ CLZInWindow::ReduceOffsets(subValue);
+
+ #ifdef __HASH_3
+
+ for(UInt32 hash = 0; hash < kHash2Size; hash++)
+ {
+ CDescendant &descendant = m_Hash2Descendants[hash];
+ if (descendant.MatchPointer != kDescendantsNotInitilized2)
+ {
+ UInt32 base = hash << 8;
+ for (UInt32 i = 0; i < 0x100; i++)
+ NormalizeDescendant(m_HashDescendants[base + i], subValue);
+ }
+ if (descendant.MatchPointer < kMatchStartValue2)
+ continue;
+ descendant.MatchPointer = descendant.MatchPointer - subValue;
+ }
+
+ #else
+
+ for(UInt32 hash = 0; hash < kHashSize; hash++)
+ NormalizeDescendant(m_HashDescendants[hash], subValue);
+
+ #endif
+
+}
+
+#else
+
+void CPatricia::TestRemoveDescendant(CDescendant &descendant, UInt32 limitPos)
+{
+ CNode &node = m_Nodes[descendant.NodePointer];
+ UInt32 numChilds = 0;
+ UInt32 childIndex = 0; // = 0 to disable GCC warning
+ for (UInt32 i = 0; i < kNumSubNodes; i++)
+ {
+ CDescendant &descendant2 = node.Descendants[i];
+ if (descendant2.IsEmpty())
+ continue;
+ if (descendant2.IsMatch())
+ {
+ if (descendant2.MatchPointer < limitPos)
+ descendant2.MakeEmpty();
+ else
+ {
+ numChilds++;
+ childIndex = i;
+ }
+ }
+ else
+ {
+ TestRemoveDescendant(descendant2, limitPos);
+ if (!descendant2.IsEmpty())
+ {
+ numChilds++;
+ childIndex = i;
+ }
+ }
+ }
+ if (numChilds > 1)
+ return;
+
+ CIndex nodePointerTemp = descendant.NodePointer;
+ if (numChilds == 1)
+ {
+ const CDescendant &descendant2 = node.Descendants[childIndex];
+ if (descendant2.IsNode())
+ m_Nodes[descendant2.NodePointer].NumSameBits += node.NumSameBits + kNumSubBits;
+ descendant = descendant2;
+ }
+ else
+ descendant.MakeEmpty();
+ node.NextFreeNode = m_FreeNode;
+ m_FreeNode = nodePointerTemp;
+ m_NumUsedNodes--;
+}
+
+void CPatricia::RemoveNode(UInt32 index)
+{
+ CNode &node = m_Nodes[index];
+ for (UInt32 i = 0; i < kNumSubNodes; i++)
+ {
+ CDescendant &descendant2 = node.Descendants[i];
+ if (descendant2.IsNode())
+ RemoveNode(descendant2.NodePointer);
+ }
+ node.NextFreeNode = m_FreeNode;
+ m_FreeNode = index;
+ m_NumUsedNodes--;
+}
+
+void CPatricia::TestRemoveNodes()
+{
+ UInt32 limitPos = kMatchStartValue + _pos - _sizeHistory + kNumHashBytes;
+
+ #ifdef __HASH_3
+
+ UInt32 limitPos2 = kMatchStartValue2 + _pos - _sizeHistory + kNumHashBytes;
+ for(UInt32 hash = 0; hash < kHash2Size; hash++)
+ {
+ CDescendant &descendant = m_Hash2Descendants[hash];
+ if (descendant.MatchPointer != kDescendantsNotInitilized2)
+ {
+ UInt32 base = hash << 8;
+ for (UInt32 i = 0; i < 0x100; i++)
+ {
+ CDescendant &descendant = m_HashDescendants[base + i];
+ if (descendant.IsEmpty())
+ continue;
+ if (descendant.IsMatch())
+ {
+ if (descendant.MatchPointer < limitPos)
+ descendant.MakeEmpty();
+ }
+ else
+ TestRemoveDescendant(descendant, limitPos);
+ }
+ }
+ if (descendant.MatchPointer < kMatchStartValue2)
+ continue;
+ if (descendant.MatchPointer < limitPos2)
+ descendant.MatchPointer = kDescendantEmptyValue2;
+ }
+
+ #else
+
+ for(UInt32 hash = 0; hash < kHashSize; hash++)
+ {
+ CDescendant &descendant = m_HashDescendants[hash];
+ if (descendant.IsEmpty())
+ continue;
+ if (descendant.IsMatch())
+ {
+ if (descendant.MatchPointer < limitPos)
+ descendant.MakeEmpty();
+ }
+ else
+ TestRemoveDescendant(descendant, limitPos);
+ }
+
+ #endif
+}
+
+void CPatricia::TestRemoveAndNormalizeDescendant(CDescendant &descendant,
+ UInt32 limitPos, UInt32 subValue)
+{
+ if (descendant.IsEmpty())
+ return;
+ if (descendant.IsMatch())
+ {
+ if (descendant.MatchPointer < limitPos)
+ descendant.MakeEmpty();
+ else
+ descendant.MatchPointer = descendant.MatchPointer - subValue;
+ return;
+ }
+ CNode &node = m_Nodes[descendant.NodePointer];
+ UInt32 numChilds = 0;
+ UInt32 childIndex = 0; // = 0 to disable GCC warning
+ for (UInt32 i = 0; i < kNumSubNodes; i++)
+ {
+ CDescendant &descendant2 = node.Descendants[i];
+ TestRemoveAndNormalizeDescendant(descendant2, limitPos, subValue);
+ if (!descendant2.IsEmpty())
+ {
+ numChilds++;
+ childIndex = i;
+ }
+ }
+ if (numChilds > 1)
+ {
+ node.LastMatch = node.LastMatch - subValue;
+ return;
+ }
+
+ CIndex nodePointerTemp = descendant.NodePointer;
+ if (numChilds == 1)
+ {
+ const CDescendant &descendant2 = node.Descendants[childIndex];
+ if (descendant2.IsNode())
+ m_Nodes[descendant2.NodePointer].NumSameBits += node.NumSameBits + kNumSubBits;
+ descendant = descendant2;
+ }
+ else
+ descendant.MakeEmpty();
+ node.NextFreeNode = m_FreeNode;
+ m_FreeNode = nodePointerTemp;
+ m_NumUsedNodes--;
+}
+
+void CPatricia::TestRemoveNodesAndNormalize()
+{
+ UInt32 subValue = _pos - _sizeHistory;
+ UInt32 limitPos = kMatchStartValue + _pos - _sizeHistory + kNumHashBytes;
+ CLZInWindow::ReduceOffsets(subValue);
+
+ #ifdef __HASH_3
+
+ UInt32 limitPos2 = kMatchStartValue2 + _pos - _sizeHistory + kNumHashBytes;
+ for(UInt32 hash = 0; hash < kHash2Size; hash++)
+ {
+ CDescendant &descendant = m_Hash2Descendants[hash];
+ if (descendant.MatchPointer != kDescendantsNotInitilized2)
+ {
+ UInt32 base = hash << 8;
+ for (UInt32 i = 0; i < 0x100; i++)
+ TestRemoveAndNormalizeDescendant(m_HashDescendants[base + i], limitPos, subValue);
+ }
+ if (descendant.MatchPointer < kMatchStartValue2)
+ continue;
+ if (descendant.MatchPointer < limitPos2)
+ descendant.MatchPointer = kDescendantEmptyValue2;
+ else
+ descendant.MatchPointer = descendant.MatchPointer - subValue;
+ }
+
+ #else
+
+ for(UInt32 hash = 0; hash < kHashSize; hash++)
+ TestRemoveAndNormalizeDescendant(m_HashDescendants[hash], limitPos, subValue);
+
+ #endif
+}
+
+#endif
+
+STDMETHODIMP_(Byte) CPatricia::GetIndexByte(Int32 index)
+{
+ return CLZInWindow::GetIndexByte(index);
+}
+
+STDMETHODIMP_(UInt32) CPatricia::GetMatchLen(Int32 index, UInt32 back, UInt32 limit)
+{
+ return CLZInWindow::GetMatchLen(index, back, limit);
+}
+
+STDMETHODIMP_(UInt32) CPatricia::GetNumAvailableBytes()
+{
+ return CLZInWindow::GetNumAvailableBytes();
+}
+
+STDMETHODIMP_(const Byte *) CPatricia::GetPointerToCurrentPos()
+{
+ return CLZInWindow::GetPointerToCurrentPos();
+}
+
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/StdAfx.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/StdAfx.h new file mode 100644 index 00000000..3de038a4 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZ/StdAfx.h @@ -0,0 +1,6 @@ +// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA/LZMA.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA/LZMA.h new file mode 100644 index 00000000..d53296ee --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA/LZMA.h @@ -0,0 +1,82 @@ +// LZMA.h
+
+#ifndef __LZMA_H
+#define __LZMA_H
+
+namespace NCompress {
+namespace NLZMA {
+
+const UInt32 kNumRepDistances = 4;
+
+const int kNumStates = 12;
+
+const Byte kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5};
+const Byte kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
+const Byte kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
+const Byte kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
+
+class CState
+{
+public:
+ Byte Index;
+ void Init() { Index = 0; }
+ void UpdateChar() { Index = kLiteralNextStates[Index]; }
+ void UpdateMatch() { Index = kMatchNextStates[Index]; }
+ void UpdateRep() { Index = kRepNextStates[Index]; }
+ void UpdateShortRep() { Index = kShortRepNextStates[Index]; }
+ bool IsCharState() const { return Index < 7; }
+};
+
+const int kNumPosSlotBits = 6;
+const int kDicLogSizeMin = 0;
+const int kDicLogSizeMax = 32;
+const int kDistTableSizeMax = kDicLogSizeMax * 2;
+
+const UInt32 kNumLenToPosStates = 4;
+
+inline UInt32 GetLenToPosState(UInt32 len)
+{
+ len -= 2;
+ if (len < kNumLenToPosStates)
+ return len;
+ return kNumLenToPosStates - 1;
+}
+
+namespace NLength {
+
+const int kNumPosStatesBitsMax = 4;
+const UInt32 kNumPosStatesMax = (1 << kNumPosStatesBitsMax);
+
+const int kNumPosStatesBitsEncodingMax = 4;
+const UInt32 kNumPosStatesEncodingMax = (1 << kNumPosStatesBitsEncodingMax);
+
+const int kNumLowBits = 3;
+const int kNumMidBits = 3;
+const int kNumHighBits = 8;
+const UInt32 kNumLowSymbols = 1 << kNumLowBits;
+const UInt32 kNumMidSymbols = 1 << kNumMidBits;
+const UInt32 kNumSymbolsTotal = kNumLowSymbols + kNumMidSymbols + (1 << kNumHighBits);
+
+}
+
+const UInt32 kMatchMinLen = 2;
+const UInt32 kMatchMaxLen = kMatchMinLen + NLength::kNumSymbolsTotal - 1;
+
+const int kNumAlignBits = 4;
+const UInt32 kAlignTableSize = 1 << kNumAlignBits;
+const UInt32 kAlignMask = (kAlignTableSize - 1);
+
+const UInt32 kStartPosModelIndex = 4;
+const UInt32 kEndPosModelIndex = 14;
+const UInt32 kNumPosModels = kEndPosModelIndex - kStartPosModelIndex;
+
+const UInt32 kNumFullDistances = 1 << (kEndPosModelIndex / 2);
+
+const int kNumLitPosStatesBitsEncodingMax = 4;
+const int kNumLitContextBitsMax = 8;
+
+const int kNumMoveBits = 5;
+
+}}
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA/LZMADecoder.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA/LZMADecoder.cpp new file mode 100644 index 00000000..f672099a --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA/LZMADecoder.cpp @@ -0,0 +1,342 @@ +// LZMADecoder.cpp
+
+#include "StdAfx.h"
+
+#include "LZMADecoder.h"
+#include "../../../Common/Defs.h"
+
+namespace NCompress {
+namespace NLZMA {
+
+const int kLenIdFinished = -1;
+const int kLenIdNeedInit = -2;
+
+void CDecoder::Init()
+{
+ {
+ for(int i = 0; i < kNumStates; i++)
+ {
+ for (UInt32 j = 0; j <= _posStateMask; j++)
+ {
+ _isMatch[i][j].Init();
+ _isRep0Long[i][j].Init();
+ }
+ _isRep[i].Init();
+ _isRepG0[i].Init();
+ _isRepG1[i].Init();
+ _isRepG2[i].Init();
+ }
+ }
+ {
+ for (UInt32 i = 0; i < kNumLenToPosStates; i++)
+ _posSlotDecoder[i].Init();
+ }
+ {
+ for(UInt32 i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
+ _posDecoders[i].Init();
+ }
+ _posAlignDecoder.Init();
+ _lenDecoder.Init(_posStateMask + 1);
+ _repMatchLenDecoder.Init(_posStateMask + 1);
+ _literalDecoder.Init();
+
+ _state.Init();
+ _reps[0] = _reps[1] = _reps[2] = _reps[3] = 0;
+}
+
+HRESULT CDecoder::CodeSpec(UInt32 curSize)
+{
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _outWindowStream.GetProcessedSize();
+ if (curSize > rem)
+ curSize = (UInt32)rem;
+ }
+
+ if (_remainLen == kLenIdFinished)
+ return S_OK;
+ if (_remainLen == kLenIdNeedInit)
+ {
+ _rangeDecoder.Init();
+ Init();
+ _remainLen = 0;
+ }
+ if (curSize == 0)
+ return S_OK;
+
+ UInt32 rep0 = _reps[0];
+ UInt32 rep1 = _reps[1];
+ UInt32 rep2 = _reps[2];
+ UInt32 rep3 = _reps[3];
+ CState state = _state;
+ Byte previousByte;
+
+ while(_remainLen > 0 && curSize > 0)
+ {
+ previousByte = _outWindowStream.GetByte(rep0);
+ _outWindowStream.PutByte(previousByte);
+ _remainLen--;
+ curSize--;
+ }
+ UInt64 nowPos64 = _outWindowStream.GetProcessedSize();
+ if (nowPos64 == 0)
+ previousByte = 0;
+ else
+ previousByte = _outWindowStream.GetByte(0);
+
+ while(curSize > 0)
+ {
+ {
+ #ifdef _NO_EXCEPTIONS
+ if (_rangeDecoder.Stream.ErrorCode != S_OK)
+ return _rangeDecoder.Stream.ErrorCode;
+ #endif
+ if (_rangeDecoder.Stream.WasFinished())
+ return S_FALSE;
+ UInt32 posState = UInt32(nowPos64) & _posStateMask;
+ if (_isMatch[state.Index][posState].Decode(&_rangeDecoder) == 0)
+ {
+ if(!state.IsCharState())
+ previousByte = _literalDecoder.DecodeWithMatchByte(&_rangeDecoder,
+ (UInt32)nowPos64, previousByte, _outWindowStream.GetByte(rep0));
+ else
+ previousByte = _literalDecoder.DecodeNormal(&_rangeDecoder,
+ (UInt32)nowPos64, previousByte);
+ _outWindowStream.PutByte(previousByte);
+ state.UpdateChar();
+ curSize--;
+ nowPos64++;
+ }
+ else
+ {
+ UInt32 len;
+ if(_isRep[state.Index].Decode(&_rangeDecoder) == 1)
+ {
+ len = 0;
+ if(_isRepG0[state.Index].Decode(&_rangeDecoder) == 0)
+ {
+ if(_isRep0Long[state.Index][posState].Decode(&_rangeDecoder) == 0)
+ {
+ state.UpdateShortRep();
+ len = 1;
+ }
+ }
+ else
+ {
+ UInt32 distance;
+ if(_isRepG1[state.Index].Decode(&_rangeDecoder) == 0)
+ distance = rep1;
+ else
+ {
+ if (_isRepG2[state.Index].Decode(&_rangeDecoder) == 0)
+ distance = rep2;
+ else
+ {
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ if (len == 0)
+ {
+ len = _repMatchLenDecoder.Decode(&_rangeDecoder, posState) + kMatchMinLen;
+ state.UpdateRep();
+ }
+ }
+ else
+ {
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ len = kMatchMinLen + _lenDecoder.Decode(&_rangeDecoder, posState);
+ state.UpdateMatch();
+ UInt32 posSlot = _posSlotDecoder[GetLenToPosState(len)].Decode(&_rangeDecoder);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ UInt32 numDirectBits = (posSlot >> 1) - 1;
+ rep0 = ((2 | (posSlot & 1)) << numDirectBits);
+
+ if (posSlot < kEndPosModelIndex)
+ rep0 += NRangeCoder::ReverseBitTreeDecode(_posDecoders +
+ rep0 - posSlot - 1, &_rangeDecoder, numDirectBits);
+ else
+ {
+ rep0 += (_rangeDecoder.DecodeDirectBits(
+ numDirectBits - kNumAlignBits) << kNumAlignBits);
+ rep0 += _posAlignDecoder.ReverseDecode(&_rangeDecoder);
+ if (rep0 == 0xFFFFFFFF)
+ {
+ _remainLen = kLenIdFinished;
+ return S_OK;
+ }
+ }
+ }
+ else
+ rep0 = posSlot;
+ }
+ UInt32 locLen = len;
+ if (len > curSize)
+ locLen = (UInt32)curSize;
+ if (!_outWindowStream.CopyBlock(rep0, locLen))
+ return S_FALSE;
+ previousByte = _outWindowStream.GetByte(0);
+ curSize -= locLen;
+ nowPos64 += locLen;
+ len -= locLen;
+ if (len != 0)
+ {
+ _remainLen = (Int32)len;
+ break;
+ }
+
+ #ifdef _NO_EXCEPTIONS
+ if (_outWindowStream.ErrorCode != S_OK)
+ return _outWindowStream.ErrorCode;
+ #endif
+ }
+ }
+ }
+ if (_rangeDecoder.Stream.WasFinished())
+ return S_FALSE;
+ _reps[0] = rep0;
+ _reps[1] = rep1;
+ _reps[2] = rep2;
+ _reps[3] = rep3;
+ _state = state;
+
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::CodeReal(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream,
+ const UInt64 *, const UInt64 *outSize,
+ ICompressProgressInfo *progress)
+{
+ SetInStream(inStream);
+ _outWindowStream.SetStream(outStream);
+ SetOutStreamSize(outSize);
+ CDecoderFlusher flusher(this);
+
+ while (true)
+ {
+ UInt32 curSize = 1 << 18;
+ RINOK(CodeSpec(curSize));
+ if (_remainLen == kLenIdFinished)
+ break;
+ if (progress != NULL)
+ {
+ UInt64 inSize = _rangeDecoder.GetProcessedSize();
+ UInt64 nowPos64 = _outWindowStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
+ }
+ if (_outSizeDefined)
+ if (_outWindowStream.GetProcessedSize() >= _outSize)
+ break;
+ }
+ flusher.NeedFlush = false;
+ return Flush();
+}
+
+
+#ifdef _NO_EXCEPTIONS
+
+#define LZMA_TRY_BEGIN
+#define LZMA_TRY_END
+
+#else
+
+#define LZMA_TRY_BEGIN try {
+#define LZMA_TRY_END } \
+ catch(const CInBufferException &e) { return e.ErrorCode; } \
+ catch(const CLZOutWindowException &e) { return e.ErrorCode; } \
+ catch(...) { return S_FALSE; }
+
+#endif
+
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress)
+{
+ LZMA_TRY_BEGIN
+ return CodeReal(inStream, outStream, inSize, outSize, progress);
+ LZMA_TRY_END
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *properties, UInt32 size)
+{
+ if (size < 5)
+ return E_INVALIDARG;
+ int lc = properties[0] % 9;
+ Byte remainder = (Byte)(properties[0] / 9);
+ int lp = remainder % 5;
+ int pb = remainder / 5;
+ UInt32 dictionarySize = 0;
+ for (int i = 0; i < 4; i++)
+ dictionarySize += ((UInt32)(properties[1 + i])) << (i * 8);
+ return SetDecoderPropertiesRaw(lc, lp, pb, dictionarySize);
+}
+
+STDMETHODIMP CDecoder::SetDecoderPropertiesRaw(int lc, int lp, int pb, UInt32 dictionarySize)
+{
+ if (pb > NLength::kNumPosStatesBitsMax)
+ return E_INVALIDARG;
+ _posStateMask = (1 << pb) - 1;
+ if (!_outWindowStream.Create(dictionarySize))
+ return E_OUTOFMEMORY;
+ if (!_literalDecoder.Create(lp, lc))
+ return E_OUTOFMEMORY;
+ if (!_rangeDecoder.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
+{
+ *value = _rangeDecoder.GetProcessedSize();
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
+{
+ _rangeDecoder.SetStream(inStream);
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::ReleaseInStream()
+{
+ _rangeDecoder.ReleaseStream();
+ return S_OK;
+}
+
+STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
+{
+ if (_outSizeDefined = (outSize != NULL))
+ _outSize = *outSize;
+ _remainLen = kLenIdNeedInit;
+ _outWindowStream.Init();
+ return S_OK;
+}
+
+#ifdef _ST_MODE
+
+STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ LZMA_TRY_BEGIN
+ if (processedSize)
+ *processedSize = 0;
+ const UInt64 startPos = _outWindowStream.GetProcessedSize();
+ _outWindowStream.SetMemStream((Byte *)data);
+ RINOK(CodeSpec(size));
+ if (processedSize)
+ *processedSize = (UInt32)(_outWindowStream.GetProcessedSize() - startPos);
+ return Flush();
+ LZMA_TRY_END
+}
+
+#endif
+
+}}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA/LZMADecoder.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA/LZMADecoder.h new file mode 100644 index 00000000..6f5f7ecc --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA/LZMADecoder.h @@ -0,0 +1,249 @@ +// LZMA/Decoder.h
+
+#ifndef __LZMA_DECODER_H
+#define __LZMA_DECODER_H
+
+#include "../../../Common/MyCom.h"
+#include "../../../Common/Alloc.h"
+#include "../../ICoder.h"
+#include "../LZ/LZOutWindow.h"
+#include "../RangeCoder/RangeCoderBitTree.h"
+
+#include "LZMA.h"
+
+namespace NCompress {
+namespace NLZMA {
+
+typedef NRangeCoder::CBitDecoder<kNumMoveBits> CMyBitDecoder;
+
+class CLiteralDecoder2
+{
+ CMyBitDecoder _decoders[0x300];
+public:
+ void Init()
+ {
+ for (int i = 0; i < 0x300; i++)
+ _decoders[i].Init();
+ }
+ Byte DecodeNormal(NRangeCoder::CDecoder *rangeDecoder)
+ {
+ UInt32 symbol = 1;
+ RC_INIT_VAR
+ do
+ {
+ // symbol = (symbol << 1) | _decoders[0][symbol].Decode(rangeDecoder);
+ RC_GETBIT(kNumMoveBits, _decoders[symbol].Prob, symbol)
+ }
+ while (symbol < 0x100);
+ RC_FLUSH_VAR
+ return (Byte)symbol;
+ }
+ Byte DecodeWithMatchByte(NRangeCoder::CDecoder *rangeDecoder, Byte matchByte)
+ {
+ UInt32 symbol = 1;
+ RC_INIT_VAR
+ do
+ {
+ UInt32 matchBit = (matchByte >> 7) & 1;
+ matchByte <<= 1;
+ // UInt32 bit = _decoders[1 + matchBit][symbol].Decode(rangeDecoder);
+ // symbol = (symbol << 1) | bit;
+ UInt32 bit;
+ RC_GETBIT2(kNumMoveBits, _decoders[0x100 + (matchBit << 8) + symbol].Prob, symbol,
+ bit = 0, bit = 1)
+ if (matchBit != bit)
+ {
+ while (symbol < 0x100)
+ {
+ // symbol = (symbol << 1) | _decoders[0][symbol].Decode(rangeDecoder);
+ RC_GETBIT(kNumMoveBits, _decoders[symbol].Prob, symbol)
+ }
+ break;
+ }
+ }
+ while (symbol < 0x100);
+ RC_FLUSH_VAR
+ return (Byte)symbol;
+ }
+};
+
+class CLiteralDecoder
+{
+ CLiteralDecoder2 *_coders;
+ int _numPrevBits;
+ int _numPosBits;
+ UInt32 _posMask;
+public:
+ CLiteralDecoder(): _coders(0) {}
+ ~CLiteralDecoder() { Free(); }
+ void Free()
+ {
+ MyFree(_coders);
+ _coders = 0;
+ }
+ bool Create(int numPosBits, int numPrevBits)
+ {
+ if (_coders == 0 || (numPosBits + numPrevBits) !=
+ (_numPrevBits + _numPosBits) )
+ {
+ Free();
+ UInt32 numStates = 1 << (numPosBits + numPrevBits);
+ _coders = (CLiteralDecoder2 *)MyAlloc(numStates * sizeof(CLiteralDecoder2));
+ }
+ _numPosBits = numPosBits;
+ _posMask = (1 << numPosBits) - 1;
+ _numPrevBits = numPrevBits;
+ return (_coders != 0);
+ }
+ void Init()
+ {
+ UInt32 numStates = 1 << (_numPrevBits + _numPosBits);
+ for (UInt32 i = 0; i < numStates; i++)
+ _coders[i].Init();
+ }
+ UInt32 GetState(UInt32 pos, Byte prevByte) const
+ { return ((pos & _posMask) << _numPrevBits) + (prevByte >> (8 - _numPrevBits)); }
+ Byte DecodeNormal(NRangeCoder::CDecoder *rangeDecoder, UInt32 pos, Byte prevByte)
+ { return _coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); }
+ Byte DecodeWithMatchByte(NRangeCoder::CDecoder *rangeDecoder, UInt32 pos, Byte prevByte, Byte matchByte)
+ { return _coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); }
+};
+
+namespace NLength {
+
+class CDecoder
+{
+ CMyBitDecoder _choice;
+ CMyBitDecoder _choice2;
+ NRangeCoder::CBitTreeDecoder<kNumMoveBits, kNumLowBits> _lowCoder[kNumPosStatesMax];
+ NRangeCoder::CBitTreeDecoder<kNumMoveBits, kNumMidBits> _midCoder[kNumPosStatesMax];
+ NRangeCoder::CBitTreeDecoder<kNumMoveBits, kNumHighBits> _highCoder;
+public:
+ void Init(UInt32 numPosStates)
+ {
+ _choice.Init();
+ _choice2.Init();
+ for (UInt32 posState = 0; posState < numPosStates; posState++)
+ {
+ _lowCoder[posState].Init();
+ _midCoder[posState].Init();
+ }
+ _highCoder.Init();
+ }
+ UInt32 Decode(NRangeCoder::CDecoder *rangeDecoder, UInt32 posState)
+ {
+ if(_choice.Decode(rangeDecoder) == 0)
+ return _lowCoder[posState].Decode(rangeDecoder);
+ if(_choice2.Decode(rangeDecoder) == 0)
+ return kNumLowSymbols + _midCoder[posState].Decode(rangeDecoder);
+ return kNumLowSymbols + kNumMidSymbols + _highCoder.Decode(rangeDecoder);
+ }
+};
+
+}
+
+class CDecoder:
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ #ifdef _ST_MODE
+ public ICompressSetInStream,
+ public ICompressSetOutStreamSize,
+ public ISequentialInStream,
+ #endif
+ public CMyUnknownImp
+{
+ CLZOutWindow _outWindowStream;
+ NRangeCoder::CDecoder _rangeDecoder;
+
+ CMyBitDecoder _isMatch[kNumStates][NLength::kNumPosStatesMax];
+ CMyBitDecoder _isRep[kNumStates];
+ CMyBitDecoder _isRepG0[kNumStates];
+ CMyBitDecoder _isRepG1[kNumStates];
+ CMyBitDecoder _isRepG2[kNumStates];
+ CMyBitDecoder _isRep0Long[kNumStates][NLength::kNumPosStatesMax];
+
+ NRangeCoder::CBitTreeDecoder<kNumMoveBits, kNumPosSlotBits> _posSlotDecoder[kNumLenToPosStates];
+
+ CMyBitDecoder _posDecoders[kNumFullDistances - kEndPosModelIndex];
+ NRangeCoder::CBitTreeDecoder<kNumMoveBits, kNumAlignBits> _posAlignDecoder;
+
+ NLength::CDecoder _lenDecoder;
+ NLength::CDecoder _repMatchLenDecoder;
+
+ CLiteralDecoder _literalDecoder;
+
+ UInt32 _posStateMask;
+
+ ///////////////////
+ // State
+ UInt32 _reps[4];
+ CState _state;
+ Int32 _remainLen; // -1 means end of stream. // -2 means need Init
+ UInt64 _outSize;
+ bool _outSizeDefined;
+
+ void Init();
+ HRESULT CodeSpec(UInt32 size);
+public:
+
+ #ifdef _ST_MODE
+ MY_UNKNOWN_IMP4(
+ ICompressSetDecoderProperties2,
+ ICompressSetInStream,
+ ICompressSetOutStreamSize,
+ ISequentialInStream)
+ #else
+ MY_UNKNOWN_IMP1(
+ ICompressSetDecoderProperties2)
+ #endif
+
+ void ReleaseStreams()
+ {
+ _outWindowStream.ReleaseStream();
+ ReleaseInStream();
+ }
+
+ class CDecoderFlusher
+ {
+ CDecoder *_decoder;
+ public:
+ bool NeedFlush;
+ CDecoderFlusher(CDecoder *decoder): _decoder(decoder), NeedFlush(true) {}
+ ~CDecoderFlusher()
+ {
+ if (NeedFlush)
+ _decoder->Flush();
+ _decoder->ReleaseStreams();
+ }
+ };
+
+ HRESULT Flush() { return _outWindowStream.Flush(); }
+
+ STDMETHOD(CodeReal)(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress);
+
+ STDMETHOD(Code)(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress);
+
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+ STDMETHOD(SetDecoderPropertiesRaw)(int lc, int lp, int pb, UInt32 dictionarySize);
+
+ STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
+
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream);
+ STDMETHOD(ReleaseInStream)();
+ STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
+
+ #ifdef _ST_MODE
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ #endif
+
+ CDecoder(): _outSizeDefined(false) {}
+ virtual ~CDecoder() {}
+};
+
+}}
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA/LZMAEncoder.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA/LZMAEncoder.cpp new file mode 100644 index 00000000..4f20ed5a --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA/LZMAEncoder.cpp @@ -0,0 +1,1504 @@ +// LZMA/Encoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/Defs.h"
+#include "../../Common/StreamUtils.h"
+
+#include "LZMAEncoder.h"
+
+// for minimal compressing code size define these:
+// #define COMPRESS_MF_BT
+// #define COMPRESS_MF_BT4
+
+#if !defined(COMPRESS_MF_BT) && !defined(COMPRESS_MF_PAT) && !defined(COMPRESS_MF_HC)
+#define COMPRESS_MF_BT
+#define COMPRESS_MF_PAT
+#define COMPRESS_MF_HC
+#endif
+
+#ifdef COMPRESS_MF_BT
+#if !defined(COMPRESS_MF_BT2) && !defined(COMPRESS_MF_BT3) && !defined(COMPRESS_MF_BT4) && !defined(COMPRESS_MF_BT4B)
+#define COMPRESS_MF_BT2
+#define COMPRESS_MF_BT3
+#define COMPRESS_MF_BT4
+#define COMPRESS_MF_BT4B
+#endif
+#ifdef COMPRESS_MF_BT2
+#include "../LZ/BinTree/BinTree2.h"
+#endif
+#ifdef COMPRESS_MF_BT3
+#include "../LZ/BinTree/BinTree3.h"
+#endif
+#ifdef COMPRESS_MF_BT4
+#include "../LZ/BinTree/BinTree4.h"
+#endif
+#ifdef COMPRESS_MF_BT4B
+#include "../LZ/BinTree/BinTree4b.h"
+#endif
+#endif
+
+#ifdef COMPRESS_MF_PAT
+#include "../LZ/Patricia/Pat2.h"
+#include "../LZ/Patricia/Pat2H.h"
+#include "../LZ/Patricia/Pat3H.h"
+#include "../LZ/Patricia/Pat4H.h"
+#include "../LZ/Patricia/Pat2R.h"
+#endif
+
+#ifdef COMPRESS_MF_HC
+#include "../LZ/HashChain/HC3.h"
+#include "../LZ/HashChain/HC4.h"
+#endif
+
+#ifdef COMPRESS_MF_MT
+#include "../LZ/MT/MT.h"
+#endif
+
+namespace NCompress {
+namespace NLZMA {
+
+const int kDefaultDictionaryLogSize = 20;
+const UInt32 kNumFastBytesDefault = 0x20;
+
+enum
+{
+ kBT2,
+ kBT3,
+ kBT4,
+ kBT4B,
+ kPat2,
+ kPat2H,
+ kPat3H,
+ kPat4H,
+ kPat2R,
+ kHC3,
+ kHC4
+};
+
+static const wchar_t *kMatchFinderIDs[] =
+{
+ L"BT2",
+ L"BT3",
+ L"BT4",
+ L"BT4B",
+ L"PAT2",
+ L"PAT2H",
+ L"PAT3H",
+ L"PAT4H",
+ L"PAT2R",
+ L"HC3",
+ L"HC4"
+};
+
+Byte g_FastPos[1024];
+
+class CFastPosInit
+{
+public:
+ CFastPosInit() { Init(); }
+ void Init()
+ {
+ const Byte kFastSlots = 20;
+ int c = 2;
+ g_FastPos[0] = 0;
+ g_FastPos[1] = 1;
+
+ for (Byte slotFast = 2; slotFast < kFastSlots; slotFast++)
+ {
+ UInt32 k = (1 << ((slotFast >> 1) - 1));
+ for (UInt32 j = 0; j < k; j++, c++)
+ g_FastPos[c] = slotFast;
+ }
+ }
+} g_FastPosInit;
+
+
+void CLiteralEncoder2::Encode(NRangeCoder::CEncoder *rangeEncoder, Byte symbol)
+{
+ UInt32 context = 1;
+ int i = 8;
+ do
+ {
+ i--;
+ UInt32 bit = (symbol >> i) & 1;
+ _encoders[context].Encode(rangeEncoder, bit);
+ context = (context << 1) | bit;
+ }
+ while(i != 0);
+}
+
+void CLiteralEncoder2::EncodeMatched(NRangeCoder::CEncoder *rangeEncoder,
+ Byte matchByte, Byte symbol)
+{
+ UInt32 context = 1;
+ int i = 8;
+ do
+ {
+ i--;
+ UInt32 bit = (symbol >> i) & 1;
+ UInt32 matchBit = (matchByte >> i) & 1;
+ _encoders[0x100 + (matchBit << 8) + context].Encode(rangeEncoder, bit);
+ context = (context << 1) | bit;
+ if (matchBit != bit)
+ {
+ while(i != 0)
+ {
+ i--;
+ UInt32 bit = (symbol >> i) & 1;
+ _encoders[context].Encode(rangeEncoder, bit);
+ context = (context << 1) | bit;
+ }
+ break;
+ }
+ }
+ while(i != 0);
+}
+
+UInt32 CLiteralEncoder2::GetPrice(bool matchMode, Byte matchByte, Byte symbol) const
+{
+ UInt32 price = 0;
+ UInt32 context = 1;
+ int i = 8;
+ if (matchMode)
+ {
+ do
+ {
+ i--;
+ UInt32 matchBit = (matchByte >> i) & 1;
+ UInt32 bit = (symbol >> i) & 1;
+ price += _encoders[0x100 + (matchBit << 8) + context].GetPrice(bit);
+ context = (context << 1) | bit;
+ if (matchBit != bit)
+ break;
+ }
+ while (i != 0);
+ }
+ while(i != 0)
+ {
+ i--;
+ UInt32 bit = (symbol >> i) & 1;
+ price += _encoders[context].GetPrice(bit);
+ context = (context << 1) | bit;
+ }
+ return price;
+};
+
+
+namespace NLength {
+
+void CEncoder::Init(UInt32 numPosStates)
+{
+ _choice.Init();
+ _choice2.Init();
+ for (UInt32 posState = 0; posState < numPosStates; posState++)
+ {
+ _lowCoder[posState].Init();
+ _midCoder[posState].Init();
+ }
+ _highCoder.Init();
+}
+
+void CEncoder::Encode(NRangeCoder::CEncoder *rangeEncoder, UInt32 symbol, UInt32 posState)
+{
+ if(symbol < kNumLowSymbols)
+ {
+ _choice.Encode(rangeEncoder, 0);
+ _lowCoder[posState].Encode(rangeEncoder, symbol);
+ }
+ else
+ {
+ _choice.Encode(rangeEncoder, 1);
+ if(symbol < kNumLowSymbols + kNumMidSymbols)
+ {
+ _choice2.Encode(rangeEncoder, 0);
+ _midCoder[posState].Encode(rangeEncoder, symbol - kNumLowSymbols);
+ }
+ else
+ {
+ _choice2.Encode(rangeEncoder, 1);
+ _highCoder.Encode(rangeEncoder, symbol - kNumLowSymbols - kNumMidSymbols);
+ }
+ }
+}
+
+UInt32 CEncoder::GetPrice(UInt32 symbol, UInt32 posState) const
+{
+ if(symbol < kNumLowSymbols)
+ return _choice.GetPrice0() + _lowCoder[posState].GetPrice(symbol);
+ UInt32 price = _choice.GetPrice1();
+ if(symbol < kNumLowSymbols + kNumMidSymbols)
+ {
+ price += _choice2.GetPrice0();
+ price += _midCoder[posState].GetPrice(symbol - kNumLowSymbols);
+ }
+ else
+ {
+ price += _choice2.GetPrice1();
+ price += _highCoder.GetPrice(symbol - kNumLowSymbols - kNumMidSymbols);
+ }
+ return price;
+}
+
+}
+CEncoder::CEncoder():
+ _numFastBytes(kNumFastBytesDefault),
+ _distTableSize(kDefaultDictionaryLogSize * 2),
+ _posStateBits(2),
+ _posStateMask(4 - 1),
+ _numLiteralPosStateBits(0),
+ _numLiteralContextBits(3),
+ _dictionarySize(1 << kDefaultDictionaryLogSize),
+ _dictionarySizePrev(UInt32(-1)),
+ _numFastBytesPrev(UInt32(-1)),
+ _matchFinderIndex(kBT4),
+ #ifdef COMPRESS_MF_MT
+ _multiThread(false),
+ #endif
+ _writeEndMark(false)
+{
+ _maxMode = false;
+ _fastMode = false;
+}
+
+HRESULT CEncoder::Create()
+{
+ if (!_rangeEncoder.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ if (!_matchFinder)
+ {
+ switch(_matchFinderIndex)
+ {
+ #ifdef COMPRESS_MF_BT
+ #ifdef COMPRESS_MF_BT2
+ case kBT2:
+ _matchFinder = new NBT2::CMatchFinderBinTree;
+ break;
+ #endif
+ #ifdef COMPRESS_MF_BT3
+ case kBT3:
+ _matchFinder = new NBT3::CMatchFinderBinTree;
+ break;
+ #endif
+ #ifdef COMPRESS_MF_BT4
+ case kBT4:
+ _matchFinder = new NBT4::CMatchFinderBinTree;
+ break;
+ #endif
+ #ifdef COMPRESS_MF_BT4B
+ case kBT4B:
+ _matchFinder = new NBT4B::CMatchFinderBinTree;
+ break;
+ #endif
+ #endif
+
+ #ifdef COMPRESS_MF_PAT
+ case kPat2:
+ _matchFinder = new NPat2::CPatricia;
+ break;
+ case kPat2H:
+ _matchFinder = new NPat2H::CPatricia;
+ break;
+ case kPat3H:
+ _matchFinder = new NPat3H::CPatricia;
+ break;
+ case kPat4H:
+ _matchFinder = new NPat4H::CPatricia;
+ break;
+ case kPat2R:
+ _matchFinder = new NPat2R::CPatricia;
+ break;
+ #endif
+
+ #ifdef COMPRESS_MF_HC
+ case kHC3:
+ _matchFinder = new NHC3::CMatchFinderHC;
+ break;
+ case kHC4:
+ _matchFinder = new NHC4::CMatchFinderHC;
+ break;
+ #endif
+ }
+ if (_matchFinder == 0)
+ return E_OUTOFMEMORY;
+
+ #ifdef COMPRESS_MF_MT
+ if (_multiThread && !(_fastMode && (_matchFinderIndex == kHC3 || _matchFinderIndex == kHC4)))
+ {
+ CMatchFinderMT *mfSpec = new CMatchFinderMT;
+ if (mfSpec == 0)
+ return E_OUTOFMEMORY;
+ CMyComPtr<IMatchFinder> mf = mfSpec;
+ RINOK(mfSpec->SetMatchFinder(_matchFinder));
+ _matchFinder.Release();
+ _matchFinder = mf;
+ }
+ #endif
+ }
+
+ if (!_literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits))
+ return E_OUTOFMEMORY;
+
+ if (_dictionarySize == _dictionarySizePrev && _numFastBytesPrev == _numFastBytes)
+ return S_OK;
+ RINOK(_matchFinder->Create(_dictionarySize, kNumOpts, _numFastBytes,
+ kMatchMaxLen * 2 + 1 - _numFastBytes));
+ _dictionarySizePrev = _dictionarySize;
+ _numFastBytesPrev = _numFastBytes;
+ return S_OK;
+}
+
+static bool AreStringsEqual(const wchar_t *base, const wchar_t *testString)
+{
+ while (true)
+ {
+ wchar_t c = *testString;
+ if (c >= 'a' && c <= 'z')
+ c -= 0x20;
+ if (*base != c)
+ return false;
+ if (c == 0)
+ return true;
+ base++;
+ testString++;
+ }
+}
+
+static int FindMatchFinder(const wchar_t *s)
+{
+ for (int m = 0; m < (int)(sizeof(kMatchFinderIDs) / sizeof(kMatchFinderIDs[0])); m++)
+ if (AreStringsEqual(kMatchFinderIDs[m], s))
+ return m;
+ return -1;
+}
+
+STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
+ const PROPVARIANT *properties, UInt32 numProperties)
+{
+ for (UInt32 i = 0; i < numProperties; i++)
+ {
+ const PROPVARIANT &prop = properties[i];
+ switch(propIDs[i])
+ {
+ case NCoderPropID::kNumFastBytes:
+ {
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 numFastBytes = prop.ulVal;
+ if(numFastBytes < 5 || numFastBytes > kMatchMaxLen)
+ return E_INVALIDARG;
+ _numFastBytes = numFastBytes;
+ break;
+ }
+ case NCoderPropID::kAlgorithm:
+ {
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 maximize = prop.ulVal;
+ _fastMode = (maximize == 0);
+ _maxMode = (maximize >= 2);
+ break;
+ }
+ case NCoderPropID::kMatchFinder:
+ {
+ if (prop.vt != VT_BSTR)
+ return E_INVALIDARG;
+ int matchFinderIndexPrev = _matchFinderIndex;
+ int m = FindMatchFinder(prop.bstrVal);
+ if (m < 0)
+ return E_INVALIDARG;
+ _matchFinderIndex = m;
+ if (_matchFinder && matchFinderIndexPrev != _matchFinderIndex)
+ {
+ _dictionarySizePrev = UInt32(-1);
+ _matchFinder.Release();
+ }
+ break;
+ }
+ #ifdef COMPRESS_MF_MT
+ case NCoderPropID::kMultiThread:
+ {
+ if (prop.vt != VT_BOOL)
+ return E_INVALIDARG;
+ bool newMultiThread = (prop.boolVal == VARIANT_TRUE);
+ if (newMultiThread != _multiThread)
+ {
+ _dictionarySizePrev = UInt32(-1);
+ _matchFinder.Release();
+ }
+ _multiThread = newMultiThread;
+ break;
+ }
+ #endif
+ case NCoderPropID::kDictionarySize:
+ {
+ const int kDicLogSizeMaxCompress = 28;
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 dictionarySize = prop.ulVal;
+ if (dictionarySize < UInt32(1 << kDicLogSizeMin) ||
+ dictionarySize > UInt32(1 << kDicLogSizeMaxCompress))
+ return E_INVALIDARG;
+ _dictionarySize = dictionarySize;
+ UInt32 dicLogSize;
+ for(dicLogSize = 0; dicLogSize < (UInt32)kDicLogSizeMaxCompress; dicLogSize++)
+ if (dictionarySize <= (UInt32(1) << dicLogSize))
+ break;
+ _distTableSize = dicLogSize * 2;
+ break;
+ }
+ case NCoderPropID::kPosStateBits:
+ {
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 value = prop.ulVal;
+ if (value > (UInt32)NLength::kNumPosStatesBitsEncodingMax)
+ return E_INVALIDARG;
+ _posStateBits = value;
+ _posStateMask = (1 << _posStateBits) - 1;
+ break;
+ }
+ case NCoderPropID::kLitPosBits:
+ {
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 value = prop.ulVal;
+ if (value > (UInt32)kNumLitPosStatesBitsEncodingMax)
+ return E_INVALIDARG;
+ _numLiteralPosStateBits = value;
+ break;
+ }
+ case NCoderPropID::kLitContextBits:
+ {
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 value = prop.ulVal;
+ if (value > (UInt32)kNumLitContextBitsMax)
+ return E_INVALIDARG;
+ _numLiteralContextBits = value;
+ break;
+ }
+ case NCoderPropID::kEndMarker:
+ {
+ if (prop.vt != VT_BOOL)
+ return E_INVALIDARG;
+ SetWriteEndMarkerMode(prop.boolVal == VARIANT_TRUE);
+ break;
+ }
+ default:
+ return E_INVALIDARG;
+ }
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
+{
+ const UInt32 kPropSize = 5;
+ Byte properties[kPropSize];
+ properties[0] = (_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits;
+ for (int i = 0; i < 4; i++)
+ properties[1 + i] = Byte(_dictionarySize >> (8 * i));
+ return WriteStream(outStream, properties, kPropSize, NULL);
+}
+
+STDMETHODIMP CEncoder::SetOutStream(ISequentialOutStream *outStream)
+{
+ _rangeEncoder.SetStream(outStream);
+ return S_OK;
+}
+
+STDMETHODIMP CEncoder::ReleaseOutStream()
+{
+ _rangeEncoder.ReleaseStream();
+ return S_OK;
+}
+
+HRESULT CEncoder::Init()
+{
+ CBaseState::Init();
+
+ // RINOK(_matchFinder->Init(inStream));
+ _rangeEncoder.Init();
+
+ for(int i = 0; i < kNumStates; i++)
+ {
+ for (UInt32 j = 0; j <= _posStateMask; j++)
+ {
+ _isMatch[i][j].Init();
+ _isRep0Long[i][j].Init();
+ }
+ _isRep[i].Init();
+ _isRepG0[i].Init();
+ _isRepG1[i].Init();
+ _isRepG2[i].Init();
+ }
+
+ _literalEncoder.Init();
+
+ // _repMatchLenEncoder.Init();
+
+ {
+ for(UInt32 i = 0; i < kNumLenToPosStates; i++)
+ _posSlotEncoder[i].Init();
+ }
+ {
+ for(UInt32 i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
+ _posEncoders[i].Init();
+ }
+
+ _lenEncoder.Init(1 << _posStateBits);
+ _repMatchLenEncoder.Init(1 << _posStateBits);
+
+ _posAlignEncoder.Init();
+
+ _longestMatchWasFound = false;
+ _optimumEndIndex = 0;
+ _optimumCurrentIndex = 0;
+ _additionalOffset = 0;
+
+ return S_OK;
+}
+
+HRESULT CEncoder::MovePos(UInt32 num)
+{
+ for (;num != 0; num--)
+ {
+ _matchFinder->DummyLongestMatch();
+ RINOK(_matchFinder->MovePos());
+ _additionalOffset++;
+ }
+ return S_OK;
+}
+
+UInt32 CEncoder::Backward(UInt32 &backRes, UInt32 cur)
+{
+ _optimumEndIndex = cur;
+ UInt32 posMem = _optimum[cur].PosPrev;
+ UInt32 backMem = _optimum[cur].BackPrev;
+ do
+ {
+ if (_optimum[cur].Prev1IsChar)
+ {
+ _optimum[posMem].MakeAsChar();
+ _optimum[posMem].PosPrev = posMem - 1;
+ if (_optimum[cur].Prev2)
+ {
+ _optimum[posMem - 1].Prev1IsChar = false;
+ _optimum[posMem - 1].PosPrev = _optimum[cur].PosPrev2;
+ _optimum[posMem - 1].BackPrev = _optimum[cur].BackPrev2;
+ }
+ }
+ UInt32 posPrev = posMem;
+ UInt32 backCur = backMem;
+
+ backMem = _optimum[posPrev].BackPrev;
+ posMem = _optimum[posPrev].PosPrev;
+
+ _optimum[posPrev].BackPrev = backCur;
+ _optimum[posPrev].PosPrev = cur;
+ cur = posPrev;
+ }
+ while(cur != 0);
+ backRes = _optimum[0].BackPrev;
+ _optimumCurrentIndex = _optimum[0].PosPrev;
+ return _optimumCurrentIndex;
+}
+
+/*
+inline UInt32 GetMatchLen(const Byte *data, UInt32 back, UInt32 limit)
+{
+ back++;
+ for(UInt32 i = 0; i < limit && data[i] == data[i - back]; i++);
+ return i;
+}
+*/
+
+
+/*
+Out:
+ (lenRes == 1) && (backRes == 0xFFFFFFFF) means Literal
+*/
+
+HRESULT CEncoder::GetOptimum(UInt32 position, UInt32 &backRes, UInt32 &lenRes)
+{
+ if(_optimumEndIndex != _optimumCurrentIndex)
+ {
+ const COptimal &optimum = _optimum[_optimumCurrentIndex];
+ lenRes = optimum.PosPrev - _optimumCurrentIndex;
+ backRes = optimum.BackPrev;
+ _optimumCurrentIndex = optimum.PosPrev;
+ return S_OK;
+ }
+ _optimumCurrentIndex = 0;
+ _optimumEndIndex = 0; // test it;
+
+ UInt32 lenMain;
+ if (!_longestMatchWasFound)
+ {
+ RINOK(ReadMatchDistances(lenMain));
+ }
+ else
+ {
+ lenMain = _longestMatchLength;
+ _longestMatchWasFound = false;
+ }
+
+
+ UInt32 reps[kNumRepDistances];
+ UInt32 repLens[kNumRepDistances];
+ UInt32 repMaxIndex = 0;
+ UInt32 i;
+ for(i = 0; i < kNumRepDistances; i++)
+ {
+ reps[i] = _repDistances[i];
+ repLens[i] = _matchFinder->GetMatchLen(0 - 1, reps[i], kMatchMaxLen);
+ if (i == 0 || repLens[i] > repLens[repMaxIndex])
+ repMaxIndex = i;
+ }
+ if(repLens[repMaxIndex] >= _numFastBytes)
+ {
+ backRes = repMaxIndex;
+ lenRes = repLens[repMaxIndex];
+ return MovePos(lenRes - 1);
+ }
+
+ if(lenMain >= _numFastBytes)
+ {
+ backRes = _matchDistances[_numFastBytes] + kNumRepDistances;
+ lenRes = lenMain;
+ return MovePos(lenMain - 1);
+ }
+ Byte currentByte = _matchFinder->GetIndexByte(0 - 1);
+
+ _optimum[0].State = _state;
+
+ Byte matchByte;
+
+ matchByte = _matchFinder->GetIndexByte(0 - _repDistances[0] - 1 - 1);
+
+ UInt32 posState = (position & _posStateMask);
+
+ _optimum[1].Price = _isMatch[_state.Index][posState].GetPrice0() +
+ _literalEncoder.GetPrice(position, _previousByte, !_state.IsCharState(), matchByte, currentByte);
+ _optimum[1].MakeAsChar();
+
+ _optimum[1].PosPrev = 0;
+
+ for (i = 0; i < kNumRepDistances; i++)
+ _optimum[0].Backs[i] = reps[i];
+
+ UInt32 matchPrice = _isMatch[_state.Index][posState].GetPrice1();
+ UInt32 repMatchPrice = matchPrice + _isRep[_state.Index].GetPrice1();
+
+ if(matchByte == currentByte)
+ {
+ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(_state, posState);
+ if(shortRepPrice < _optimum[1].Price)
+ {
+ _optimum[1].Price = shortRepPrice;
+ _optimum[1].MakeAsShortRep();
+ }
+ }
+ if(lenMain < 2)
+ {
+ backRes = _optimum[1].BackPrev;
+ lenRes = 1;
+ return S_OK;
+ }
+
+
+ UInt32 normalMatchPrice = matchPrice +
+ _isRep[_state.Index].GetPrice0();
+
+ if (lenMain <= repLens[repMaxIndex])
+ lenMain = 0;
+
+ UInt32 len;
+ for(len = 2; len <= lenMain; len++)
+ {
+ _optimum[len].PosPrev = 0;
+ _optimum[len].BackPrev = _matchDistances[len] + kNumRepDistances;
+ _optimum[len].Price = normalMatchPrice +
+ GetPosLenPrice(_matchDistances[len], len, posState);
+ _optimum[len].Prev1IsChar = false;
+ }
+
+ if (lenMain < repLens[repMaxIndex])
+ lenMain = repLens[repMaxIndex];
+
+ for (; len <= lenMain; len++)
+ _optimum[len].Price = kIfinityPrice;
+
+ for(i = 0; i < kNumRepDistances; i++)
+ {
+ UInt32 repLen = repLens[i];
+ for(UInt32 lenTest = 2; lenTest <= repLen; lenTest++)
+ {
+ UInt32 curAndLenPrice = repMatchPrice + GetRepPrice(i, lenTest, _state, posState);
+ COptimal &optimum = _optimum[lenTest];
+ if (curAndLenPrice < optimum.Price)
+ {
+ optimum.Price = curAndLenPrice;
+ optimum.PosPrev = 0;
+ optimum.BackPrev = i;
+ optimum.Prev1IsChar = false;
+ }
+ }
+ }
+
+ UInt32 cur = 0;
+ UInt32 lenEnd = lenMain;
+
+ while(true)
+ {
+ cur++;
+ if(cur == lenEnd)
+ {
+ lenRes = Backward(backRes, cur);
+ return S_OK;
+ }
+ position++;
+ COptimal &curOptimum = _optimum[cur];
+ UInt32 posPrev = curOptimum.PosPrev;
+ CState state;
+ if (curOptimum.Prev1IsChar)
+ {
+ posPrev--;
+ if (curOptimum.Prev2)
+ {
+ state = _optimum[curOptimum.PosPrev2].State;
+ if (curOptimum.BackPrev2 < kNumRepDistances)
+ state.UpdateRep();
+ else
+ state.UpdateMatch();
+ }
+ else
+ state = _optimum[posPrev].State;
+ state.UpdateChar();
+ }
+ else
+ state = _optimum[posPrev].State;
+ if (posPrev == cur - 1)
+ {
+ if (curOptimum.IsShortRep())
+ state.UpdateShortRep();
+ else
+ state.UpdateChar();
+ /*
+ if (curOptimum.Prev1IsChar)
+ for(int i = 0; i < kNumRepDistances; i++)
+ reps[i] = _optimum[posPrev].Backs[i];
+ */
+ }
+ else
+ {
+ UInt32 pos;
+ if (curOptimum.Prev1IsChar && curOptimum.Prev2)
+ {
+ posPrev = curOptimum.PosPrev2;
+ pos = curOptimum.BackPrev2;
+ state.UpdateRep();
+ }
+ else
+ {
+ pos = curOptimum.BackPrev;
+ if (pos < kNumRepDistances)
+ state.UpdateRep();
+ else
+ state.UpdateMatch();
+ }
+ const COptimal &prevOptimum = _optimum[posPrev];
+ if (pos < kNumRepDistances)
+ {
+ reps[0] = prevOptimum.Backs[pos];
+ UInt32 i;
+ for(i = 1; i <= pos; i++)
+ reps[i] = prevOptimum.Backs[i - 1];
+ for(; i < kNumRepDistances; i++)
+ reps[i] = prevOptimum.Backs[i];
+ }
+ else
+ {
+ reps[0] = (pos - kNumRepDistances);
+ for(UInt32 i = 1; i < kNumRepDistances; i++)
+ reps[i] = prevOptimum.Backs[i - 1];
+ }
+ }
+ curOptimum.State = state;
+ for(UInt32 i = 0; i < kNumRepDistances; i++)
+ curOptimum.Backs[i] = reps[i];
+ UInt32 newLen;
+ RINOK(ReadMatchDistances(newLen));
+ if(newLen >= _numFastBytes)
+ {
+ _longestMatchLength = newLen;
+ _longestMatchWasFound = true;
+ lenRes = Backward(backRes, cur);
+ return S_OK;
+ }
+ UInt32 curPrice = curOptimum.Price;
+ // Byte currentByte = _matchFinder->GetIndexByte(0 - 1);
+ // Byte matchByte = _matchFinder->GetIndexByte(0 - reps[0] - 1 - 1);
+ const Byte *data = _matchFinder->GetPointerToCurrentPos() - 1;
+ Byte currentByte = *data;
+ Byte matchByte = data[(size_t)0 - reps[0] - 1];
+
+ UInt32 posState = (position & _posStateMask);
+
+ UInt32 curAnd1Price = curPrice +
+ _isMatch[state.Index][posState].GetPrice0() +
+ _literalEncoder.GetPrice(position, data[(size_t)0 - 1], !state.IsCharState(), matchByte, currentByte);
+
+ COptimal &nextOptimum = _optimum[cur + 1];
+
+ bool nextIsChar = false;
+ if (curAnd1Price < nextOptimum.Price)
+ {
+ nextOptimum.Price = curAnd1Price;
+ nextOptimum.PosPrev = cur;
+ nextOptimum.MakeAsChar();
+ nextIsChar = true;
+ }
+
+ UInt32 matchPrice = curPrice + _isMatch[state.Index][posState].GetPrice1();
+ UInt32 repMatchPrice = matchPrice + _isRep[state.Index].GetPrice1();
+
+ if(matchByte == currentByte &&
+ !(nextOptimum.PosPrev < cur && nextOptimum.BackPrev == 0))
+ {
+ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState);
+ if(shortRepPrice <= nextOptimum.Price)
+ {
+ nextOptimum.Price = shortRepPrice;
+ nextOptimum.PosPrev = cur;
+ nextOptimum.MakeAsShortRep();
+ // nextIsChar = false;
+ }
+ }
+ /*
+ if(newLen == 2 && _matchDistances[2] >= kDistLimit2) // test it maybe set 2000 ?
+ continue;
+ */
+
+ UInt32 numAvailableBytesFull = _matchFinder->GetNumAvailableBytes() + 1;
+ numAvailableBytesFull = MyMin(kNumOpts - 1 - cur, numAvailableBytesFull);
+ UInt32 numAvailableBytes = numAvailableBytesFull;
+
+ if (numAvailableBytes < 2)
+ continue;
+ if (numAvailableBytes > _numFastBytes)
+ numAvailableBytes = _numFastBytes;
+ if (numAvailableBytes >= 3 && !nextIsChar)
+ {
+ // try Literal + rep0
+ UInt32 backOffset = reps[0] + 1;
+ UInt32 temp;
+ for (temp = 1; temp < numAvailableBytes; temp++)
+ if (data[temp] != data[(size_t)temp - backOffset])
+ break;
+ UInt32 lenTest2 = temp - 1;
+ if (lenTest2 >= 2)
+ {
+ CState state2 = state;
+ state2.UpdateChar();
+ UInt32 posStateNext = (position + 1) & _posStateMask;
+ UInt32 nextRepMatchPrice = curAnd1Price +
+ _isMatch[state2.Index][posStateNext].GetPrice1() +
+ _isRep[state2.Index].GetPrice1();
+ // for (; lenTest2 >= 2; lenTest2--)
+ {
+ while(lenEnd < cur + 1 + lenTest2)
+ _optimum[++lenEnd].Price = kIfinityPrice;
+ UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(
+ 0, lenTest2, state2, posStateNext);
+ COptimal &optimum = _optimum[cur + 1 + lenTest2];
+ if (curAndLenPrice < optimum.Price)
+ {
+ optimum.Price = curAndLenPrice;
+ optimum.PosPrev = cur + 1;
+ optimum.BackPrev = 0;
+ optimum.Prev1IsChar = true;
+ optimum.Prev2 = false;
+ }
+ }
+ }
+ }
+ for(UInt32 repIndex = 0; repIndex < kNumRepDistances; repIndex++)
+ {
+ // UInt32 repLen = _matchFinder->GetMatchLen(0 - 1, reps[repIndex], newLen); // test it;
+ UInt32 backOffset = reps[repIndex] + 1;
+ if (data[0] != data[(size_t)0 - backOffset] ||
+ data[1] != data[(size_t)1 - backOffset])
+ continue;
+ UInt32 lenTest;
+ for (lenTest = 2; lenTest < numAvailableBytes; lenTest++)
+ if (data[lenTest] != data[(size_t)lenTest - backOffset])
+ break;
+ UInt32 lenTestTemp = lenTest;
+ do
+ {
+ while(lenEnd < cur + lenTest)
+ _optimum[++lenEnd].Price = kIfinityPrice;
+ UInt32 curAndLenPrice = repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState);
+ COptimal &optimum = _optimum[cur + lenTest];
+ if (curAndLenPrice < optimum.Price)
+ {
+ optimum.Price = curAndLenPrice;
+ optimum.PosPrev = cur;
+ optimum.BackPrev = repIndex;
+ optimum.Prev1IsChar = false;
+ }
+ }
+ while(--lenTest >= 2);
+ lenTest = lenTestTemp;
+
+ if (_maxMode)
+ {
+ UInt32 lenTest2 = lenTest + 1;
+ UInt32 limit = MyMin(numAvailableBytesFull, lenTest2 + _numFastBytes);
+ for (; lenTest2 < limit; lenTest2++)
+ if (data[lenTest2] != data[(size_t)lenTest2 - backOffset])
+ break;
+ lenTest2 -= lenTest + 1;
+ if (lenTest2 >= 2)
+ {
+ CState state2 = state;
+ state2.UpdateRep();
+ UInt32 posStateNext = (position + lenTest) & _posStateMask;
+ UInt32 curAndLenCharPrice =
+ repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState) +
+ _isMatch[state2.Index][posStateNext].GetPrice0() +
+ _literalEncoder.GetPrice(position + lenTest, data[(size_t)lenTest - 1],
+ true, data[(size_t)lenTest - backOffset], data[lenTest]);
+ state2.UpdateChar();
+ posStateNext = (position + lenTest + 1) & _posStateMask;
+ UInt32 nextMatchPrice = curAndLenCharPrice + _isMatch[state2.Index][posStateNext].GetPrice1();
+ UInt32 nextRepMatchPrice = nextMatchPrice + _isRep[state2.Index].GetPrice1();
+
+ // for(; lenTest2 >= 2; lenTest2--)
+ {
+ UInt32 offset = lenTest + 1 + lenTest2;
+ while(lenEnd < cur + offset)
+ _optimum[++lenEnd].Price = kIfinityPrice;
+ UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(
+ 0, lenTest2, state2, posStateNext);
+ COptimal &optimum = _optimum[cur + offset];
+ if (curAndLenPrice < optimum.Price)
+ {
+ optimum.Price = curAndLenPrice;
+ optimum.PosPrev = cur + lenTest + 1;
+ optimum.BackPrev = 0;
+ optimum.Prev1IsChar = true;
+ optimum.Prev2 = true;
+ optimum.PosPrev2 = cur;
+ optimum.BackPrev2 = repIndex;
+ }
+ }
+ }
+ }
+ }
+
+ // for(UInt32 lenTest = 2; lenTest <= newLen; lenTest++)
+ if (newLen > numAvailableBytes)
+ newLen = numAvailableBytes;
+ if (newLen >= 2)
+ {
+ if (newLen == 2 && _matchDistances[2] >= 0x80)
+ continue;
+ UInt32 normalMatchPrice = matchPrice +
+ _isRep[state.Index].GetPrice0();
+ while(lenEnd < cur + newLen)
+ _optimum[++lenEnd].Price = kIfinityPrice;
+
+ for(UInt32 lenTest = newLen; lenTest >= 2; lenTest--)
+ {
+ UInt32 curBack = _matchDistances[lenTest];
+ UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(curBack, lenTest, posState);
+ COptimal &optimum = _optimum[cur + lenTest];
+ if (curAndLenPrice < optimum.Price)
+ {
+ optimum.Price = curAndLenPrice;
+ optimum.PosPrev = cur;
+ optimum.BackPrev = curBack + kNumRepDistances;
+ optimum.Prev1IsChar = false;
+ }
+
+ if (_maxMode && (lenTest == newLen || curBack != _matchDistances[lenTest + 1]))
+ {
+ // Try Match + Literal + Rep0
+ UInt32 backOffset = curBack + 1;
+ UInt32 lenTest2 = lenTest + 1;
+ UInt32 limit = MyMin(numAvailableBytesFull, lenTest2 + _numFastBytes);
+ for (; lenTest2 < limit; lenTest2++)
+ if (data[lenTest2] != data[(size_t)lenTest2 - backOffset])
+ break;
+ lenTest2 -= lenTest + 1;
+ if (lenTest2 >= 2)
+ {
+ CState state2 = state;
+ state2.UpdateMatch();
+ UInt32 posStateNext = (position + lenTest) & _posStateMask;
+ UInt32 curAndLenCharPrice = curAndLenPrice +
+ _isMatch[state2.Index][posStateNext].GetPrice0() +
+ _literalEncoder.GetPrice(position + lenTest, data[(size_t)lenTest - 1],
+ true, data[(size_t)lenTest - backOffset], data[lenTest]);
+ state2.UpdateChar();
+ posStateNext = (position + lenTest + 1) & _posStateMask;
+ UInt32 nextMatchPrice = curAndLenCharPrice + _isMatch[state2.Index][posStateNext].GetPrice1();
+ UInt32 nextRepMatchPrice = nextMatchPrice + _isRep[state2.Index].GetPrice1();
+
+ // for(; lenTest2 >= 2; lenTest2--)
+ {
+ UInt32 offset = lenTest + 1 + lenTest2;
+ while(lenEnd < cur + offset)
+ _optimum[++lenEnd].Price = kIfinityPrice;
+ UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(
+ 0, lenTest2, state2, posStateNext);
+ COptimal &optimum = _optimum[cur + offset];
+ if (curAndLenPrice < optimum.Price)
+ {
+ optimum.Price = curAndLenPrice;
+ optimum.PosPrev = cur + lenTest + 1;
+ optimum.BackPrev = 0;
+ optimum.Prev1IsChar = true;
+ optimum.Prev2 = true;
+ optimum.PosPrev2 = cur;
+ optimum.BackPrev2 = curBack + kNumRepDistances;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static inline bool ChangePair(UInt32 smallDist, UInt32 bigDist)
+{
+ const int kDif = 7;
+ return (smallDist < (UInt32(1) << (32-kDif)) && bigDist >= (smallDist << kDif));
+}
+
+
+HRESULT CEncoder::ReadMatchDistances(UInt32 &lenRes)
+{
+ lenRes = _matchFinder->GetLongestMatch(_matchDistances);
+ if (lenRes == _numFastBytes)
+ lenRes += _matchFinder->GetMatchLen(lenRes, _matchDistances[lenRes],
+ kMatchMaxLen - lenRes);
+ _additionalOffset++;
+ return _matchFinder->MovePos();
+}
+
+HRESULT CEncoder::GetOptimumFast(UInt32 position, UInt32 &backRes, UInt32 &lenRes)
+{
+ UInt32 lenMain;
+ if (!_longestMatchWasFound)
+ {
+ RINOK(ReadMatchDistances(lenMain));
+ }
+ else
+ {
+ lenMain = _longestMatchLength;
+ _longestMatchWasFound = false;
+ }
+ UInt32 repLens[kNumRepDistances];
+ UInt32 repMaxIndex = 0;
+ for(UInt32 i = 0; i < kNumRepDistances; i++)
+ {
+ repLens[i] = _matchFinder->GetMatchLen(0 - 1, _repDistances[i], kMatchMaxLen);
+ if (i == 0 || repLens[i] > repLens[repMaxIndex])
+ repMaxIndex = i;
+ }
+ if(repLens[repMaxIndex] >= _numFastBytes)
+ {
+ backRes = repMaxIndex;
+ lenRes = repLens[repMaxIndex];
+ return MovePos(lenRes - 1);
+ }
+ if(lenMain >= _numFastBytes)
+ {
+ backRes = _matchDistances[_numFastBytes] + kNumRepDistances;
+ lenRes = lenMain;
+ return MovePos(lenMain - 1);
+ }
+ while (lenMain > 2)
+ {
+ if (!ChangePair(_matchDistances[lenMain - 1], _matchDistances[lenMain]))
+ break;
+ lenMain--;
+ }
+ if (lenMain == 2 && _matchDistances[2] >= 0x80)
+ lenMain = 1;
+
+ UInt32 backMain = _matchDistances[lenMain];
+ if (repLens[repMaxIndex] >= 2)
+ {
+ if (repLens[repMaxIndex] + 1 >= lenMain ||
+ repLens[repMaxIndex] + 2 >= lenMain && (backMain > (1<<12)))
+ {
+ backRes = repMaxIndex;
+ lenRes = repLens[repMaxIndex];
+ return MovePos(lenRes - 1);
+ }
+ }
+
+
+ if (lenMain >= 2)
+ {
+ RINOK(ReadMatchDistances(_longestMatchLength));
+ if (_longestMatchLength >= 2 &&
+ (
+ (_longestMatchLength >= lenMain && _matchDistances[lenMain] < backMain) ||
+ _longestMatchLength == lenMain + 1 &&
+ !ChangePair(backMain, _matchDistances[_longestMatchLength]) ||
+ _longestMatchLength > lenMain + 1 ||
+ _longestMatchLength + 1 >= lenMain && lenMain >= 3 &&
+ ChangePair(_matchDistances[lenMain - 1], backMain)
+ )
+ )
+ {
+ _longestMatchWasFound = true;
+ backRes = UInt32(-1);
+ lenRes = 1;
+ return S_OK;
+ }
+ for(UInt32 i = 0; i < kNumRepDistances; i++)
+ {
+ UInt32 repLen = _matchFinder->GetMatchLen(0 - 1, _repDistances[i], kMatchMaxLen);
+ if (repLen >= 2 && repLen + 1 >= lenMain)
+ {
+ _longestMatchWasFound = true;
+ backRes = UInt32(-1);
+ lenRes = 1;
+ return S_OK;
+ }
+ }
+ backRes = backMain + kNumRepDistances;
+ lenRes = lenMain;
+ return MovePos(lenMain - 2);
+ }
+ backRes = UInt32(-1);
+ lenRes = 1;
+ return S_OK;
+}
+
+STDMETHODIMP CEncoder::InitMatchFinder(IMatchFinder *matchFinder)
+{
+ _matchFinder = matchFinder;
+ return S_OK;
+}
+
+HRESULT CEncoder::Flush(UInt32 nowPos)
+{
+ ReleaseMFStream();
+ WriteEndMarker(nowPos & _posStateMask);
+ _rangeEncoder.FlushData();
+ return _rangeEncoder.FlushStream();
+}
+
+void CEncoder::WriteEndMarker(UInt32 posState)
+{
+ // This function for writing End Mark for stream version of LZMA.
+ // In current version this feature is not used.
+ if (!_writeEndMark)
+ return;
+
+ _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 1);
+ _isRep[_state.Index].Encode(&_rangeEncoder, 0);
+ _state.UpdateMatch();
+ UInt32 len = kMatchMinLen; // kMatchMaxLen;
+ _lenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState);
+ UInt32 posSlot = (1 << kNumPosSlotBits) - 1;
+ UInt32 lenToPosState = GetLenToPosState(len);
+ _posSlotEncoder[lenToPosState].Encode(&_rangeEncoder, posSlot);
+ UInt32 footerBits = 30;
+ UInt32 posReduced = (UInt32(1) << footerBits) - 1;
+ _rangeEncoder.EncodeDirectBits(posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
+ _posAlignEncoder.ReverseEncode(&_rangeEncoder, posReduced & kAlignMask);
+}
+
+HRESULT CEncoder::CodeReal(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress)
+{
+ _needReleaseMFStream = false;
+ CCoderReleaser coderReleaser(this);
+ RINOK(SetStreams(inStream, outStream, inSize, outSize));
+ while(true)
+ {
+ UInt64 processedInSize;
+ UInt64 processedOutSize;
+ Int32 finished;
+ RINOK(CodeOneBlock(&processedInSize, &processedOutSize, &finished));
+ if (finished != 0)
+ return S_OK;
+ if (progress != 0)
+ {
+ RINOK(progress->SetRatioInfo(&processedInSize, &processedOutSize));
+ }
+ }
+}
+
+HRESULT CEncoder::SetStreams(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize)
+{
+ _inStream = inStream;
+ _finished = false;
+ RINOK(Create());
+ RINOK(SetOutStream(outStream));
+ RINOK(Init());
+
+ // CCoderReleaser releaser(this);
+
+ /*
+ if (_matchFinder->GetNumAvailableBytes() == 0)
+ return Flush();
+ */
+
+ if (!_fastMode)
+ {
+ FillPosSlotPrices();
+ FillDistancesPrices();
+ FillAlignPrices();
+ }
+
+ _lenEncoder.SetTableSize(_numFastBytes + 1 - kMatchMinLen);
+ _lenEncoder.UpdateTables(1 << _posStateBits);
+ _repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - kMatchMinLen);
+ _repMatchLenEncoder.UpdateTables(1 << _posStateBits);
+
+ lastPosSlotFillingPos = 0;
+ nowPos64 = 0;
+ return S_OK;
+}
+
+HRESULT CEncoder::CodeOneBlock(UInt64 *inSize, UInt64 *outSize, Int32 *finished)
+{
+ if (_inStream != 0)
+ {
+ RINOK(_matchFinder->Init(_inStream));
+ _needReleaseMFStream = true;
+ _inStream = 0;
+ }
+
+
+ *finished = 1;
+ if (_finished)
+ return S_OK;
+ _finished = true;
+
+
+ UInt64 progressPosValuePrev = nowPos64;
+ if (nowPos64 == 0)
+ {
+ if (_matchFinder->GetNumAvailableBytes() == 0)
+ return Flush(UInt32(nowPos64));
+ UInt32 len; // it's not used
+ RINOK(ReadMatchDistances(len));
+ UInt32 posState = UInt32(nowPos64) & _posStateMask;
+ _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 0);
+ _state.UpdateChar();
+ Byte curByte = _matchFinder->GetIndexByte(0 - _additionalOffset);
+ _literalEncoder.GetSubCoder(UInt32(nowPos64), _previousByte)->Encode(&_rangeEncoder, curByte);
+ _previousByte = curByte;
+ _additionalOffset--;
+ nowPos64++;
+ }
+ if (_matchFinder->GetNumAvailableBytes() == 0)
+ return Flush(UInt32(nowPos64));
+ while(true)
+ {
+ #ifdef _NO_EXCEPTIONS
+ if (_rangeEncoder.Stream.ErrorCode != S_OK)
+ return _rangeEncoder.Stream.ErrorCode;
+ #endif
+ UInt32 pos;
+ UInt32 posState = UInt32(nowPos64) & _posStateMask;
+
+ UInt32 len;
+ HRESULT result;
+ if (_fastMode)
+ result = GetOptimumFast(UInt32(nowPos64), pos, len);
+ else
+ result = GetOptimum(UInt32(nowPos64), pos, len);
+ RINOK(result);
+
+ if(len == 1 && pos == 0xFFFFFFFF)
+ {
+ _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 0);
+ Byte curByte = _matchFinder->GetIndexByte(0 - _additionalOffset);
+ CLiteralEncoder2 *subCoder = _literalEncoder.GetSubCoder(UInt32(nowPos64), _previousByte);
+ if(!_state.IsCharState())
+ {
+ Byte matchByte = _matchFinder->GetIndexByte(0 - _repDistances[0] - 1 - _additionalOffset);
+ subCoder->EncodeMatched(&_rangeEncoder, matchByte, curByte);
+ }
+ else
+ subCoder->Encode(&_rangeEncoder, curByte);
+ _state.UpdateChar();
+ _previousByte = curByte;
+ }
+ else
+ {
+ _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 1);
+ if(pos < kNumRepDistances)
+ {
+ _isRep[_state.Index].Encode(&_rangeEncoder, 1);
+ if(pos == 0)
+ {
+ _isRepG0[_state.Index].Encode(&_rangeEncoder, 0);
+ if(len == 1)
+ _isRep0Long[_state.Index][posState].Encode(&_rangeEncoder, 0);
+ else
+ _isRep0Long[_state.Index][posState].Encode(&_rangeEncoder, 1);
+ }
+ else
+ {
+ _isRepG0[_state.Index].Encode(&_rangeEncoder, 1);
+ if (pos == 1)
+ _isRepG1[_state.Index].Encode(&_rangeEncoder, 0);
+ else
+ {
+ _isRepG1[_state.Index].Encode(&_rangeEncoder, 1);
+ _isRepG2[_state.Index].Encode(&_rangeEncoder, pos - 2);
+ }
+ }
+ if (len == 1)
+ _state.UpdateShortRep();
+ else
+ {
+ _repMatchLenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState);
+ _state.UpdateRep();
+ }
+
+
+ UInt32 distance = _repDistances[pos];
+ if (pos != 0)
+ {
+ for(UInt32 i = pos; i >= 1; i--)
+ _repDistances[i] = _repDistances[i - 1];
+ _repDistances[0] = distance;
+ }
+ }
+ else
+ {
+ _isRep[_state.Index].Encode(&_rangeEncoder, 0);
+ _state.UpdateMatch();
+ _lenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState);
+ pos -= kNumRepDistances;
+ UInt32 posSlot = GetPosSlot(pos);
+ UInt32 lenToPosState = GetLenToPosState(len);
+ _posSlotEncoder[lenToPosState].Encode(&_rangeEncoder, posSlot);
+
+ if (posSlot >= kStartPosModelIndex)
+ {
+ UInt32 footerBits = ((posSlot >> 1) - 1);
+ UInt32 base = ((2 | (posSlot & 1)) << footerBits);
+ UInt32 posReduced = pos - base;
+
+ if (posSlot < kEndPosModelIndex)
+ NRangeCoder::ReverseBitTreeEncode(_posEncoders + base - posSlot - 1,
+ &_rangeEncoder, footerBits, posReduced);
+ else
+ {
+ _rangeEncoder.EncodeDirectBits(posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
+ _posAlignEncoder.ReverseEncode(&_rangeEncoder, posReduced & kAlignMask);
+ if (!_fastMode)
+ if (--_alignPriceCount == 0)
+ FillAlignPrices();
+ }
+ }
+ UInt32 distance = pos;
+ for(UInt32 i = kNumRepDistances - 1; i >= 1; i--)
+ _repDistances[i] = _repDistances[i - 1];
+ _repDistances[0] = distance;
+ }
+ _previousByte = _matchFinder->GetIndexByte(len - 1 - _additionalOffset);
+ }
+ _additionalOffset -= len;
+ nowPos64 += len;
+ if (!_fastMode)
+ if (nowPos64 - lastPosSlotFillingPos >= (1 << 9))
+ {
+ FillPosSlotPrices();
+ FillDistancesPrices();
+ lastPosSlotFillingPos = nowPos64;
+ }
+ if (_additionalOffset == 0)
+ {
+ *inSize = nowPos64;
+ *outSize = _rangeEncoder.GetProcessedSize();
+ if (_matchFinder->GetNumAvailableBytes() == 0)
+ return Flush(UInt32(nowPos64));
+ if (nowPos64 - progressPosValuePrev >= (1 << 12))
+ {
+ _finished = false;
+ *finished = 0;
+ return S_OK;
+ }
+ }
+ }
+}
+
+STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress)
+{
+ #ifndef _NO_EXCEPTIONS
+ try
+ {
+ #endif
+ return CodeReal(inStream, outStream, inSize, outSize, progress);
+ #ifndef _NO_EXCEPTIONS
+ }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return E_FAIL; }
+ #endif
+}
+
+void CEncoder::FillPosSlotPrices()
+{
+ for (UInt32 lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
+ {
+ UInt32 posSlot;
+ for (posSlot = 0; posSlot < kEndPosModelIndex && posSlot < _distTableSize; posSlot++)
+ _posSlotPrices[lenToPosState][posSlot] = _posSlotEncoder[lenToPosState].GetPrice(posSlot);
+ for (; posSlot < _distTableSize; posSlot++)
+ _posSlotPrices[lenToPosState][posSlot] = _posSlotEncoder[lenToPosState].GetPrice(posSlot) +
+ ((((posSlot >> 1) - 1) - kNumAlignBits) << NRangeCoder::kNumBitPriceShiftBits);
+ }
+}
+
+void CEncoder::FillDistancesPrices()
+{
+ for (UInt32 lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
+ {
+ UInt32 i;
+ for (i = 0; i < kStartPosModelIndex; i++)
+ _distancesPrices[lenToPosState][i] = _posSlotPrices[lenToPosState][i];
+ for (; i < kNumFullDistances; i++)
+ {
+ UInt32 posSlot = GetPosSlot(i);
+ UInt32 footerBits = ((posSlot >> 1) - 1);
+ UInt32 base = ((2 | (posSlot & 1)) << footerBits);
+
+ _distancesPrices[lenToPosState][i] = _posSlotPrices[lenToPosState][posSlot] +
+ NRangeCoder::ReverseBitTreeGetPrice(_posEncoders +
+ base - posSlot - 1, footerBits, i - base);
+
+ }
+ }
+}
+
+void CEncoder::FillAlignPrices()
+{
+ for (UInt32 i = 0; i < kAlignTableSize; i++)
+ _alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i);
+ _alignPriceCount = kAlignTableSize;
+}
+
+}}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA/LZMAEncoder.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA/LZMAEncoder.h new file mode 100644 index 00000000..542994e3 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA/LZMAEncoder.h @@ -0,0 +1,416 @@ +// LZMA/Encoder.h
+
+#ifndef __LZMA_ENCODER_H
+#define __LZMA_ENCODER_H
+
+#include "../../../Common/MyCom.h"
+#include "../../../Common/Alloc.h"
+#include "../../ICoder.h"
+#include "../LZ/IMatchFinder.h"
+#include "../RangeCoder/RangeCoderBitTree.h"
+
+#include "LZMA.h"
+
+namespace NCompress {
+namespace NLZMA {
+
+typedef NRangeCoder::CBitEncoder<kNumMoveBits> CMyBitEncoder;
+
+class CBaseState
+{
+protected:
+ CState _state;
+ Byte _previousByte;
+ UInt32 _repDistances[kNumRepDistances];
+ void Init()
+ {
+ _state.Init();
+ _previousByte = 0;
+ for(UInt32 i = 0 ; i < kNumRepDistances; i++)
+ _repDistances[i] = 0;
+ }
+};
+
+struct COptimal
+{
+ CState State;
+
+ bool Prev1IsChar;
+ bool Prev2;
+
+ UInt32 PosPrev2;
+ UInt32 BackPrev2;
+
+ UInt32 Price;
+ UInt32 PosPrev; // posNext;
+ UInt32 BackPrev;
+ UInt32 Backs[kNumRepDistances];
+ void MakeAsChar() { BackPrev = UInt32(-1); Prev1IsChar = false; }
+ void MakeAsShortRep() { BackPrev = 0; ; Prev1IsChar = false; }
+ bool IsShortRep() { return (BackPrev == 0); }
+};
+
+
+extern Byte g_FastPos[1024];
+inline UInt32 GetPosSlot(UInt32 pos)
+{
+ if (pos < (1 << 10))
+ return g_FastPos[pos];
+ if (pos < (1 << 19))
+ return g_FastPos[pos >> 9] + 18;
+ return g_FastPos[pos >> 18] + 36;
+}
+
+inline UInt32 GetPosSlot2(UInt32 pos)
+{
+ if (pos < (1 << 16))
+ return g_FastPos[pos >> 6] + 12;
+ if (pos < (1 << 25))
+ return g_FastPos[pos >> 15] + 30;
+ return g_FastPos[pos >> 24] + 48;
+}
+
+const UInt32 kIfinityPrice = 0xFFFFFFF;
+
+const UInt32 kNumOpts = 1 << 12;
+
+
+class CLiteralEncoder2
+{
+ CMyBitEncoder _encoders[0x300];
+public:
+ void Init()
+ {
+ for (int i = 0; i < 0x300; i++)
+ _encoders[i].Init();
+ }
+ void Encode(NRangeCoder::CEncoder *rangeEncoder, Byte symbol);
+ void EncodeMatched(NRangeCoder::CEncoder *rangeEncoder, Byte matchByte, Byte symbol);
+ UInt32 GetPrice(bool matchMode, Byte matchByte, Byte symbol) const;
+};
+
+class CLiteralEncoder
+{
+ CLiteralEncoder2 *_coders;
+ int _numPrevBits;
+ int _numPosBits;
+ UInt32 _posMask;
+public:
+ CLiteralEncoder(): _coders(0) {}
+ ~CLiteralEncoder() { Free(); }
+ void Free()
+ {
+ MyFree(_coders);
+ _coders = 0;
+ }
+ bool Create(int numPosBits, int numPrevBits)
+ {
+ if (_coders == 0 || (numPosBits + numPrevBits) !=
+ (_numPrevBits + _numPosBits) )
+ {
+ Free();
+ UInt32 numStates = 1 << (numPosBits + numPrevBits);
+ _coders = (CLiteralEncoder2 *)MyAlloc(numStates * sizeof(CLiteralEncoder2));
+ }
+ _numPosBits = numPosBits;
+ _posMask = (1 << numPosBits) - 1;
+ _numPrevBits = numPrevBits;
+ return (_coders != 0);
+ }
+ void Init()
+ {
+ UInt32 numStates = 1 << (_numPrevBits + _numPosBits);
+ for (UInt32 i = 0; i < numStates; i++)
+ _coders[i].Init();
+ }
+ UInt32 GetState(UInt32 pos, Byte prevByte) const
+ { return ((pos & _posMask) << _numPrevBits) + (prevByte >> (8 - _numPrevBits)); }
+ CLiteralEncoder2 *GetSubCoder(UInt32 pos, Byte prevByte)
+ { return &_coders[GetState(pos, prevByte)]; }
+ /*
+ void Encode(NRangeCoder::CEncoder *rangeEncoder, UInt32 pos, Byte prevByte,
+ Byte symbol)
+ { _coders[GetState(pos, prevByte)].Encode(rangeEncoder, symbol); }
+ void EncodeMatched(NRangeCoder::CEncoder *rangeEncoder, UInt32 pos, Byte prevByte,
+ Byte matchByte, Byte symbol)
+ { _coders[GetState(pos, prevByte)].Encode(rangeEncoder,
+ matchByte, symbol); }
+ */
+ UInt32 GetPrice(UInt32 pos, Byte prevByte, bool matchMode, Byte matchByte, Byte symbol) const
+ { return _coders[GetState(pos, prevByte)].GetPrice(matchMode, matchByte, symbol); }
+};
+
+namespace NLength {
+
+class CEncoder
+{
+ CMyBitEncoder _choice;
+ CMyBitEncoder _choice2;
+ NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumLowBits> _lowCoder[kNumPosStatesEncodingMax];
+ NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumMidBits> _midCoder[kNumPosStatesEncodingMax];
+ NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumHighBits> _highCoder;
+public:
+ void Init(UInt32 numPosStates);
+ void Encode(NRangeCoder::CEncoder *rangeEncoder, UInt32 symbol, UInt32 posState);
+ UInt32 GetPrice(UInt32 symbol, UInt32 posState) const;
+};
+
+const UInt32 kNumSpecSymbols = kNumLowSymbols + kNumMidSymbols;
+
+class CPriceTableEncoder: public CEncoder
+{
+ UInt32 _prices[kNumSymbolsTotal][kNumPosStatesEncodingMax];
+ UInt32 _tableSize;
+ UInt32 _counters[kNumPosStatesEncodingMax];
+public:
+ void SetTableSize(UInt32 tableSize) { _tableSize = tableSize; }
+ UInt32 GetPrice(UInt32 symbol, UInt32 posState) const
+ { return _prices[symbol][posState]; }
+ void UpdateTable(UInt32 posState)
+ {
+ for (UInt32 len = 0; len < _tableSize; len++)
+ _prices[len][posState] = CEncoder::GetPrice(len, posState);
+ _counters[posState] = _tableSize;
+ }
+ void UpdateTables(UInt32 numPosStates)
+ {
+ for (UInt32 posState = 0; posState < numPosStates; posState++)
+ UpdateTable(posState);
+ }
+ void Encode(NRangeCoder::CEncoder *rangeEncoder, UInt32 symbol, UInt32 posState)
+ {
+ CEncoder::Encode(rangeEncoder, symbol, posState);
+ if (--_counters[posState] == 0)
+ UpdateTable(posState);
+ }
+};
+
+}
+
+class CEncoder :
+ public ICompressCoder,
+ public ICompressSetOutStream,
+ public ICompressSetCoderProperties,
+ public ICompressWriteCoderProperties,
+ public CBaseState,
+ public CMyUnknownImp
+{
+ COptimal _optimum[kNumOpts];
+ CMyComPtr<IMatchFinder> _matchFinder; // test it
+ NRangeCoder::CEncoder _rangeEncoder;
+
+ CMyBitEncoder _isMatch[kNumStates][NLength::kNumPosStatesEncodingMax];
+ CMyBitEncoder _isRep[kNumStates];
+ CMyBitEncoder _isRepG0[kNumStates];
+ CMyBitEncoder _isRepG1[kNumStates];
+ CMyBitEncoder _isRepG2[kNumStates];
+ CMyBitEncoder _isRep0Long[kNumStates][NLength::kNumPosStatesEncodingMax];
+
+ NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumPosSlotBits> _posSlotEncoder[kNumLenToPosStates];
+
+ CMyBitEncoder _posEncoders[kNumFullDistances - kEndPosModelIndex];
+ NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumAlignBits> _posAlignEncoder;
+
+ NLength::CPriceTableEncoder _lenEncoder;
+ NLength::CPriceTableEncoder _repMatchLenEncoder;
+
+ CLiteralEncoder _literalEncoder;
+
+ UInt32 _matchDistances[kMatchMaxLen + 1];
+
+ bool _fastMode;
+ bool _maxMode;
+ UInt32 _numFastBytes;
+ UInt32 _longestMatchLength;
+
+ UInt32 _additionalOffset;
+
+ UInt32 _optimumEndIndex;
+ UInt32 _optimumCurrentIndex;
+
+ bool _longestMatchWasFound;
+
+ UInt32 _posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
+
+ UInt32 _distancesPrices[kNumLenToPosStates][kNumFullDistances];
+
+ UInt32 _alignPrices[kAlignTableSize];
+ UInt32 _alignPriceCount;
+
+ UInt32 _distTableSize;
+
+ UInt32 _posStateBits;
+ UInt32 _posStateMask;
+ UInt32 _numLiteralPosStateBits;
+ UInt32 _numLiteralContextBits;
+
+ UInt32 _dictionarySize;
+
+ UInt32 _dictionarySizePrev;
+ UInt32 _numFastBytesPrev;
+
+ UInt64 lastPosSlotFillingPos;
+ UInt64 nowPos64;
+ bool _finished;
+ ISequentialInStream *_inStream;
+
+ int _matchFinderIndex;
+ #ifdef COMPRESS_MF_MT
+ bool _multiThread;
+ #endif
+
+ bool _writeEndMark;
+
+ bool _needReleaseMFStream;
+
+ HRESULT ReadMatchDistances(UInt32 &len);
+
+ HRESULT MovePos(UInt32 num);
+ UInt32 GetRepLen1Price(CState state, UInt32 posState) const
+ {
+ return _isRepG0[state.Index].GetPrice0() +
+ _isRep0Long[state.Index][posState].GetPrice0();
+ }
+ UInt32 GetRepPrice(UInt32 repIndex, UInt32 len, CState state, UInt32 posState) const
+ {
+ UInt32 price = _repMatchLenEncoder.GetPrice(len - kMatchMinLen, posState);
+ if(repIndex == 0)
+ {
+ price += _isRepG0[state.Index].GetPrice0();
+ price += _isRep0Long[state.Index][posState].GetPrice1();
+ }
+ else
+ {
+ price += _isRepG0[state.Index].GetPrice1();
+ if (repIndex == 1)
+ price += _isRepG1[state.Index].GetPrice0();
+ else
+ {
+ price += _isRepG1[state.Index].GetPrice1();
+ price += _isRepG2[state.Index].GetPrice(repIndex - 2);
+ }
+ }
+ return price;
+ }
+ /*
+ UInt32 GetPosLen2Price(UInt32 pos, UInt32 posState) const
+ {
+ if (pos >= kNumFullDistances)
+ return kIfinityPrice;
+ return _distancesPrices[0][pos] + _lenEncoder.GetPrice(0, posState);
+ }
+ UInt32 GetPosLen3Price(UInt32 pos, UInt32 len, UInt32 posState) const
+ {
+ UInt32 price;
+ UInt32 lenToPosState = GetLenToPosState(len);
+ if (pos < kNumFullDistances)
+ price = _distancesPrices[lenToPosState][pos];
+ else
+ price = _posSlotPrices[lenToPosState][GetPosSlot2(pos)] +
+ _alignPrices[pos & kAlignMask];
+ return price + _lenEncoder.GetPrice(len - kMatchMinLen, posState);
+ }
+ */
+ UInt32 GetPosLenPrice(UInt32 pos, UInt32 len, UInt32 posState) const
+ {
+ if (len == 2 && pos >= 0x80)
+ return kIfinityPrice;
+ UInt32 price;
+ UInt32 lenToPosState = GetLenToPosState(len);
+ if (pos < kNumFullDistances)
+ price = _distancesPrices[lenToPosState][pos];
+ else
+ price = _posSlotPrices[lenToPosState][GetPosSlot2(pos)] +
+ _alignPrices[pos & kAlignMask];
+ return price + _lenEncoder.GetPrice(len - kMatchMinLen, posState);
+ }
+
+ UInt32 Backward(UInt32 &backRes, UInt32 cur);
+ HRESULT GetOptimum(UInt32 position, UInt32 &backRes, UInt32 &lenRes);
+ HRESULT GetOptimumFast(UInt32 position, UInt32 &backRes, UInt32 &lenRes);
+
+ void FillPosSlotPrices();
+ void FillDistancesPrices();
+ void FillAlignPrices();
+
+ void ReleaseMFStream()
+ {
+ if (_matchFinder && _needReleaseMFStream)
+ {
+ _matchFinder->ReleaseStream();
+ _needReleaseMFStream = false;
+ }
+ }
+
+ void ReleaseStreams()
+ {
+ ReleaseMFStream();
+ ReleaseOutStream();
+ }
+
+ HRESULT Flush(UInt32 nowPos);
+ class CCoderReleaser
+ {
+ CEncoder *_coder;
+ public:
+ CCoderReleaser(CEncoder *coder): _coder(coder) {}
+ ~CCoderReleaser()
+ {
+ _coder->ReleaseStreams();
+ }
+ };
+ friend class CCoderReleaser;
+
+ void WriteEndMarker(UInt32 posState);
+
+public:
+ CEncoder();
+ void SetWriteEndMarkerMode(bool writeEndMarker)
+ { _writeEndMark= writeEndMarker; }
+
+ HRESULT Create();
+
+ MY_UNKNOWN_IMP3(
+ ICompressSetOutStream,
+ ICompressSetCoderProperties,
+ ICompressWriteCoderProperties
+ )
+
+ HRESULT Init();
+
+ // ICompressCoder interface
+ HRESULT SetStreams(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize);
+ HRESULT CodeOneBlock(UInt64 *inSize, UInt64 *outSize, Int32 *finished);
+
+ HRESULT CodeReal(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress);
+
+ // ICompressCoder interface
+ STDMETHOD(Code)(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress);
+
+ // IInitMatchFinder interface
+ STDMETHOD(InitMatchFinder)(IMatchFinder *matchFinder);
+
+ // ICompressSetCoderProperties2
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs,
+ const PROPVARIANT *properties, UInt32 numProperties);
+
+ // ICompressWriteCoderProperties
+ STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
+
+ STDMETHOD(SetOutStream)(ISequentialOutStream *outStream);
+ STDMETHOD(ReleaseOutStream)();
+
+ virtual ~CEncoder() {}
+};
+
+}}
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA/StdAfx.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA/StdAfx.h new file mode 100644 index 00000000..83fdd22d --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA/StdAfx.h @@ -0,0 +1,8 @@ +// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/AloneLZMA.dsp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/AloneLZMA.dsp new file mode 100644 index 00000000..41d5b489 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/AloneLZMA.dsp @@ -0,0 +1,523 @@ +# Microsoft Developer Studio Project File - Name="AloneLZMA" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=AloneLZMA - Win32 DebugU
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "AloneLZMA.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "AloneLZMA.mak" CFG="AloneLZMA - Win32 DebugU"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "AloneLZMA - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "AloneLZMA - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "AloneLZMA - Win32 ReleaseU" (based on "Win32 (x86) Console Application")
+!MESSAGE "AloneLZMA - Win32 DebugU" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "AloneLZMA - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\\" /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /Yu"StdAfx.h" /FD /c
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\lzma.exe" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "AloneLZMA - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\lzma.exe" /pdbtype:sept
+
+!ELSEIF "$(CFG)" == "AloneLZMA - Win32 ReleaseU"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "ReleaseU"
+# PROP BASE Intermediate_Dir "ReleaseU"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "ReleaseU"
+# PROP Intermediate_Dir "ReleaseU"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "EXCLUDE_COM" /D "NO_REGISTRY" /D "FORMAT_7Z" /D "FORMAT_BZIP2" /D "FORMAT_ZIP" /D "FORMAT_TAR" /D "FORMAT_GZIP" /D "COMPRESS_LZMA" /D "COMPRESS_BCJ_X86" /D "COMPRESS_BCJ2" /D "COMPRESS_COPY" /D "COMPRESS_MF_PAT" /D "COMPRESS_MF_BT" /D "COMPRESS_PPMD" /D "COMPRESS_DEFLATE" /D "COMPRESS_IMPLODE" /D "COMPRESS_BZIP2" /D "CRYPTO_ZIP" /Yu"StdAfx.h" /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\\" /D "NDEBUG" /D "UNICODE" /D "_UNICODE" /D "WIN32" /D "_CONSOLE" /Yu"StdAfx.h" /FD /c
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7za2.exe" /opt:NOWIN98
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\lzma.exe" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "AloneLZMA - Win32 DebugU"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "DebugU"
+# PROP BASE Intermediate_Dir "DebugU"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "DebugU"
+# PROP Intermediate_Dir "DebugU"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "EXCLUDE_COM" /D "NO_REGISTRY" /D "FORMAT_7Z" /D "FORMAT_BZIP2" /D "FORMAT_ZIP" /D "FORMAT_TAR" /D "FORMAT_GZIP" /D "COMPRESS_LZMA" /D "COMPRESS_BCJ_X86" /D "COMPRESS_BCJ2" /D "COMPRESS_COPY" /D "COMPRESS_MF_PAT" /D "COMPRESS_MF_BT" /D "COMPRESS_PPMD" /D "COMPRESS_DEFLATE" /D "COMPRESS_IMPLODE" /D "COMPRESS_BZIP2" /D "CRYPTO_ZIP" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_CONSOLE" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7za2.exe" /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\lzma.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "AloneLZMA - Win32 Release"
+# Name "AloneLZMA - Win32 Debug"
+# Name "AloneLZMA - Win32 ReleaseU"
+# Name "AloneLZMA - Win32 DebugU"
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"StdAfx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# End Group
+# Begin Group "Compress"
+
+# PROP Default_Filter ""
+# Begin Group "LZMA"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\LZMA\LZMA.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZMA\LZMADecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZMA\LZMADecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZMA\LZMAEncoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZMA\LZMAEncoder.h
+# End Source File
+# End Group
+# Begin Group "RangeCoder"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\RangeCoder\RangeCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\RangeCoder\RangeCoderBit.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\RangeCoder\RangeCoderBit.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\RangeCoder\RangeCoderBitTree.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\RangeCoder\RangeCoderOpt.h
+# End Source File
+# End Group
+# Begin Group "LZ"
+
+# PROP Default_Filter ""
+# Begin Group "Pat"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\LZ\Patricia\Pat.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\Patricia\Pat2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\Patricia\Pat2H.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\Patricia\Pat2R.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\Patricia\Pat3H.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\Patricia\Pat4H.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\Patricia\PatMain.h
+# End Source File
+# End Group
+# Begin Group "BT"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\LZ\BinTree\BinTree.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\BinTree\BinTree2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\BinTree\BinTree3.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\BinTree\BinTree3Z.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\BinTree\BinTree3ZMain.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\BinTree\BinTree4.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\BinTree\BinTree4b.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\BinTree\BinTreeMain.h
+# End Source File
+# End Group
+# Begin Group "HC"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\LZ\HashChain\HC.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\HashChain\HC2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\HashChain\HC3.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\HashChain\HC4.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\HashChain\HC4b.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\HashChain\HCMain.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\LZ\IMatchFinder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\LZInWindow.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\LZInWindow.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\LZOutWindow.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZ\LZOutWindow.h
+# End Source File
+# End Group
+# Begin Group "Branch"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\Branch\BranchX86.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\Branch\BranchX86.h
+# End Source File
+# End Group
+# Begin Group "LZMA_C"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\LZMA_C\LzmaDecode.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\LZMA_C\LzmaDecode.h
+# End Source File
+# End Group
+# End Group
+# Begin Group "Windows"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.h
+# End Source File
+# End Group
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Common\Alloc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CRC.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyCom.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\String.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\String.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Types.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Vector.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Vector.h
+# End Source File
+# End Group
+# Begin Group "7zip Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\ICoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\LzmaAlone.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\LzmaBench.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\LzmaBench.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\LzmaRam.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\LzmaRam.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\LzmaRamDecode.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=.\LzmaRamDecode.h
+# End Source File
+# End Target
+# End Project
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/AloneLZMA.dsw b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/AloneLZMA.dsw new file mode 100644 index 00000000..7402f297 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/AloneLZMA.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "AloneLZMA"=.\AloneLZMA.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/LzmaAlone.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/LzmaAlone.cpp new file mode 100644 index 00000000..52149033 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/LzmaAlone.cpp @@ -0,0 +1,509 @@ +// LzmaAlone.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/MyInitGuid.h"
+
+#include <stdio.h>
+
+#if defined(_WIN32) || defined(OS2) || defined(MSDOS)
+#include <fcntl.h>
+#include <io.h>
+#define MY_SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY)
+#else
+#define MY_SET_BINARY_MODE(file)
+#endif
+
+#include "../../../Common/CommandLineParser.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/StringToInt.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../LZMA/LZMADecoder.h"
+#include "../LZMA/LZMAEncoder.h"
+
+#include "LzmaBench.h"
+#include "LzmaRam.h"
+
+extern "C"
+{
+#include "LzmaRamDecode.h"
+}
+
+using namespace NCommandLineParser;
+
+#ifdef _WIN32
+bool g_IsNT = false;
+static inline bool IsItWindowsNT()
+{
+ OSVERSIONINFO versionInfo;
+ versionInfo.dwOSVersionInfoSize = sizeof(versionInfo);
+ if (!::GetVersionEx(&versionInfo))
+ return false;
+ return (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT);
+}
+#endif
+
+static const char *kCantAllocate = "Can not allocate memory";
+static const char *kReadError = "Read error";
+static const char *kWriteError = "Write error";
+
+namespace NKey {
+enum Enum
+{
+ kHelp1 = 0,
+ kHelp2,
+ kMode,
+ kDictionary,
+ kFastBytes,
+ kLitContext,
+ kLitPos,
+ kPosBits,
+ kMatchFinder,
+ kEOS,
+ kStdIn,
+ kStdOut,
+ kFilter86
+};
+}
+
+static const CSwitchForm kSwitchForms[] =
+{
+ { L"?", NSwitchType::kSimple, false },
+ { L"H", NSwitchType::kSimple, false },
+ { L"A", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"D", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"FB", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"LC", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"LP", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"PB", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"MF", NSwitchType::kUnLimitedPostString, false, 1 },
+ { L"EOS", NSwitchType::kSimple, false },
+ { L"SI", NSwitchType::kSimple, false },
+ { L"SO", NSwitchType::kSimple, false },
+ { L"F86", NSwitchType::kSimple, false }
+};
+
+static const int kNumSwitches = sizeof(kSwitchForms) / sizeof(kSwitchForms[0]);
+
+static void PrintHelp()
+{
+ fprintf(stderr, "\nUsage: LZMA <e|d> inputFile outputFile [<switches>...]\n"
+ " e: encode file\n"
+ " d: decode file\n"
+ " b: Benchmark\n"
+ "<Switches>\n"
+ " -a{N}: set compression mode - [0, 2], default: 2 (max)\n"
+ " -d{N}: set dictionary - [0,28], default: 23 (8MB)\n"
+ " -fb{N}: set number of fast bytes - [5, 273], default: 128\n"
+ " -lc{N}: set number of literal context bits - [0, 8], default: 3\n"
+ " -lp{N}: set number of literal pos bits - [0, 4], default: 0\n"
+ " -pb{N}: set number of pos bits - [0, 4], default: 2\n"
+ " -mf{MF_ID}: set Match Finder: [bt2, bt3, bt4, bt4b, pat2r, pat2,\n"
+ " pat2h, pat3h, pat4h, hc3, hc4], default: bt4\n"
+ " -eos: write End Of Stream marker\n"
+ " -si: read data from stdin\n"
+ " -so: write data to stdout\n"
+ );
+}
+
+static void PrintHelpAndExit(const char *s)
+{
+ fprintf(stderr, "\nError: %s\n\n", s);
+ PrintHelp();
+ throw -1;
+}
+
+static void IncorrectCommand()
+{
+ PrintHelpAndExit("Incorrect command");
+}
+
+static void WriteArgumentsToStringList(int numArguments, const char *arguments[],
+ UStringVector &strings)
+{
+ for(int i = 1; i < numArguments; i++)
+ strings.Add(MultiByteToUnicodeString(arguments[i]));
+}
+
+static bool GetNumber(const wchar_t *s, UInt32 &value)
+{
+ value = 0;
+ if (MyStringLen(s) == 0)
+ return false;
+ const wchar_t *end;
+ UInt64 res = ConvertStringToUInt64(s, &end);
+ if (*end != L'\0')
+ return false;
+ if (res > 0xFFFFFFFF)
+ return false;
+ value = UInt32(res);
+ return true;
+}
+
+int main2(int n, const char *args[])
+{
+ #ifdef _WIN32
+ g_IsNT = IsItWindowsNT();
+ #endif
+
+ fprintf(stderr, "\nLZMA 4.32 Copyright (c) 1999-2005 Igor Pavlov 2005-12-09\n");
+
+ if (n == 1)
+ {
+ PrintHelp();
+ return 0;
+ }
+
+ if (sizeof(Byte) != 1 || sizeof(UInt32) < 4 || sizeof(UInt64) < 4)
+ {
+ fprintf(stderr, "Unsupported base types. Edit Common/Types.h and recompile");
+ return 1;
+ }
+
+ UStringVector commandStrings;
+ WriteArgumentsToStringList(n, args, commandStrings);
+ CParser parser(kNumSwitches);
+ try
+ {
+ parser.ParseStrings(kSwitchForms, commandStrings);
+ }
+ catch(...)
+ {
+ IncorrectCommand();
+ }
+
+ if(parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs)
+ {
+ PrintHelp();
+ return 0;
+ }
+ const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
+
+ int paramIndex = 0;
+ if (paramIndex >= nonSwitchStrings.Size())
+ IncorrectCommand();
+ const UString &command = nonSwitchStrings[paramIndex++];
+
+ bool dictionaryIsDefined = false;
+ UInt32 dictionary = 1 << 21;
+ if(parser[NKey::kDictionary].ThereIs)
+ {
+ UInt32 dicLog;
+ if (!GetNumber(parser[NKey::kDictionary].PostStrings[0], dicLog))
+ IncorrectCommand();
+ dictionary = 1 << dicLog;
+ dictionaryIsDefined = true;
+ }
+ UString mf = L"BT4";
+ if (parser[NKey::kMatchFinder].ThereIs)
+ mf = parser[NKey::kMatchFinder].PostStrings[0];
+
+ if (command.CompareNoCase(L"b") == 0)
+ {
+ const UInt32 kNumDefaultItereations = 10;
+ UInt32 numIterations = kNumDefaultItereations;
+ {
+ if (paramIndex < nonSwitchStrings.Size())
+ if (!GetNumber(nonSwitchStrings[paramIndex++], numIterations))
+ numIterations = kNumDefaultItereations;
+ }
+ return LzmaBenchmark(stderr, numIterations, dictionary,
+ mf.CompareNoCase(L"BT4") == 0);
+ }
+
+ bool encodeMode = false;
+ if (command.CompareNoCase(L"e") == 0)
+ encodeMode = true;
+ else if (command.CompareNoCase(L"d") == 0)
+ encodeMode = false;
+ else
+ IncorrectCommand();
+
+ bool stdInMode = parser[NKey::kStdIn].ThereIs;
+ bool stdOutMode = parser[NKey::kStdOut].ThereIs;
+
+ CMyComPtr<ISequentialInStream> inStream;
+ CInFileStream *inStreamSpec = 0;
+ if (stdInMode)
+ {
+ inStream = new CStdInFileStream;
+ MY_SET_BINARY_MODE(stdin);
+ }
+ else
+ {
+ if (paramIndex >= nonSwitchStrings.Size())
+ IncorrectCommand();
+ const UString &inputName = nonSwitchStrings[paramIndex++];
+ inStreamSpec = new CInFileStream;
+ inStream = inStreamSpec;
+ if (!inStreamSpec->Open(GetSystemString(inputName)))
+ {
+ fprintf(stderr, "\nError: can not open input file %s\n",
+ (const char *)GetOemString(inputName));
+ return 1;
+ }
+ }
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ if (stdOutMode)
+ {
+ outStream = new CStdOutFileStream;
+ MY_SET_BINARY_MODE(stdout);
+ }
+ else
+ {
+ if (paramIndex >= nonSwitchStrings.Size())
+ IncorrectCommand();
+ const UString &outputName = nonSwitchStrings[paramIndex++];
+ COutFileStream *outStreamSpec = new COutFileStream;
+ outStream = outStreamSpec;
+ if (!outStreamSpec->Create(GetSystemString(outputName), true))
+ {
+ fprintf(stderr, "\nError: can not open output file %s\n",
+ (const char *)GetOemString(outputName));
+ return 1;
+ }
+ }
+
+ if (parser[NKey::kFilter86].ThereIs)
+ {
+ // -f86 switch is for x86 filtered mode: BCJ + LZMA.
+ if (parser[NKey::kEOS].ThereIs || stdInMode)
+ throw "Can not use stdin in this mode";
+ UInt64 fileSize;
+ inStreamSpec->File.GetLength(fileSize);
+ if (fileSize > 0xF0000000)
+ throw "File is too big";
+ UInt32 inSize = (UInt32)fileSize;
+ Byte *inBuffer = 0;
+ if (inSize != 0)
+ {
+ inBuffer = (Byte *)MyAlloc((size_t)inSize);
+ if (inBuffer == 0)
+ throw kCantAllocate;
+ }
+
+ UInt32 processedSize;
+ if (ReadStream(inStream, inBuffer, (UInt32)inSize, &processedSize) != S_OK)
+ throw "Can not read";
+ if ((UInt32)inSize != processedSize)
+ throw "Read size error";
+
+ Byte *outBuffer = 0;
+ size_t outSizeProcessed;
+ if (encodeMode)
+ {
+ // we allocate 105% of original size for output buffer
+ size_t outSize = (size_t)fileSize / 20 * 21 + (1 << 16);
+ if (outSize != 0)
+ {
+ outBuffer = (Byte *)MyAlloc((size_t)outSize);
+ if (outBuffer == 0)
+ throw kCantAllocate;
+ }
+ if (!dictionaryIsDefined)
+ dictionary = 1 << 23;
+ int res = LzmaRamEncode(inBuffer, inSize, outBuffer, outSize, &outSizeProcessed,
+ dictionary, SZ_FILTER_AUTO);
+ if (res != 0)
+ {
+ fprintf(stderr, "\nEncoder error = %d\n", (int)res);
+ return 1;
+ }
+ }
+ else
+ {
+ size_t outSize;
+ if (LzmaRamGetUncompressedSize(inBuffer, inSize, &outSize) != 0)
+ throw "data error";
+ if (outSize != 0)
+ {
+ outBuffer = (Byte *)MyAlloc(outSize);
+ if (outBuffer == 0)
+ throw kCantAllocate;
+ }
+ int res = LzmaRamDecompress(inBuffer, inSize, outBuffer, outSize, &outSizeProcessed, malloc, free);
+ if (res != 0)
+ throw "LzmaDecoder error";
+ }
+ if (WriteStream(outStream, outBuffer, (UInt32)outSizeProcessed, &processedSize) != S_OK)
+ throw kWriteError;
+ MyFree(outBuffer);
+ MyFree(inBuffer);
+ return 0;
+ }
+
+
+ UInt64 fileSize;
+ if (encodeMode)
+ {
+ NCompress::NLZMA::CEncoder *encoderSpec =
+ new NCompress::NLZMA::CEncoder;
+ CMyComPtr<ICompressCoder> encoder = encoderSpec;
+
+ if (!dictionaryIsDefined)
+ dictionary = 1 << 23;
+
+ UInt32 posStateBits = 2;
+ UInt32 litContextBits = 3; // for normal files
+ // UInt32 litContextBits = 0; // for 32-bit data
+ UInt32 litPosBits = 0;
+ // UInt32 litPosBits = 2; // for 32-bit data
+ UInt32 algorithm = 2;
+ UInt32 numFastBytes = 128;
+
+ bool eos = parser[NKey::kEOS].ThereIs || stdInMode;
+
+ if(parser[NKey::kMode].ThereIs)
+ if (!GetNumber(parser[NKey::kMode].PostStrings[0], algorithm))
+ IncorrectCommand();
+
+ if(parser[NKey::kFastBytes].ThereIs)
+ if (!GetNumber(parser[NKey::kFastBytes].PostStrings[0], numFastBytes))
+ IncorrectCommand();
+ if(parser[NKey::kLitContext].ThereIs)
+ if (!GetNumber(parser[NKey::kLitContext].PostStrings[0], litContextBits))
+ IncorrectCommand();
+ if(parser[NKey::kLitPos].ThereIs)
+ if (!GetNumber(parser[NKey::kLitPos].PostStrings[0], litPosBits))
+ IncorrectCommand();
+ if(parser[NKey::kPosBits].ThereIs)
+ if (!GetNumber(parser[NKey::kPosBits].PostStrings[0], posStateBits))
+ IncorrectCommand();
+
+ PROPID propIDs[] =
+ {
+ NCoderPropID::kDictionarySize,
+ NCoderPropID::kPosStateBits,
+ NCoderPropID::kLitContextBits,
+ NCoderPropID::kLitPosBits,
+ NCoderPropID::kAlgorithm,
+ NCoderPropID::kNumFastBytes,
+ NCoderPropID::kMatchFinder,
+ NCoderPropID::kEndMarker
+ };
+ const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]);
+ /*
+ NWindows::NCOM::CPropVariant properties[kNumProps];
+ properties[0] = UInt32(dictionary);
+ properties[1] = UInt32(posStateBits);
+ properties[2] = UInt32(litContextBits);
+
+ properties[3] = UInt32(litPosBits);
+ properties[4] = UInt32(algorithm);
+ properties[5] = UInt32(numFastBytes);
+ properties[6] = mf;
+ properties[7] = eos;
+ */
+ PROPVARIANT properties[kNumProps];
+ for (int p = 0; p < 6; p++)
+ properties[p].vt = VT_UI4;
+ properties[0].ulVal = UInt32(dictionary);
+ properties[1].ulVal = UInt32(posStateBits);
+ properties[2].ulVal = UInt32(litContextBits);
+ properties[3].ulVal = UInt32(litPosBits);
+ properties[4].ulVal = UInt32(algorithm);
+ properties[5].ulVal = UInt32(numFastBytes);
+
+ properties[6].vt = VT_BSTR;
+ properties[6].bstrVal = (BSTR)(const wchar_t *)mf;
+
+ properties[7].vt = VT_BOOL;
+ properties[7].boolVal = eos ? VARIANT_TRUE : VARIANT_FALSE;
+
+ if (encoderSpec->SetCoderProperties(propIDs, properties, kNumProps) != S_OK)
+ IncorrectCommand();
+ encoderSpec->WriteCoderProperties(outStream);
+
+ if (eos || stdInMode)
+ fileSize = (UInt64)(Int64)-1;
+ else
+ inStreamSpec->File.GetLength(fileSize);
+
+ for (int i = 0; i < 8; i++)
+ {
+ Byte b = Byte(fileSize >> (8 * i));
+ if (outStream->Write(&b, 1, 0) != S_OK)
+ {
+ fprintf(stderr, kWriteError);
+ return 1;
+ }
+ }
+ HRESULT result = encoder->Code(inStream, outStream, 0, 0, 0);
+ if (result == E_OUTOFMEMORY)
+ {
+ fprintf(stderr, "\nError: Can not allocate memory\n");
+ return 1;
+ }
+ else if (result != S_OK)
+ {
+ fprintf(stderr, "\nEncoder error = %X\n", (unsigned int)result);
+ return 1;
+ }
+ }
+ else
+ {
+ NCompress::NLZMA::CDecoder *decoderSpec =
+ new NCompress::NLZMA::CDecoder;
+ CMyComPtr<ICompressCoder> decoder = decoderSpec;
+ const UInt32 kPropertiesSize = 5;
+ Byte properties[kPropertiesSize];
+ UInt32 processedSize;
+ if (ReadStream(inStream, properties, kPropertiesSize, &processedSize) != S_OK)
+ {
+ fprintf(stderr, kReadError);
+ return 1;
+ }
+ if (processedSize != kPropertiesSize)
+ {
+ fprintf(stderr, kReadError);
+ return 1;
+ }
+ if (decoderSpec->SetDecoderProperties2(properties, kPropertiesSize) != S_OK)
+ {
+ fprintf(stderr, "SetDecoderProperties error");
+ return 1;
+ }
+ fileSize = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ Byte b;
+ if (inStream->Read(&b, 1, &processedSize) != S_OK)
+ {
+ fprintf(stderr, kReadError);
+ return 1;
+ }
+ if (processedSize != 1)
+ {
+ fprintf(stderr, kReadError);
+ return 1;
+ }
+ fileSize |= ((UInt64)b) << (8 * i);
+ }
+ if (decoder->Code(inStream, outStream, 0, &fileSize, 0) != S_OK)
+ {
+ fprintf(stderr, "Decoder error");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int main(int n, const char *args[])
+{
+ try { return main2(n, args); }
+ catch(const char *s)
+ {
+ fprintf(stderr, "\nError: %s\n", s);
+ return 1;
+ }
+ catch(...)
+ {
+ fprintf(stderr, "\nError\n");
+ return 1;
+ }
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/LzmaBench.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/LzmaBench.cpp new file mode 100644 index 00000000..fd6af9bd --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/LzmaBench.cpp @@ -0,0 +1,508 @@ +// LzmaBench.cpp
+
+#include "StdAfx.h"
+
+#include "LzmaBench.h"
+
+#ifndef _WIN32
+#include <time.h>
+#endif
+
+#include "../../../Common/CRC.h"
+#include "../LZMA/LZMADecoder.h"
+#include "../LZMA/LZMAEncoder.h"
+
+static const UInt32 kAdditionalSize =
+#ifdef _WIN32_WCE
+(1 << 20);
+#else
+(6 << 20);
+#endif
+
+static const UInt32 kCompressedAdditionalSize = (1 << 10);
+static const UInt32 kMaxLzmaPropSize = 10;
+
+class CRandomGenerator
+{
+ UInt32 A1;
+ UInt32 A2;
+public:
+ CRandomGenerator() { Init(); }
+ void Init() { A1 = 362436069; A2 = 521288629;}
+ UInt32 GetRnd()
+ {
+ return
+ ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) ^
+ ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)) );
+ }
+};
+
+class CBitRandomGenerator
+{
+ CRandomGenerator RG;
+ UInt32 Value;
+ int NumBits;
+public:
+ void Init()
+ {
+ Value = 0;
+ NumBits = 0;
+ }
+ UInt32 GetRnd(int numBits)
+ {
+ if (NumBits > numBits)
+ {
+ UInt32 result = Value & ((1 << numBits) - 1);
+ Value >>= numBits;
+ NumBits -= numBits;
+ return result;
+ }
+ numBits -= NumBits;
+ UInt32 result = (Value << numBits);
+ Value = RG.GetRnd();
+ result |= Value & ((1 << numBits) - 1);
+ Value >>= numBits;
+ NumBits = 32 - numBits;
+ return result;
+ }
+};
+
+class CBenchRandomGenerator
+{
+ CBitRandomGenerator RG;
+ UInt32 Pos;
+public:
+ UInt32 BufferSize;
+ Byte *Buffer;
+ CBenchRandomGenerator(): Buffer(0) {}
+ ~CBenchRandomGenerator() { delete []Buffer; }
+ void Init() { RG.Init(); }
+ void Set(UInt32 bufferSize)
+ {
+ delete []Buffer;
+ Buffer = 0;
+ Buffer = new Byte[bufferSize];
+ Pos = 0;
+ BufferSize = bufferSize;
+ }
+ UInt32 GetRndBit() { return RG.GetRnd(1); }
+ /*
+ UInt32 GetLogRand(int maxLen)
+ {
+ UInt32 len = GetRnd() % (maxLen + 1);
+ return GetRnd() & ((1 << len) - 1);
+ }
+ */
+ UInt32 GetLogRandBits(int numBits)
+ {
+ UInt32 len = RG.GetRnd(numBits);
+ return RG.GetRnd(len);
+ }
+ UInt32 GetOffset()
+ {
+ if (GetRndBit() == 0)
+ return GetLogRandBits(4);
+ return (GetLogRandBits(4) << 10) | RG.GetRnd(10);
+ }
+ UInt32 GetLen()
+ {
+ if (GetRndBit() == 0)
+ return RG.GetRnd(2);
+ if (GetRndBit() == 0)
+ return 4 + RG.GetRnd(3);
+ return 12 + RG.GetRnd(4);
+ }
+ void Generate()
+ {
+ while(Pos < BufferSize)
+ {
+ if (GetRndBit() == 0 || Pos < 1)
+ Buffer[Pos++] = Byte(RG.GetRnd(8));
+ else
+ {
+ UInt32 offset = GetOffset();
+ while (offset >= Pos)
+ offset >>= 1;
+ offset += 1;
+ UInt32 len = 2 + GetLen();
+ for (UInt32 i = 0; i < len && Pos < BufferSize; i++, Pos++)
+ Buffer[Pos] = Buffer[Pos - offset];
+ }
+ }
+ }
+};
+
+class CBenchmarkInStream:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+ const Byte *Data;
+ UInt32 Pos;
+ UInt32 Size;
+public:
+ MY_UNKNOWN_IMP
+ void Init(const Byte *data, UInt32 size)
+ {
+ Data = data;
+ Size = size;
+ Pos = 0;
+ }
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+};
+
+STDMETHODIMP CBenchmarkInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 remain = Size - Pos;
+ if (size > remain)
+ size = remain;
+ for (UInt32 i = 0; i < size; i++)
+ ((Byte *)data)[i] = Data[Pos + i];
+ Pos += size;
+ if(processedSize != NULL)
+ *processedSize = size;
+ return S_OK;
+}
+
+class CBenchmarkOutStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ UInt32 BufferSize;
+ FILE *_f;
+public:
+ UInt32 Pos;
+ Byte *Buffer;
+ CBenchmarkOutStream(): _f(0), Buffer(0) {}
+ virtual ~CBenchmarkOutStream() { delete []Buffer; }
+ void Init(FILE *f, UInt32 bufferSize)
+ {
+ delete []Buffer;
+ Buffer = 0;
+ Buffer = new Byte[bufferSize];
+ Pos = 0;
+ BufferSize = bufferSize;
+ _f = f;
+ }
+ MY_UNKNOWN_IMP
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+STDMETHODIMP CBenchmarkOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 i;
+ for (i = 0; i < size && Pos < BufferSize; i++)
+ Buffer[Pos++] = ((const Byte *)data)[i];
+ if(processedSize != NULL)
+ *processedSize = i;
+ if (i != size)
+ {
+ fprintf(_f, "\nERROR: Buffer is full\n");
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+class CCrcOutStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+public:
+ CCRC CRC;
+ MY_UNKNOWN_IMP
+ void Init() { CRC.Init(); }
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+STDMETHODIMP CCrcOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ CRC.Update(data, size);
+ if(processedSize != NULL)
+ *processedSize = size;
+ return S_OK;
+}
+
+static UInt64 GetTimeCount()
+{
+ #ifdef _WIN32
+ LARGE_INTEGER value;
+ if (::QueryPerformanceCounter(&value))
+ return value.QuadPart;
+ return GetTickCount();
+ #else
+ return clock();
+ #endif
+}
+
+static UInt64 GetFreq()
+{
+ #ifdef _WIN32
+ LARGE_INTEGER value;
+ if (::QueryPerformanceFrequency(&value))
+ return value.QuadPart;
+ return 1000;
+ #else
+ return CLOCKS_PER_SEC;
+ #endif
+}
+
+struct CProgressInfo:
+ public ICompressProgressInfo,
+ public CMyUnknownImp
+{
+ UInt64 ApprovedStart;
+ UInt64 InSize;
+ UInt64 Time;
+ void Init()
+ {
+ InSize = 0;
+ Time = 0;
+ }
+ MY_UNKNOWN_IMP
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
+};
+
+STDMETHODIMP CProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ if (*inSize >= ApprovedStart && InSize == 0)
+ {
+ Time = ::GetTimeCount();
+ InSize = *inSize;
+ }
+ return S_OK;
+}
+
+static const int kSubBits = 8;
+
+static UInt32 GetLogSize(UInt32 size)
+{
+ for (int i = kSubBits; i < 32; i++)
+ for (UInt32 j = 0; j < (1 << kSubBits); j++)
+ if (size <= (((UInt32)1) << i) + (j << (i - kSubBits)))
+ return (i << kSubBits) + j;
+ return (32 << kSubBits);
+}
+
+static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime)
+{
+ UInt64 freq = GetFreq();
+ UInt64 elTime = elapsedTime;
+ while(freq > 1000000)
+ {
+ freq >>= 1;
+ elTime >>= 1;
+ }
+ if (elTime == 0)
+ elTime = 1;
+ return value * freq / elTime;
+}
+
+static UInt64 GetCompressRating(UInt32 dictionarySize, bool isBT4,
+ UInt64 elapsedTime, UInt64 size)
+{
+ UInt64 numCommandsForOne;
+ if (isBT4)
+ {
+ UInt64 t = GetLogSize(dictionarySize) - (19 << kSubBits);
+ numCommandsForOne = 2000 + ((t * t * 68) >> (2 * kSubBits));
+ }
+ else
+ {
+ UInt64 t = GetLogSize(dictionarySize) - (15 << kSubBits);
+ numCommandsForOne = 1500 + ((t * t * 41) >> (2 * kSubBits));
+ }
+ UInt64 numCommands = (UInt64)(size) * numCommandsForOne;
+ return MyMultDiv64(numCommands, elapsedTime);
+}
+
+static UInt64 GetDecompressRating(UInt64 elapsedTime,
+ UInt64 outSize, UInt64 inSize)
+{
+ UInt64 numCommands = inSize * 250 + outSize * 21;
+ return MyMultDiv64(numCommands, elapsedTime);
+}
+
+/*
+static UInt64 GetTotalRating(
+ UInt32 dictionarySize,
+ bool isBT4,
+ UInt64 elapsedTimeEn, UInt64 sizeEn,
+ UInt64 elapsedTimeDe,
+ UInt64 inSizeDe, UInt64 outSizeDe)
+{
+ return (GetCompressRating(dictionarySize, isBT4, elapsedTimeEn, sizeEn) +
+ GetDecompressRating(elapsedTimeDe, inSizeDe, outSizeDe)) / 2;
+}
+*/
+
+static void PrintRating(FILE *f, UInt64 rating)
+{
+ fprintf(f, "%5d MIPS", (unsigned int)(rating / 1000000));
+}
+
+static void PrintResults(
+ FILE *f,
+ UInt32 dictionarySize,
+ bool isBT4,
+ UInt64 elapsedTime,
+ UInt64 size,
+ bool decompressMode, UInt64 secondSize)
+{
+ UInt64 speed = MyMultDiv64(size, elapsedTime);
+ fprintf(f, "%6d KB/s ", (unsigned int)(speed / 1024));
+ UInt64 rating;
+ if (decompressMode)
+ rating = GetDecompressRating(elapsedTime, size, secondSize);
+ else
+ rating = GetCompressRating(dictionarySize, isBT4, elapsedTime, size);
+ PrintRating(f, rating);
+}
+
+static void ThrowError(FILE *f, HRESULT result, const char *s)
+{
+ fprintf(f, "\nError: ");
+ if (result == E_ABORT)
+ fprintf(f, "User break");
+ if (result == E_OUTOFMEMORY)
+ fprintf(f, "Can not allocate memory");
+ else
+ fprintf(f, s);
+ fprintf(f, "\n");
+}
+
+const wchar_t *bt2 = L"BT2";
+const wchar_t *bt4 = L"BT4";
+
+int LzmaBenchmark(FILE *f, UInt32 numIterations, UInt32 dictionarySize, bool isBT4)
+{
+ if (numIterations == 0)
+ return 0;
+ if (dictionarySize < (1 << 19) && isBT4 || dictionarySize < (1 << 15))
+ {
+ fprintf(f, "\nError: dictionary size for benchmark must be >= 19 (512 KB)\n");
+ return 1;
+ }
+ fprintf(f, "\n Compressing Decompressing\n\n");
+ NCompress::NLZMA::CEncoder *encoderSpec = new NCompress::NLZMA::CEncoder;
+ CMyComPtr<ICompressCoder> encoder = encoderSpec;
+
+ NCompress::NLZMA::CDecoder *decoderSpec = new NCompress::NLZMA::CDecoder;
+ CMyComPtr<ICompressCoder> decoder = decoderSpec;
+
+ CBenchmarkOutStream *propStreamSpec = new CBenchmarkOutStream;
+ CMyComPtr<ISequentialOutStream> propStream = propStreamSpec;
+ propStreamSpec->Init(f, kMaxLzmaPropSize);
+
+ PROPID propIDs[] =
+ {
+ NCoderPropID::kDictionarySize,
+ NCoderPropID::kMatchFinder
+ };
+ const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]);
+ PROPVARIANT properties[kNumProps];
+ properties[0].vt = VT_UI4;
+ properties[0].ulVal = UInt32(dictionarySize);
+
+ properties[1].vt = VT_BSTR;
+ properties[1].bstrVal = isBT4 ? (BSTR)bt4: (BSTR)bt2;
+
+ const UInt32 kBufferSize = dictionarySize + kAdditionalSize;
+ const UInt32 kCompressedBufferSize = (kBufferSize / 2) + kCompressedAdditionalSize;
+
+ if (encoderSpec->SetCoderProperties(propIDs, properties, kNumProps) != S_OK)
+ {
+ fprintf(f, "\nError: Incorrect command\n");
+ return 1;
+ }
+ encoderSpec->WriteCoderProperties(propStream);
+
+ CBenchRandomGenerator rg;
+ rg.Init();
+ rg.Set(kBufferSize);
+ rg.Generate();
+ CCRC crc;
+ crc.Update(rg.Buffer, rg.BufferSize);
+
+ CProgressInfo *progressInfoSpec = new CProgressInfo;
+ CMyComPtr<ICompressProgressInfo> progressInfo = progressInfoSpec;
+
+ progressInfoSpec->ApprovedStart = dictionarySize;
+
+ UInt64 totalBenchSize = 0;
+ UInt64 totalEncodeTime = 0;
+ UInt64 totalDecodeTime = 0;
+ UInt64 totalCompressedSize = 0;
+
+ for (UInt32 i = 0; i < numIterations; i++)
+ {
+ progressInfoSpec->Init();
+ CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
+ inStreamSpec->Init(rg.Buffer, rg.BufferSize);
+ CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
+ CBenchmarkOutStream *outStreamSpec = new CBenchmarkOutStream;
+ outStreamSpec->Init(f, kCompressedBufferSize);
+ CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+ HRESULT result = encoder->Code(inStream, outStream, 0, 0, progressInfo);
+ UInt64 encodeTime = ::GetTimeCount() - progressInfoSpec->Time;
+ UInt32 compressedSize = outStreamSpec->Pos;
+ if(result != S_OK)
+ {
+ ThrowError(f, result, "Encoder Error");
+ return 1;
+ }
+ if (progressInfoSpec->InSize == 0)
+ {
+ fprintf(f, "\nError: Internal ERROR 1282\n");
+ return 1;
+ }
+
+ ///////////////////////
+ // Decompressing
+
+ CCrcOutStream *crcOutStreamSpec = new CCrcOutStream;
+ CMyComPtr<ISequentialOutStream> crcOutStream = crcOutStreamSpec;
+
+ UInt64 decodeTime;
+ for (int j = 0; j < 2; j++)
+ {
+ inStreamSpec->Init(outStreamSpec->Buffer, compressedSize);
+ crcOutStreamSpec->Init();
+
+ if (decoderSpec->SetDecoderProperties2(propStreamSpec->Buffer, propStreamSpec->Pos) != S_OK)
+ {
+ fprintf(f, "\nError: Set Decoder Properties Error\n");
+ return 1;
+ }
+ UInt64 outSize = kBufferSize;
+ UInt64 startTime = ::GetTimeCount();
+ result = decoder->Code(inStream, crcOutStream, 0, &outSize, 0);
+ decodeTime = ::GetTimeCount() - startTime;
+ if(result != S_OK)
+ {
+ ThrowError(f, result, "Decode Error");
+ return 1;
+ }
+ if (crcOutStreamSpec->CRC.GetDigest() != crc.GetDigest())
+ {
+ fprintf(f, "\nError: CRC Error\n");
+ return 1;
+ }
+ }
+ UInt64 benchSize = kBufferSize - progressInfoSpec->InSize;
+ PrintResults(f, dictionarySize, isBT4, encodeTime, benchSize, false, 0);
+ fprintf(f, " ");
+ PrintResults(f, dictionarySize, isBT4, decodeTime, kBufferSize, true, compressedSize);
+ fprintf(f, "\n");
+
+ totalBenchSize += benchSize;
+ totalEncodeTime += encodeTime;
+ totalDecodeTime += decodeTime;
+ totalCompressedSize += compressedSize;
+ }
+ fprintf(f, "---------------------------------------------------\n");
+ PrintResults(f, dictionarySize, isBT4, totalEncodeTime, totalBenchSize, false, 0);
+ fprintf(f, " ");
+ PrintResults(f, dictionarySize, isBT4, totalDecodeTime,
+ kBufferSize * numIterations, true, totalCompressedSize);
+ fprintf(f, " Average\n");
+ return 0;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/LzmaBench.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/LzmaBench.h new file mode 100644 index 00000000..9a1a63a5 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/LzmaBench.h @@ -0,0 +1,11 @@ +// LzmaBench.h
+
+#ifndef __LzmaBench_h
+#define __LzmaBench_h
+
+#include <stdio.h>
+#include "../../../Common/Types.h"
+
+int LzmaBenchmark(FILE *f, UInt32 numIterations, UInt32 dictionarySize, bool isBT4);
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/LzmaRam.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/LzmaRam.cpp new file mode 100644 index 00000000..3cc264a1 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/LzmaRam.cpp @@ -0,0 +1,228 @@ +// LzmaRam.cpp
+
+#include "StdAfx.h"
+#include "../../../Common/Types.h"
+#include "../LZMA/LZMADecoder.h"
+#include "../LZMA/LZMAEncoder.h"
+#include "LzmaRam.h"
+
+extern "C"
+{
+#include "../Branch/BranchX86.h"
+}
+
+class CInStreamRam:
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+ const Byte *Data;
+ size_t Size;
+ size_t Pos;
+public:
+ MY_UNKNOWN_IMP
+ void Init(const Byte *data, size_t size)
+ {
+ Data = data;
+ Size = size;
+ Pos = 0;
+ }
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+};
+
+STDMETHODIMP CInStreamRam::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 remain = Size - Pos;
+ if (size > remain)
+ size = remain;
+ for (UInt32 i = 0; i < size; i++)
+ ((Byte *)data)[i] = Data[Pos + i];
+ Pos += size;
+ if(processedSize != NULL)
+ *processedSize = size;
+ return S_OK;
+}
+
+class COutStreamRam:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ size_t Size;
+public:
+ Byte *Data;
+ size_t Pos;
+ bool Overflow;
+ void Init(Byte *data, size_t size)
+ {
+ Data = data;
+ Size = size;
+ Pos = 0;
+ Overflow = false;
+ }
+ void SetPos(size_t pos)
+ {
+ Overflow = false;
+ Pos = pos;
+ }
+ MY_UNKNOWN_IMP
+ HRESULT WriteByte(Byte b)
+ {
+ if (Pos >= Size)
+ {
+ Overflow = true;
+ return E_FAIL;
+ }
+ Data[Pos++] = b;
+ return S_OK;
+ }
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
+};
+
+STDMETHODIMP COutStreamRam::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ UInt32 i;
+ for (i = 0; i < size && Pos < Size; i++)
+ Data[Pos++] = ((const Byte *)data)[i];
+ if(processedSize != NULL)
+ *processedSize = i;
+ if (i != size)
+ {
+ Overflow = true;
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+#define SZE_FAIL (1)
+#define SZE_OUTOFMEMORY (2)
+#define SZE_OUT_OVERFLOW (3)
+
+int LzmaRamEncode(
+ const Byte *inBuffer, size_t inSize,
+ Byte *outBuffer, size_t outSize, size_t *outSizeProcessed,
+ UInt32 dictionarySize, ESzFilterMode filterMode)
+{
+ #ifndef _NO_EXCEPTIONS
+ try {
+ #endif
+
+ *outSizeProcessed = 0;
+ const size_t kIdSize = 1;
+ const size_t kLzmaPropsSize = 5;
+ const size_t kMinDestSize = kIdSize + kLzmaPropsSize + 8;
+ if (outSize < kMinDestSize)
+ return SZE_OUT_OVERFLOW;
+ NCompress::NLZMA::CEncoder *encoderSpec = new NCompress::NLZMA::CEncoder;
+ CMyComPtr<ICompressCoder> encoder = encoderSpec;
+
+ PROPID propIDs[] =
+ {
+ NCoderPropID::kAlgorithm,
+ NCoderPropID::kDictionarySize,
+ NCoderPropID::kNumFastBytes,
+ };
+ const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]);
+ PROPVARIANT properties[kNumProps];
+ properties[0].vt = VT_UI4;
+ properties[1].vt = VT_UI4;
+ properties[2].vt = VT_UI4;
+ properties[0].ulVal = (UInt32)2;
+ properties[1].ulVal = (UInt32)dictionarySize;
+ properties[2].ulVal = (UInt32)64;
+
+ if (encoderSpec->SetCoderProperties(propIDs, properties, kNumProps) != S_OK)
+ return 1;
+
+ COutStreamRam *outStreamSpec = new COutStreamRam;
+ if (outStreamSpec == 0)
+ return SZE_OUTOFMEMORY;
+ CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+ CInStreamRam *inStreamSpec = new CInStreamRam;
+ if (inStreamSpec == 0)
+ return SZE_OUTOFMEMORY;
+ CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
+
+ outStreamSpec->Init(outBuffer, outSize);
+ if (outStreamSpec->WriteByte(0) != S_OK)
+ return SZE_OUT_OVERFLOW;
+
+ if (encoderSpec->WriteCoderProperties(outStream) != S_OK)
+ return SZE_OUT_OVERFLOW;
+ if (outStreamSpec->Pos != kIdSize + kLzmaPropsSize)
+ return 1;
+
+ int i;
+ for (i = 0; i < 8; i++)
+ {
+ UInt64 t = (UInt64)(inSize);
+ if (outStreamSpec->WriteByte((Byte)((t) >> (8 * i))) != S_OK)
+ return SZE_OUT_OVERFLOW;
+ }
+
+ Byte *filteredStream = 0;
+
+ bool useFilter = (filterMode != SZ_FILTER_NO);
+ if (useFilter)
+ {
+ if (inSize != 0)
+ {
+ filteredStream = (Byte *)MyAlloc(inSize);
+ if (filteredStream == 0)
+ return SZE_OUTOFMEMORY;
+ memmove(filteredStream, inBuffer, inSize);
+ }
+ UInt32 _prevMask;
+ UInt32 _prevPos;
+ x86_Convert_Init(_prevMask, _prevPos);
+ x86_Convert(filteredStream, (UInt32)inSize, 0, &_prevMask, &_prevPos, 1);
+ }
+
+ UInt32 minSize = 0;
+ int numPasses = (filterMode == SZ_FILTER_AUTO) ? 3 : 1;
+ bool bestIsFiltered = false;
+ int mainResult = 0;
+ size_t startPos = outStreamSpec->Pos;
+ for (i = 0; i < numPasses; i++)
+ {
+ if (numPasses > 1 && i == numPasses - 1 && !bestIsFiltered)
+ break;
+ outStreamSpec->SetPos(startPos);
+ bool curModeIsFiltered = false;
+ if (useFilter && i == 0)
+ curModeIsFiltered = true;
+ if (numPasses > 1 && i == numPasses - 1)
+ curModeIsFiltered = true;
+
+ inStreamSpec->Init(curModeIsFiltered ? filteredStream : inBuffer, inSize);
+
+ HRESULT lzmaResult = encoder->Code(inStream, outStream, 0, 0, 0);
+
+ mainResult = 0;
+ if (lzmaResult == E_OUTOFMEMORY)
+ {
+ mainResult = SZE_OUTOFMEMORY;
+ break;
+ }
+ if (i == 0 || outStreamSpec->Pos <= minSize)
+ {
+ minSize = outStreamSpec->Pos;
+ bestIsFiltered = curModeIsFiltered;
+ }
+ if (outStreamSpec->Overflow)
+ mainResult = SZE_OUT_OVERFLOW;
+ else if (lzmaResult != S_OK)
+ {
+ mainResult = SZE_FAIL;
+ break;
+ }
+ }
+ *outSizeProcessed = outStreamSpec->Pos;
+ if (bestIsFiltered)
+ outBuffer[0] = 1;
+ if (useFilter)
+ MyFree(filteredStream);
+ return mainResult;
+
+ #ifndef _NO_EXCEPTIONS
+ } catch(...) { return SZE_OUTOFMEMORY; }
+ #endif
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/LzmaRam.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/LzmaRam.h new file mode 100644 index 00000000..74d584d2 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/LzmaRam.h @@ -0,0 +1,46 @@ +// LzmaRam.h
+
+#ifndef __LzmaRam_h
+#define __LzmaRam_h
+
+#include <stdlib.h>
+#include "../../../Common/Types.h"
+
+/*
+LzmaRamEncode: BCJ + LZMA RAM->RAM compressing.
+It uses .lzma format, but it writes one additional byte to .lzma file:
+ 0: - no filter
+ 1: - x86(BCJ) filter.
+
+To provide best compression ratio dictionarySize mustbe >= inSize
+
+LzmaRamEncode allocates Data with MyAlloc/BigAlloc functions.
+RAM Requirements:
+ RamSize = dictionarySize * 9.5 + 6MB + FilterBlockSize
+ FilterBlockSize = 0, if useFilter == false
+ FilterBlockSize = inSize, if useFilter == true
+
+ Return code:
+ 0 - OK
+ 1 - Unspecified Error
+ 2 - Memory allocating error
+ 3 - Output buffer OVERFLOW
+
+If you use SZ_FILTER_AUTO mode, then encoder will use 2 or 3 passes:
+ 2 passes when FILTER_NO provides better compression.
+ 3 passes when FILTER_YES provides better compression.
+*/
+
+enum ESzFilterMode
+{
+ SZ_FILTER_NO,
+ SZ_FILTER_YES,
+ SZ_FILTER_AUTO
+};
+
+int LzmaRamEncode(
+ const Byte *inBuffer, size_t inSize,
+ Byte *outBuffer, size_t outSize, size_t *outSizeProcessed,
+ UInt32 dictionarySize, ESzFilterMode filterMode);
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/LzmaRamDecode.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/LzmaRamDecode.c new file mode 100644 index 00000000..0f0f8424 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/LzmaRamDecode.c @@ -0,0 +1,79 @@ +/* LzmaRamDecode.c */
+
+#include "LzmaRamDecode.h"
+#ifdef _SZ_ONE_DIRECTORY
+#include "LzmaDecode.h"
+#include "BranchX86.h"
+#else
+#include "../LZMA_C/LzmaDecode.h"
+#include "../Branch/BranchX86.h"
+#endif
+
+#define LZMA_PROPS_SIZE 14
+#define LZMA_SIZE_OFFSET 6
+
+int LzmaRamGetUncompressedSize(
+ const unsigned char *inBuffer,
+ size_t inSize,
+ size_t *outSize)
+{
+ unsigned int i;
+ if (inSize < LZMA_PROPS_SIZE)
+ return 1;
+ *outSize = 0;
+ for(i = 0; i < sizeof(size_t); i++)
+ *outSize += ((size_t)inBuffer[LZMA_SIZE_OFFSET + i]) << (8 * i);
+ for(; i < 8; i++)
+ if (inBuffer[LZMA_SIZE_OFFSET + i] != 0)
+ return 1;
+ return 0;
+}
+
+#define SZE_DATA_ERROR (1)
+#define SZE_OUTOFMEMORY (2)
+
+int LzmaRamDecompress(
+ const unsigned char *inBuffer,
+ size_t inSize,
+ unsigned char *outBuffer,
+ size_t outSize,
+ size_t *outSizeProcessed,
+ void * (*allocFunc)(size_t size),
+ void (*freeFunc)(void *))
+{
+ CLzmaDecoderState state; /* it's about 24 bytes structure, if int is 32-bit */
+ int result;
+ SizeT outSizeProcessedLoc;
+ SizeT inProcessed;
+ int useFilter;
+
+ if (inSize < LZMA_PROPS_SIZE)
+ return 1;
+ useFilter = inBuffer[0];
+
+ *outSizeProcessed = 0;
+ if (useFilter > 1)
+ return 1;
+
+ if (LzmaDecodeProperties(&state.Properties, inBuffer + 1, LZMA_PROPERTIES_SIZE) != LZMA_RESULT_OK)
+ return 1;
+ state.Probs = (CProb *)allocFunc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
+ if (state.Probs == 0)
+ return SZE_OUTOFMEMORY;
+
+ result = LzmaDecode(&state,
+ inBuffer + LZMA_PROPS_SIZE, (SizeT)inSize - LZMA_PROPS_SIZE, &inProcessed,
+ outBuffer, (SizeT)outSize, &outSizeProcessedLoc);
+ freeFunc(state.Probs);
+ if (result != LZMA_RESULT_OK)
+ return 1;
+ *outSizeProcessed = (size_t)outSizeProcessedLoc;
+ if (useFilter == 1)
+ {
+ UInt32 _prevMask;
+ UInt32 _prevPos;
+ x86_Convert_Init(_prevMask, _prevPos);
+ x86_Convert(outBuffer, (UInt32)outSizeProcessedLoc, 0, &_prevMask, &_prevPos, 0);
+ }
+ return 0;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/LzmaRamDecode.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/LzmaRamDecode.h new file mode 100644 index 00000000..783734a4 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/LzmaRamDecode.h @@ -0,0 +1,55 @@ +/* LzmaRamDecode.h */
+
+#ifndef __LzmaRamDecode_h
+#define __LzmaRamDecode_h
+
+#include <stdlib.h>
+
+/*
+LzmaRamGetUncompressedSize:
+ In:
+ inBuffer - input data
+ inSize - input data size
+ Out:
+ outSize - uncompressed size
+ Return code:
+ 0 - OK
+ 1 - Error in headers
+*/
+
+int LzmaRamGetUncompressedSize(
+ const unsigned char *inBuffer,
+ size_t inSize,
+ size_t *outSize);
+
+
+/*
+LzmaRamDecompress:
+ In:
+ inBuffer - input data
+ inSize - input data size
+ outBuffer - output data
+ outSize - output size
+ allocFunc - alloc function (can be malloc)
+ freeFunc - free function (can be free)
+ Out:
+ outSizeProcessed - processed size
+ Return code:
+ 0 - OK
+ 1 - Error in headers / data stream
+ 2 - Memory allocating error
+
+Memory requirements depend from properties of LZMA stream.
+With default lzma settings it's about 16 KB.
+*/
+
+int LzmaRamDecompress(
+ const unsigned char *inBuffer,
+ size_t inSize,
+ unsigned char *outBuffer,
+ size_t outSize,
+ size_t *outSizeProcessed,
+ void * (*allocFunc)(size_t size),
+ void (*freeFunc)(void *));
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/StdAfx.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/StdAfx.cpp new file mode 100644 index 00000000..c6d3b1fa --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/StdAfx.cpp @@ -0,0 +1,3 @@ +// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/StdAfx.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/StdAfx.h new file mode 100644 index 00000000..83fdd22d --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/StdAfx.h @@ -0,0 +1,8 @@ +// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/makefile b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/makefile new file mode 100644 index 00000000..5b8d0a32 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/makefile @@ -0,0 +1,100 @@ +PROG = lzma.exe
+CFLAGS = $(CFLAGS) -I ../../../
+LIBS = $(LIBS) oleaut32.lib user32.lib
+
+!IFNDEF O
+!IFDEF CPU
+O=$(CPU)
+!ELSE
+O=O
+!ENDIF
+!ENDIF
+
+CFLAGS = $(CFLAGS) -nologo -EHsc -c -Fo$O/ -GS-
+CFLAGS_O1 = $(CFLAGS) -O1
+CFLAGS_O2 = $(CFLAGS) -O2
+
+LFLAGS = $(LFLAGS) -nologo -OPT:NOWIN98
+
+PROGPATH = $O\$(PROG)
+
+COMPL_O1 = $(CPP) $(CFLAGS_O1) $**
+COMPL_O2 = $(CPP) $(CFLAGS_O2) $**
+COMPL = $(CPP) $(CFLAGS_O1) $**
+
+
+LZMA_OBJS = \
+ $O\LzmaAlone.obj \
+ $O\LzmaBench.obj \
+ $O\LzmaRam.obj \
+
+LZMA_OPT_OBJS = \
+ $O\LZMADecoder.obj \
+ $O\LZMAEncoder.obj \
+
+COMMON_OBJS = \
+ $O\Alloc.obj \
+ $O\CRC.obj \
+ $O\CommandLineParser.obj \
+ $O\String.obj \
+ $O\StringConvert.obj \
+ $O\StringToInt.obj \
+ $O\Vector.obj
+
+7ZIP_COMMON_OBJS = \
+ $O\InBuffer.obj \
+ $O\OutBuffer.obj \
+ $O\StreamUtils.obj \
+
+LZ_OBJS = \
+ $O\LZInWindow.obj \
+ $O\LZOutWindow.obj \
+
+
+OBJS = \
+ $(LZMA_OBJS) \
+ $(LZMA_OPT_OBJS) \
+ $(COMMON_OBJS) \
+ $(7ZIP_COMMON_OBJS) \
+ $(LZ_OBJS) \
+ $O\LzmaRamDecode.obj \
+ $O\LzmaDecode.obj \
+ $O\FileStreams.obj \
+ $O\FileIO.obj \
+ $O\RangeCoderBit.obj \
+ $O\BranchX86.obj \
+
+all: $(PROGPATH)
+
+clean:
+ -del /Q $(PROGPATH) $O\*.exe $O\*.dll $O\*.obj $O\*.lib $O\*.exp $O\*.res $O\*.pch
+
+$O:
+ if not exist "$O" mkdir "$O"
+
+$(PROGPATH): $O $(OBJS)
+ link $(LFLAGS) -out:$(PROGPATH) $(OBJS) $(LIBS)
+
+
+$(LZMA_OBJS): $(*B).cpp
+ $(COMPL)
+$(LZMA_OPT_OBJS): ../LZMA/$(*B).cpp
+ $(COMPL_O2)
+$(COMMON_OBJS): ../../../Common/$(*B).cpp
+ $(COMPL)
+$(7ZIP_COMMON_OBJS): ../../Common/$(*B).cpp
+ $(COMPL)
+$(LZ_OBJS): ../LZ/$(*B).cpp
+ $(COMPL)
+$O\RangeCoderBit.obj: ../RangeCoder/$(*B).cpp
+ $(COMPL)
+$O\LzmaRamDecode.obj: LzmaRamDecode.c
+ $(COMPL_O1)
+$O\LzmaDecode.obj: ../LZMA_C/LzmaDecode.c
+ $(COMPL_O2)
+$O\BranchX86.obj: ../Branch/BranchX86.c
+ $(COMPL_O2)
+$O\FileStreams.obj: ../../Common/FileStreams.cpp
+ $(COMPL)
+$O\FileIO.obj: ../../../Windows/FileIO.cpp
+ $(COMPL)
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/makefile.gcc b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/makefile.gcc new file mode 100644 index 00000000..1e180742 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Alone/makefile.gcc @@ -0,0 +1,113 @@ +PROG = lzma +CXX = g++ -O2 -Wall +CXX_C = gcc -O2 -Wall +LIB = -lm +RM = rm -f +CFLAGS = -c -I ../../../ + +OBJS = \ + LzmaAlone.o \ + LzmaBench.o \ + LzmaRam.o \ + LzmaRamDecode.o \ + LzmaDecode.o \ + BranchX86.o \ + LZMADecoder.o \ + LZMAEncoder.o \ + LZInWindow.o \ + LZOutWindow.o \ + RangeCoderBit.o \ + InBuffer.o \ + OutBuffer.o \ + FileStreams.o \ + StreamUtils.o \ + Alloc.o \ + C_FileIO.o \ + CommandLineParser.o \ + CRC.o \ + String.o \ + StringConvert.o \ + StringToInt.o \ + Vector.o \ + + +all: $(PROG) + +$(PROG): $(OBJS) + $(CXX) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIB) + +LzmaAlone.o: LzmaAlone.cpp + $(CXX) $(CFLAGS) LzmaAlone.cpp + +LzmaBench.o: LzmaBench.cpp + $(CXX) $(CFLAGS) LzmaBench.cpp + +LzmaRam.o: LzmaRam.cpp + $(CXX) $(CFLAGS) LzmaRam.cpp + +LzmaRamDecode.o: LzmaRamDecode.c + $(CXX_C) $(CFLAGS) LzmaRamDecode.c + +LzmaDecode.o: ../LZMA_C/LzmaDecode.c + $(CXX_C) $(CFLAGS) ../LZMA_C/LzmaDecode.c + +BranchX86.o: ../Branch/BranchX86.c + $(CXX_C) $(CFLAGS) ../Branch/BranchX86.c + +LZMADecoder.o: ../LZMA/LZMADecoder.cpp + $(CXX) $(CFLAGS) ../LZMA/LZMADecoder.cpp + +LZMAEncoder.o: ../LZMA/LZMAEncoder.cpp + $(CXX) $(CFLAGS) ../LZMA/LZMAEncoder.cpp + +LZInWindow.o: ../LZ/LZInWindow.cpp + $(CXX) $(CFLAGS) ../LZ/LZInWindow.cpp + +LZOutWindow.o: ../LZ/LZOutWindow.cpp + $(CXX) $(CFLAGS) ../LZ/LZOutWindow.cpp + +RangeCoderBit.o: ../RangeCoder/RangeCoderBit.cpp + $(CXX) $(CFLAGS) ../RangeCoder/RangeCoderBit.cpp + +InBuffer.o: ../../Common/InBuffer.cpp + $(CXX) $(CFLAGS) ../../Common/InBuffer.cpp + +OutBuffer.o: ../../Common/OutBuffer.cpp + $(CXX) $(CFLAGS) ../../Common/OutBuffer.cpp + +FileStreams.o: ../../Common/FileStreams.cpp + $(CXX) $(CFLAGS) ../../Common/FileStreams.cpp + +StreamUtils.o: ../../Common/StreamUtils.cpp + $(CXX) $(CFLAGS) ../../Common/StreamUtils.cpp + +Alloc.o: ../../../Common/Alloc.cpp + $(CXX) $(CFLAGS) ../../../Common/Alloc.cpp + +C_FileIO.o: ../../../Common/C_FileIO.cpp + $(CXX) $(CFLAGS) ../../../Common/C_FileIO.cpp + +CommandLineParser.o: ../../../Common/CommandLineParser.cpp + $(CXX) $(CFLAGS) ../../../Common/CommandLineParser.cpp + +CRC.o: ../../../Common/CRC.cpp + $(CXX) $(CFLAGS) ../../../Common/CRC.cpp + +MyWindows.o: ../../../Common/MyWindows.cpp + $(CXX) $(CFLAGS) ../../../Common/MyWindows.cpp + +String.o: ../../../Common/String.cpp + $(CXX) $(CFLAGS) ../../../Common/String.cpp + +StringConvert.o: ../../../Common/StringConvert.cpp + $(CXX) $(CFLAGS) ../../../Common/StringConvert.cpp + +StringToInt.o: ../../../Common/StringToInt.cpp + $(CXX) $(CFLAGS) ../../../Common/StringToInt.cpp + +Vector.o: ../../../Common/Vector.cpp + $(CXX) $(CFLAGS) ../../../Common/Vector.cpp + +clean: + -$(RM) $(PROG) $(OBJS) + diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/LzmaDecode.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/LzmaDecode.c new file mode 100644 index 00000000..5c9d67f7 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/LzmaDecode.c @@ -0,0 +1,588 @@ +/*
+ LzmaDecode.c
+ LZMA Decoder (optimized for Speed version)
+
+ LZMA SDK 4.22 Copyright (c) 1999-2005 Igor Pavlov (2005-06-10)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this Code, expressly permits you to
+ statically or dynamically link your Code (or bind by name) to the
+ interfaces of this file without subjecting your linked Code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "LzmaDecode.h"
+
+#ifndef Byte
+#define Byte unsigned char
+#endif
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_READ_BYTE (*Buffer++)
+
+#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
+ { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }}
+
+#ifdef _LZMA_IN_CB
+
+#define RC_TEST { if (Buffer == BufferLim) \
+ { SizeT size; int result = InCallback->Read(InCallback, &Buffer, &size); if (result != LZMA_RESULT_OK) return result; \
+ BufferLim = Buffer + size; if (size == 0) return LZMA_RESULT_DATA_ERROR; }}
+
+#define RC_INIT Buffer = BufferLim = 0; RC_INIT2
+
+#else
+
+#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; }
+
+#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2
+
+#endif
+
+#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
+
+#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)
+#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;
+#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;
+
+#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \
+ { UpdateBit0(p); mi <<= 1; A0; } else \
+ { UpdateBit1(p); mi = (mi + mi) + 1; A1; }
+
+#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;)
+
+#define RangeDecoderBitTreeDecode(probs, numLevels, res) \
+ { int i = numLevels; res = 1; \
+ do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \
+ res -= (1 << numLevels); }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
+{
+ unsigned char prop0;
+ if (size < LZMA_PROPERTIES_SIZE)
+ return LZMA_RESULT_DATA_ERROR;
+ prop0 = propsData[0];
+ if (prop0 >= (9 * 5 * 5))
+ return LZMA_RESULT_DATA_ERROR;
+ {
+ for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));
+ for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);
+ propsRes->lc = prop0;
+ /*
+ unsigned char remainder = (unsigned char)(prop0 / 9);
+ propsRes->lc = prop0 % 9;
+ propsRes->pb = remainder / 5;
+ propsRes->lp = remainder % 5;
+ */
+ }
+
+ #ifdef _LZMA_OUT_READ
+ {
+ int i;
+ propsRes->DictionarySize = 0;
+ for (i = 0; i < 4; i++)
+ propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8);
+ if (propsRes->DictionarySize == 0)
+ propsRes->DictionarySize = 1;
+ }
+ #endif
+ return LZMA_RESULT_OK;
+}
+
+#define kLzmaStreamWasFinishedId (-1)
+
+int LzmaDecode(CLzmaDecoderState *vs,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *InCallback,
+ #else
+ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+ #endif
+ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
+{
+ CProb *p = vs->Probs;
+ SizeT nowPos = 0;
+ Byte previousByte = 0;
+ UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
+ UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
+ int lc = vs->Properties.lc;
+
+ #ifdef _LZMA_OUT_READ
+
+ UInt32 Range = vs->Range;
+ UInt32 Code = vs->Code;
+ #ifdef _LZMA_IN_CB
+ const Byte *Buffer = vs->Buffer;
+ const Byte *BufferLim = vs->BufferLim;
+ #else
+ const Byte *Buffer = inStream;
+ const Byte *BufferLim = inStream + inSize;
+ #endif
+ int state = vs->State;
+ UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
+ int len = vs->RemainLen;
+ UInt32 globalPos = vs->GlobalPos;
+ UInt32 distanceLimit = vs->DistanceLimit;
+
+ Byte *dictionary = vs->Dictionary;
+ UInt32 dictionarySize = vs->Properties.DictionarySize;
+ UInt32 dictionaryPos = vs->DictionaryPos;
+
+ Byte tempDictionary[4];
+
+ #ifndef _LZMA_IN_CB
+ *inSizeProcessed = 0;
+ #endif
+ *outSizeProcessed = 0;
+ if (len == kLzmaStreamWasFinishedId)
+ return LZMA_RESULT_OK;
+
+ if (dictionarySize == 0)
+ {
+ dictionary = tempDictionary;
+ dictionarySize = 1;
+ tempDictionary[0] = vs->TempDictionary[0];
+ }
+
+ if (len == kLzmaNeedInitId)
+ {
+ {
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+ UInt32 i;
+ for (i = 0; i < numProbs; i++)
+ p[i] = kBitModelTotal >> 1;
+ rep0 = rep1 = rep2 = rep3 = 1;
+ state = 0;
+ globalPos = 0;
+ distanceLimit = 0;
+ dictionaryPos = 0;
+ dictionary[dictionarySize - 1] = 0;
+ #ifdef _LZMA_IN_CB
+ RC_INIT;
+ #else
+ RC_INIT(inStream, inSize);
+ #endif
+ }
+ len = 0;
+ }
+ while(len != 0 && nowPos < outSize)
+ {
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ len--;
+ }
+ if (dictionaryPos == 0)
+ previousByte = dictionary[dictionarySize - 1];
+ else
+ previousByte = dictionary[dictionaryPos - 1];
+
+ #else /* if !_LZMA_OUT_READ */
+
+ int state = 0;
+ UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+ int len = 0;
+ const Byte *Buffer;
+ const Byte *BufferLim;
+ UInt32 Range;
+ UInt32 Code;
+
+ #ifndef _LZMA_IN_CB
+ *inSizeProcessed = 0;
+ #endif
+ *outSizeProcessed = 0;
+
+ {
+ UInt32 i;
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+ for (i = 0; i < numProbs; i++)
+ p[i] = kBitModelTotal >> 1;
+ }
+
+ #ifdef _LZMA_IN_CB
+ RC_INIT;
+ #else
+ RC_INIT(inStream, inSize);
+ #endif
+
+ #endif /* _LZMA_OUT_READ */
+
+ while(nowPos < outSize)
+ {
+ CProb *prob;
+ UInt32 bound;
+ int posState = (int)(
+ (nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ & posStateMask);
+
+ prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
+ IfBit0(prob)
+ {
+ int symbol = 1;
+ UpdateBit0(prob)
+ prob = p + Literal + (LZMA_LIT_SIZE *
+ (((
+ (nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ & literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+ if (state >= kNumLitStates)
+ {
+ int matchByte;
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ matchByte = dictionary[pos];
+ #else
+ matchByte = outStream[nowPos - rep0];
+ #endif
+ do
+ {
+ int bit;
+ CProb *probLit;
+ matchByte <<= 1;
+ bit = (matchByte & 0x100);
+ probLit = prob + 0x100 + bit + symbol;
+ RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break)
+ }
+ while (symbol < 0x100);
+ }
+ while (symbol < 0x100)
+ {
+ CProb *probLit = prob + symbol;
+ RC_GET_BIT(probLit, symbol)
+ }
+ previousByte = (Byte)symbol;
+
+ outStream[nowPos++] = previousByte;
+ #ifdef _LZMA_OUT_READ
+ if (distanceLimit < dictionarySize)
+ distanceLimit++;
+
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #endif
+ if (state < 4) state = 0;
+ else if (state < 10) state -= 3;
+ else state -= 6;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ prob = p + IsRep + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ state = state < kNumLitStates ? 0 : 3;
+ prob = p + LenCoder;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ prob = p + IsRepG0 + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ IfBit0(prob)
+ {
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos;
+ #endif
+ UpdateBit0(prob);
+
+ #ifdef _LZMA_OUT_READ
+ if (distanceLimit == 0)
+ #else
+ if (nowPos == 0)
+ #endif
+ return LZMA_RESULT_DATA_ERROR;
+
+ state = state < kNumLitStates ? 9 : 11;
+ #ifdef _LZMA_OUT_READ
+ pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ previousByte = dictionary[pos];
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #else
+ previousByte = outStream[nowPos - rep0];
+ #endif
+ outStream[nowPos++] = previousByte;
+ #ifdef _LZMA_OUT_READ
+ if (distanceLimit < dictionarySize)
+ distanceLimit++;
+ #endif
+
+ continue;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ }
+ }
+ else
+ {
+ UInt32 distance;
+ UpdateBit1(prob);
+ prob = p + IsRepG1 + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ distance = rep1;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ prob = p + IsRepG2 + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ distance = rep2;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ state = state < kNumLitStates ? 8 : 11;
+ prob = p + RepLenCoder;
+ }
+ {
+ int numBits, offset;
+ CProb *probLen = prob + LenChoice;
+ IfBit0(probLen)
+ {
+ UpdateBit0(probLen);
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ numBits = kLenNumLowBits;
+ }
+ else
+ {
+ UpdateBit1(probLen);
+ probLen = prob + LenChoice2;
+ IfBit0(probLen)
+ {
+ UpdateBit0(probLen);
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ numBits = kLenNumMidBits;
+ }
+ else
+ {
+ UpdateBit1(probLen);
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ numBits = kLenNumHighBits;
+ }
+ }
+ RangeDecoderBitTreeDecode(probLen, numBits, len);
+ len += offset;
+ }
+
+ if (state < 4)
+ {
+ int posSlot;
+ state += kNumLitStates;
+ prob = p + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits);
+ RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ int numDirectBits = ((posSlot >> 1) - 1);
+ rep0 = (2 | ((UInt32)posSlot & 1));
+ if (posSlot < kEndPosModelIndex)
+ {
+ rep0 <<= numDirectBits;
+ prob = p + SpecPos + rep0 - posSlot - 1;
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ RC_NORMALIZE
+ Range >>= 1;
+ rep0 <<= 1;
+ if (Code >= Range)
+ {
+ Code -= Range;
+ rep0 |= 1;
+ }
+ }
+ while (--numDirectBits != 0);
+ prob = p + Align;
+ rep0 <<= kNumAlignBits;
+ numDirectBits = kNumAlignBits;
+ }
+ {
+ int i = 1;
+ int mi = 1;
+ do
+ {
+ CProb *prob3 = prob + mi;
+ RC_GET_BIT2(prob3, mi, ; , rep0 |= i);
+ i <<= 1;
+ }
+ while(--numDirectBits != 0);
+ }
+ }
+ else
+ rep0 = posSlot;
+ if (++rep0 == (UInt32)(0))
+ {
+ /* it's for stream version */
+ len = kLzmaStreamWasFinishedId;
+ break;
+ }
+ }
+
+ len += kMatchMinLen;
+ #ifdef _LZMA_OUT_READ
+ if (rep0 > distanceLimit)
+ #else
+ if (rep0 > nowPos)
+ #endif
+ return LZMA_RESULT_DATA_ERROR;
+
+ #ifdef _LZMA_OUT_READ
+ if (dictionarySize - distanceLimit > (UInt32)len)
+ distanceLimit += len;
+ else
+ distanceLimit = dictionarySize;
+ #endif
+
+ do
+ {
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ previousByte = dictionary[pos];
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #else
+ previousByte = outStream[nowPos - rep0];
+ #endif
+ len--;
+ outStream[nowPos++] = previousByte;
+ }
+ while(len != 0 && nowPos < outSize);
+ }
+ }
+ RC_NORMALIZE;
+
+ #ifdef _LZMA_OUT_READ
+ vs->Range = Range;
+ vs->Code = Code;
+ vs->DictionaryPos = dictionaryPos;
+ vs->GlobalPos = globalPos + (UInt32)nowPos;
+ vs->DistanceLimit = distanceLimit;
+ vs->Reps[0] = rep0;
+ vs->Reps[1] = rep1;
+ vs->Reps[2] = rep2;
+ vs->Reps[3] = rep3;
+ vs->State = state;
+ vs->RemainLen = len;
+ vs->TempDictionary[0] = tempDictionary[0];
+ #endif
+
+ #ifdef _LZMA_IN_CB
+ vs->Buffer = Buffer;
+ vs->BufferLim = BufferLim;
+ #else
+ *inSizeProcessed = (SizeT)(Buffer - inStream);
+ #endif
+ *outSizeProcessed = nowPos;
+ return LZMA_RESULT_OK;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/LzmaDecode.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/LzmaDecode.h new file mode 100644 index 00000000..35e37ed0 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/LzmaDecode.h @@ -0,0 +1,131 @@ +/*
+ LzmaDecode.h
+ LZMA Decoder interface
+
+ LZMA SDK 4.21 Copyright (c) 1999-2005 Igor Pavlov (2005-06-08)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this code, expressly permits you to
+ statically or dynamically link your code (or bind by name) to the
+ interfaces of this file without subjecting your linked code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMADECODE_H
+#define __LZMADECODE_H
+
+/* #define _LZMA_IN_CB */
+/* Use callback for input data */
+
+/* #define _LZMA_OUT_READ */
+/* Use read function for output data */
+
+/* #define _LZMA_PROB32 */
+/* It can increase speed on some 32-bit CPUs,
+ but memory usage will be doubled in that case */
+
+/* #define _LZMA_LOC_OPT */
+/* Enable local speed optimizations inside code */
+
+/* #define _LZMA_SYSTEM_SIZE_T */
+/* Use system's size_t. You can use it to enable 64-bit sizes supporting*/
+
+#ifndef UInt32
+#ifdef _LZMA_UINT32_IS_ULONG
+#define UInt32 unsigned long
+#else
+#define UInt32 unsigned int
+#endif
+#endif
+
+#ifndef SizeT
+#ifdef _LZMA_SYSTEM_SIZE_T
+#include <stddef.h>
+#define SizeT size_t
+#else
+#define SizeT UInt32
+#endif
+#endif
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb unsigned short
+#endif
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+
+#ifdef _LZMA_IN_CB
+typedef struct _ILzmaInCallback
+{
+ int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize);
+} ILzmaInCallback;
+#endif
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LZMA_PROPERTIES_SIZE 5
+
+typedef struct _CLzmaProperties
+{
+ int lc;
+ int lp;
+ int pb;
+ #ifdef _LZMA_OUT_READ
+ UInt32 DictionarySize;
+ #endif
+}CLzmaProperties;
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size);
+
+#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp)))
+
+#define kLzmaNeedInitId (-2)
+
+typedef struct _CLzmaDecoderState
+{
+ CLzmaProperties Properties;
+ CProb *Probs;
+
+ #ifdef _LZMA_IN_CB
+ const unsigned char *Buffer;
+ const unsigned char *BufferLim;
+ #endif
+
+ #ifdef _LZMA_OUT_READ
+ unsigned char *Dictionary;
+ UInt32 Range;
+ UInt32 Code;
+ UInt32 DictionaryPos;
+ UInt32 GlobalPos;
+ UInt32 DistanceLimit;
+ UInt32 Reps[4];
+ int State;
+ int RemainLen;
+ unsigned char TempDictionary[4];
+ #endif
+} CLzmaDecoderState;
+
+#ifdef _LZMA_OUT_READ
+#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; }
+#endif
+
+int LzmaDecode(CLzmaDecoderState *vs,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback,
+ #else
+ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+ #endif
+ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed);
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/LzmaDecodeSize.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/LzmaDecodeSize.c new file mode 100644 index 00000000..fe24cf21 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/LzmaDecodeSize.c @@ -0,0 +1,716 @@ +/*
+ LzmaDecodeSize.c
+ LZMA Decoder (optimized for Size version)
+
+ LZMA SDK 4.27 Copyright (c) 1999-2005 Igor Pavlov (2005-08-07)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this code, expressly permits you to
+ statically or dynamically link your code (or bind by name) to the
+ interfaces of this file without subjecting your linked code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "LzmaDecode.h"
+
+#ifndef Byte
+#define Byte unsigned char
+#endif
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+typedef struct _CRangeDecoder
+{
+ const Byte *Buffer;
+ const Byte *BufferLim;
+ UInt32 Range;
+ UInt32 Code;
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *InCallback;
+ int Result;
+ #endif
+ int ExtraBytes;
+} CRangeDecoder;
+
+Byte RangeDecoderReadByte(CRangeDecoder *rd)
+{
+ if (rd->Buffer == rd->BufferLim)
+ {
+ #ifdef _LZMA_IN_CB
+ SizeT size;
+ rd->Result = rd->InCallback->Read(rd->InCallback, &rd->Buffer, &size);
+ rd->BufferLim = rd->Buffer + size;
+ if (size == 0)
+ #endif
+ {
+ rd->ExtraBytes = 1;
+ return 0xFF;
+ }
+ }
+ return (*rd->Buffer++);
+}
+
+/* #define ReadByte (*rd->Buffer++) */
+#define ReadByte (RangeDecoderReadByte(rd))
+
+void RangeDecoderInit(CRangeDecoder *rd
+ #ifndef _LZMA_IN_CB
+ , const Byte *stream, SizeT bufferSize
+ #endif
+ )
+{
+ int i;
+ #ifdef _LZMA_IN_CB
+ rd->Buffer = rd->BufferLim = 0;
+ #else
+ rd->Buffer = stream;
+ rd->BufferLim = stream + bufferSize;
+ #endif
+ rd->ExtraBytes = 0;
+ rd->Code = 0;
+ rd->Range = (0xFFFFFFFF);
+ for(i = 0; i < 5; i++)
+ rd->Code = (rd->Code << 8) | ReadByte;
+}
+
+#define RC_INIT_VAR UInt32 range = rd->Range; UInt32 code = rd->Code;
+#define RC_FLUSH_VAR rd->Range = range; rd->Code = code;
+#define RC_NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | ReadByte; }
+
+UInt32 RangeDecoderDecodeDirectBits(CRangeDecoder *rd, int numTotalBits)
+{
+ RC_INIT_VAR
+ UInt32 result = 0;
+ int i;
+ for (i = numTotalBits; i != 0; i--)
+ {
+ /* UInt32 t; */
+ range >>= 1;
+
+ result <<= 1;
+ if (code >= range)
+ {
+ code -= range;
+ result |= 1;
+ }
+ /*
+ t = (code - range) >> 31;
+ t &= 1;
+ code -= range & (t - 1);
+ result = (result + result) | (1 - t);
+ */
+ RC_NORMALIZE
+ }
+ RC_FLUSH_VAR
+ return result;
+}
+
+int RangeDecoderBitDecode(CProb *prob, CRangeDecoder *rd)
+{
+ UInt32 bound = (rd->Range >> kNumBitModelTotalBits) * *prob;
+ if (rd->Code < bound)
+ {
+ rd->Range = bound;
+ *prob += (kBitModelTotal - *prob) >> kNumMoveBits;
+ if (rd->Range < kTopValue)
+ {
+ rd->Code = (rd->Code << 8) | ReadByte;
+ rd->Range <<= 8;
+ }
+ return 0;
+ }
+ else
+ {
+ rd->Range -= bound;
+ rd->Code -= bound;
+ *prob -= (*prob) >> kNumMoveBits;
+ if (rd->Range < kTopValue)
+ {
+ rd->Code = (rd->Code << 8) | ReadByte;
+ rd->Range <<= 8;
+ }
+ return 1;
+ }
+}
+
+#define RC_GET_BIT2(prob, mi, A0, A1) \
+ UInt32 bound = (range >> kNumBitModelTotalBits) * *prob; \
+ if (code < bound) \
+ { A0; range = bound; *prob += (kBitModelTotal - *prob) >> kNumMoveBits; mi <<= 1; } \
+ else \
+ { A1; range -= bound; code -= bound; *prob -= (*prob) >> kNumMoveBits; mi = (mi + mi) + 1; } \
+ RC_NORMALIZE
+
+#define RC_GET_BIT(prob, mi) RC_GET_BIT2(prob, mi, ; , ;)
+
+int RangeDecoderBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
+{
+ int mi = 1;
+ int i;
+ #ifdef _LZMA_LOC_OPT
+ RC_INIT_VAR
+ #endif
+ for(i = numLevels; i != 0; i--)
+ {
+ #ifdef _LZMA_LOC_OPT
+ CProb *prob = probs + mi;
+ RC_GET_BIT(prob, mi)
+ #else
+ mi = (mi + mi) + RangeDecoderBitDecode(probs + mi, rd);
+ #endif
+ }
+ #ifdef _LZMA_LOC_OPT
+ RC_FLUSH_VAR
+ #endif
+ return mi - (1 << numLevels);
+}
+
+int RangeDecoderReverseBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
+{
+ int mi = 1;
+ int i;
+ int symbol = 0;
+ #ifdef _LZMA_LOC_OPT
+ RC_INIT_VAR
+ #endif
+ for(i = 0; i < numLevels; i++)
+ {
+ #ifdef _LZMA_LOC_OPT
+ CProb *prob = probs + mi;
+ RC_GET_BIT2(prob, mi, ; , symbol |= (1 << i))
+ #else
+ int bit = RangeDecoderBitDecode(probs + mi, rd);
+ mi = mi + mi + bit;
+ symbol |= (bit << i);
+ #endif
+ }
+ #ifdef _LZMA_LOC_OPT
+ RC_FLUSH_VAR
+ #endif
+ return symbol;
+}
+
+Byte LzmaLiteralDecode(CProb *probs, CRangeDecoder *rd)
+{
+ int symbol = 1;
+ #ifdef _LZMA_LOC_OPT
+ RC_INIT_VAR
+ #endif
+ do
+ {
+ #ifdef _LZMA_LOC_OPT
+ CProb *prob = probs + symbol;
+ RC_GET_BIT(prob, symbol)
+ #else
+ symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
+ #endif
+ }
+ while (symbol < 0x100);
+ #ifdef _LZMA_LOC_OPT
+ RC_FLUSH_VAR
+ #endif
+ return symbol;
+}
+
+Byte LzmaLiteralDecodeMatch(CProb *probs, CRangeDecoder *rd, Byte matchByte)
+{
+ int symbol = 1;
+ #ifdef _LZMA_LOC_OPT
+ RC_INIT_VAR
+ #endif
+ do
+ {
+ int bit;
+ int matchBit = (matchByte >> 7) & 1;
+ matchByte <<= 1;
+ #ifdef _LZMA_LOC_OPT
+ {
+ CProb *prob = probs + 0x100 + (matchBit << 8) + symbol;
+ RC_GET_BIT2(prob, symbol, bit = 0, bit = 1)
+ }
+ #else
+ bit = RangeDecoderBitDecode(probs + 0x100 + (matchBit << 8) + symbol, rd);
+ symbol = (symbol << 1) | bit;
+ #endif
+ if (matchBit != bit)
+ {
+ while (symbol < 0x100)
+ {
+ #ifdef _LZMA_LOC_OPT
+ CProb *prob = probs + symbol;
+ RC_GET_BIT(prob, symbol)
+ #else
+ symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
+ #endif
+ }
+ break;
+ }
+ }
+ while (symbol < 0x100);
+ #ifdef _LZMA_LOC_OPT
+ RC_FLUSH_VAR
+ #endif
+ return symbol;
+}
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+int LzmaLenDecode(CProb *p, CRangeDecoder *rd, int posState)
+{
+ if(RangeDecoderBitDecode(p + LenChoice, rd) == 0)
+ return RangeDecoderBitTreeDecode(p + LenLow +
+ (posState << kLenNumLowBits), kLenNumLowBits, rd);
+ if(RangeDecoderBitDecode(p + LenChoice2, rd) == 0)
+ return kLenNumLowSymbols + RangeDecoderBitTreeDecode(p + LenMid +
+ (posState << kLenNumMidBits), kLenNumMidBits, rd);
+ return kLenNumLowSymbols + kLenNumMidSymbols +
+ RangeDecoderBitTreeDecode(p + LenHigh, kLenNumHighBits, rd);
+}
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
+{
+ unsigned char prop0;
+ if (size < LZMA_PROPERTIES_SIZE)
+ return LZMA_RESULT_DATA_ERROR;
+ prop0 = propsData[0];
+ if (prop0 >= (9 * 5 * 5))
+ return LZMA_RESULT_DATA_ERROR;
+ {
+ for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));
+ for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);
+ propsRes->lc = prop0;
+ /*
+ unsigned char remainder = (unsigned char)(prop0 / 9);
+ propsRes->lc = prop0 % 9;
+ propsRes->pb = remainder / 5;
+ propsRes->lp = remainder % 5;
+ */
+ }
+
+ #ifdef _LZMA_OUT_READ
+ {
+ int i;
+ propsRes->DictionarySize = 0;
+ for (i = 0; i < 4; i++)
+ propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8);
+ if (propsRes->DictionarySize == 0)
+ propsRes->DictionarySize = 1;
+ }
+ #endif
+ return LZMA_RESULT_OK;
+}
+
+#define kLzmaStreamWasFinishedId (-1)
+
+int LzmaDecode(CLzmaDecoderState *vs,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *InCallback,
+ #else
+ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+ #endif
+ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
+{
+ CProb *p = vs->Probs;
+ SizeT nowPos = 0;
+ Byte previousByte = 0;
+ UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
+ UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
+ int lc = vs->Properties.lc;
+ CRangeDecoder rd;
+
+ #ifdef _LZMA_OUT_READ
+
+ int state = vs->State;
+ UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
+ int len = vs->RemainLen;
+ UInt32 globalPos = vs->GlobalPos;
+ UInt32 distanceLimit = vs->DistanceLimit;
+
+ Byte *dictionary = vs->Dictionary;
+ UInt32 dictionarySize = vs->Properties.DictionarySize;
+ UInt32 dictionaryPos = vs->DictionaryPos;
+
+ Byte tempDictionary[4];
+
+ rd.Range = vs->Range;
+ rd.Code = vs->Code;
+ #ifdef _LZMA_IN_CB
+ rd.InCallback = InCallback;
+ rd.Buffer = vs->Buffer;
+ rd.BufferLim = vs->BufferLim;
+ #else
+ rd.Buffer = inStream;
+ rd.BufferLim = inStream + inSize;
+ #endif
+
+ #ifndef _LZMA_IN_CB
+ *inSizeProcessed = 0;
+ #endif
+ *outSizeProcessed = 0;
+ if (len == kLzmaStreamWasFinishedId)
+ return LZMA_RESULT_OK;
+
+ if (dictionarySize == 0)
+ {
+ dictionary = tempDictionary;
+ dictionarySize = 1;
+ tempDictionary[0] = vs->TempDictionary[0];
+ }
+
+ if (len == kLzmaNeedInitId)
+ {
+ {
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+ UInt32 i;
+ for (i = 0; i < numProbs; i++)
+ p[i] = kBitModelTotal >> 1;
+ rep0 = rep1 = rep2 = rep3 = 1;
+ state = 0;
+ globalPos = 0;
+ distanceLimit = 0;
+ dictionaryPos = 0;
+ dictionary[dictionarySize - 1] = 0;
+ RangeDecoderInit(&rd
+ #ifndef _LZMA_IN_CB
+ , inStream, inSize
+ #endif
+ );
+ #ifdef _LZMA_IN_CB
+ if (rd.Result != LZMA_RESULT_OK)
+ return rd.Result;
+ #endif
+ if (rd.ExtraBytes != 0)
+ return LZMA_RESULT_DATA_ERROR;
+ }
+ len = 0;
+ }
+ while(len != 0 && nowPos < outSize)
+ {
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ len--;
+ }
+ if (dictionaryPos == 0)
+ previousByte = dictionary[dictionarySize - 1];
+ else
+ previousByte = dictionary[dictionaryPos - 1];
+
+ #ifdef _LZMA_IN_CB
+ rd.Result = LZMA_RESULT_OK;
+ #endif
+ rd.ExtraBytes = 0;
+
+ #else /* if !_LZMA_OUT_READ */
+
+ int state = 0;
+ UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+ int len = 0;
+
+ #ifndef _LZMA_IN_CB
+ *inSizeProcessed = 0;
+ #endif
+ *outSizeProcessed = 0;
+
+ {
+ UInt32 i;
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+ for (i = 0; i < numProbs; i++)
+ p[i] = kBitModelTotal >> 1;
+ }
+
+ #ifdef _LZMA_IN_CB
+ rd.InCallback = InCallback;
+ #endif
+ RangeDecoderInit(&rd
+ #ifndef _LZMA_IN_CB
+ , inStream, inSize
+ #endif
+ );
+
+ #ifdef _LZMA_IN_CB
+ if (rd.Result != LZMA_RESULT_OK)
+ return rd.Result;
+ #endif
+ if (rd.ExtraBytes != 0)
+ return LZMA_RESULT_DATA_ERROR;
+
+ #endif /* _LZMA_OUT_READ */
+
+
+ while(nowPos < outSize)
+ {
+ int posState = (int)(
+ (nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ & posStateMask);
+ #ifdef _LZMA_IN_CB
+ if (rd.Result != LZMA_RESULT_OK)
+ return rd.Result;
+ #endif
+ if (rd.ExtraBytes != 0)
+ return LZMA_RESULT_DATA_ERROR;
+ if (RangeDecoderBitDecode(p + IsMatch + (state << kNumPosBitsMax) + posState, &rd) == 0)
+ {
+ CProb *probs = p + Literal + (LZMA_LIT_SIZE *
+ (((
+ (nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ & literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+ if (state >= kNumLitStates)
+ {
+ Byte matchByte;
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ matchByte = dictionary[pos];
+ #else
+ matchByte = outStream[nowPos - rep0];
+ #endif
+ previousByte = LzmaLiteralDecodeMatch(probs, &rd, matchByte);
+ }
+ else
+ previousByte = LzmaLiteralDecode(probs, &rd);
+ outStream[nowPos++] = previousByte;
+ #ifdef _LZMA_OUT_READ
+ if (distanceLimit < dictionarySize)
+ distanceLimit++;
+
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #endif
+ if (state < 4) state = 0;
+ else if (state < 10) state -= 3;
+ else state -= 6;
+ }
+ else
+ {
+ if (RangeDecoderBitDecode(p + IsRep + state, &rd) == 1)
+ {
+ if (RangeDecoderBitDecode(p + IsRepG0 + state, &rd) == 0)
+ {
+ if (RangeDecoderBitDecode(p + IsRep0Long + (state << kNumPosBitsMax) + posState, &rd) == 0)
+ {
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos;
+ #endif
+
+ #ifdef _LZMA_OUT_READ
+ if (distanceLimit == 0)
+ #else
+ if (nowPos == 0)
+ #endif
+ return LZMA_RESULT_DATA_ERROR;
+
+ state = state < 7 ? 9 : 11;
+ #ifdef _LZMA_OUT_READ
+ pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ previousByte = dictionary[pos];
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #else
+ previousByte = outStream[nowPos - rep0];
+ #endif
+ outStream[nowPos++] = previousByte;
+
+ #ifdef _LZMA_OUT_READ
+ if (distanceLimit < dictionarySize)
+ distanceLimit++;
+ #endif
+ continue;
+ }
+ }
+ else
+ {
+ UInt32 distance;
+ if(RangeDecoderBitDecode(p + IsRepG1 + state, &rd) == 0)
+ distance = rep1;
+ else
+ {
+ if(RangeDecoderBitDecode(p + IsRepG2 + state, &rd) == 0)
+ distance = rep2;
+ else
+ {
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ len = LzmaLenDecode(p + RepLenCoder, &rd, posState);
+ state = state < 7 ? 8 : 11;
+ }
+ else
+ {
+ int posSlot;
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ state = state < 7 ? 7 : 10;
+ len = LzmaLenDecode(p + LenCoder, &rd, posState);
+ posSlot = RangeDecoderBitTreeDecode(p + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits), kNumPosSlotBits, &rd);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ int numDirectBits = ((posSlot >> 1) - 1);
+ rep0 = ((2 | ((UInt32)posSlot & 1)) << numDirectBits);
+ if (posSlot < kEndPosModelIndex)
+ {
+ rep0 += RangeDecoderReverseBitTreeDecode(
+ p + SpecPos + rep0 - posSlot - 1, numDirectBits, &rd);
+ }
+ else
+ {
+ rep0 += RangeDecoderDecodeDirectBits(&rd,
+ numDirectBits - kNumAlignBits) << kNumAlignBits;
+ rep0 += RangeDecoderReverseBitTreeDecode(p + Align, kNumAlignBits, &rd);
+ }
+ }
+ else
+ rep0 = posSlot;
+ if (++rep0 == (UInt32)(0))
+ {
+ /* it's for stream version */
+ len = kLzmaStreamWasFinishedId;
+ break;
+ }
+ }
+
+ len += kMatchMinLen;
+ #ifdef _LZMA_OUT_READ
+ if (rep0 > distanceLimit)
+ #else
+ if (rep0 > nowPos)
+ #endif
+ return LZMA_RESULT_DATA_ERROR;
+
+ #ifdef _LZMA_OUT_READ
+ if (dictionarySize - distanceLimit > (UInt32)len)
+ distanceLimit += len;
+ else
+ distanceLimit = dictionarySize;
+ #endif
+
+ do
+ {
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ previousByte = dictionary[pos];
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #else
+ previousByte = outStream[nowPos - rep0];
+ #endif
+ len--;
+ outStream[nowPos++] = previousByte;
+ }
+ while(len != 0 && nowPos < outSize);
+ }
+ }
+
+
+ #ifdef _LZMA_OUT_READ
+ vs->Range = rd.Range;
+ vs->Code = rd.Code;
+ vs->DictionaryPos = dictionaryPos;
+ vs->GlobalPos = globalPos + (UInt32)nowPos;
+ vs->DistanceLimit = distanceLimit;
+ vs->Reps[0] = rep0;
+ vs->Reps[1] = rep1;
+ vs->Reps[2] = rep2;
+ vs->Reps[3] = rep3;
+ vs->State = state;
+ vs->RemainLen = len;
+ vs->TempDictionary[0] = tempDictionary[0];
+ #endif
+
+ #ifdef _LZMA_IN_CB
+ vs->Buffer = rd.Buffer;
+ vs->BufferLim = rd.BufferLim;
+ #else
+ *inSizeProcessed = (SizeT)(rd.Buffer - inStream);
+ #endif
+ *outSizeProcessed = nowPos;
+ return LZMA_RESULT_OK;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/LzmaStateDecode.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/LzmaStateDecode.c new file mode 100644 index 00000000..8ddb6ee1 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/LzmaStateDecode.c @@ -0,0 +1,521 @@ +/*
+ LzmaStateDecode.c
+ LZMA Decoder (State version)
+
+ LZMA SDK 4.21 Copyright (c) 1999-2005 Igor Pavlov (2005-06-08)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this Code, expressly permits you to
+ statically or dynamically link your Code (or bind by name) to the
+ interfaces of this file without subjecting your linked Code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "LzmaStateDecode.h"
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_READ_BYTE (*Buffer++)
+
+#define RC_INIT Code = 0; Range = 0xFFFFFFFF; \
+ { int i; for(i = 0; i < 5; i++) { Code = (Code << 8) | RC_READ_BYTE; }}
+
+#define RC_NORMALIZE if (Range < kTopValue) { Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
+
+#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)
+#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;
+#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;
+
+#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \
+ { UpdateBit0(p); mi <<= 1; A0; } else \
+ { UpdateBit1(p); mi = (mi + mi) + 1; A1; }
+
+#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;)
+
+#define RangeDecoderBitTreeDecode(probs, numLevels, res) \
+ { int i = numLevels; res = 1; \
+ do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \
+ res -= (1 << numLevels); }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+/* kRequiredInBufferSize = number of required input bytes for worst case:
+ longest match with longest distance.
+ kLzmaInBufferSize must be larger than kRequiredInBufferSize
+ 23 bits = 2 (match select) + 10 (len) + 6 (distance) + 4(align) + 1 (RC_NORMALIZE)
+*/
+
+#define kRequiredInBufferSize ((23 * (kNumBitModelTotalBits - kNumMoveBits + 1) + 26 + 9) / 8)
+
+#define kLzmaStreamWasFinishedId (-1)
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
+{
+ unsigned char prop0;
+ if (size < LZMA_PROPERTIES_SIZE)
+ return LZMA_RESULT_DATA_ERROR;
+ prop0 = propsData[0];
+ if (prop0 >= (9 * 5 * 5))
+ return LZMA_RESULT_DATA_ERROR;
+ {
+ for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));
+ for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);
+ propsRes->lc = prop0;
+ /*
+ unsigned char remainder = (unsigned char)(prop0 / 9);
+ propsRes->lc = prop0 % 9;
+ propsRes->pb = remainder / 5;
+ propsRes->lp = remainder % 5;
+ */
+ }
+
+ {
+ int i;
+ propsRes->DictionarySize = 0;
+ for (i = 0; i < 4; i++)
+ propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8);
+ if (propsRes->DictionarySize == 0)
+ propsRes->DictionarySize = 1;
+ return LZMA_RESULT_OK;
+ }
+}
+
+int LzmaDecode(
+ CLzmaDecoderState *vs,
+ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed,
+ int finishDecoding)
+{
+ UInt32 Range = vs->Range;
+ UInt32 Code = vs->Code;
+
+ unsigned char *Buffer = vs->Buffer;
+ int BufferSize = vs->BufferSize; /* don't change it to unsigned int */
+ CProb *p = vs->Probs;
+
+ int state = vs->State;
+ unsigned char previousByte;
+ UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
+ SizeT nowPos = 0;
+ UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
+ UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
+ int lc = vs->Properties.lc;
+ int len = vs->RemainLen;
+ UInt32 globalPos = vs->GlobalPos;
+ UInt32 distanceLimit = vs->DistanceLimit;
+
+ unsigned char *dictionary = vs->Dictionary;
+ UInt32 dictionarySize = vs->Properties.DictionarySize;
+ UInt32 dictionaryPos = vs->DictionaryPos;
+
+ unsigned char tempDictionary[4];
+
+ (*inSizeProcessed) = 0;
+ (*outSizeProcessed) = 0;
+ if (len == kLzmaStreamWasFinishedId)
+ return LZMA_RESULT_OK;
+
+ if (dictionarySize == 0)
+ {
+ dictionary = tempDictionary;
+ dictionarySize = 1;
+ tempDictionary[0] = vs->TempDictionary[0];
+ }
+
+ if (len == kLzmaNeedInitId)
+ {
+ while (inSize > 0 && BufferSize < kLzmaInBufferSize)
+ {
+ Buffer[BufferSize++] = *inStream++;
+ (*inSizeProcessed)++;
+ inSize--;
+ }
+ if (BufferSize < 5)
+ {
+ vs->BufferSize = BufferSize;
+ return finishDecoding ? LZMA_RESULT_DATA_ERROR : LZMA_RESULT_OK;
+ }
+ {
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+ UInt32 i;
+ for (i = 0; i < numProbs; i++)
+ p[i] = kBitModelTotal >> 1;
+ rep0 = rep1 = rep2 = rep3 = 1;
+ state = 0;
+ globalPos = 0;
+ distanceLimit = 0;
+ dictionaryPos = 0;
+ dictionary[dictionarySize - 1] = 0;
+ RC_INIT;
+ }
+ len = 0;
+ }
+ while(len != 0 && nowPos < outSize)
+ {
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ len--;
+ }
+ if (dictionaryPos == 0)
+ previousByte = dictionary[dictionarySize - 1];
+ else
+ previousByte = dictionary[dictionaryPos - 1];
+
+ while(1)
+ {
+ int bufferPos = (int)(Buffer - vs->Buffer);
+ if (BufferSize - bufferPos < kRequiredInBufferSize)
+ {
+ int i;
+ BufferSize -= bufferPos;
+ if (BufferSize < 0)
+ return LZMA_RESULT_DATA_ERROR;
+ for (i = 0; i < BufferSize; i++)
+ vs->Buffer[i] = Buffer[i];
+ Buffer = vs->Buffer;
+ while (inSize > 0 && BufferSize < kLzmaInBufferSize)
+ {
+ Buffer[BufferSize++] = *inStream++;
+ (*inSizeProcessed)++;
+ inSize--;
+ }
+ if (BufferSize < kRequiredInBufferSize && !finishDecoding)
+ break;
+ }
+ if (nowPos >= outSize)
+ break;
+ {
+ CProb *prob;
+ UInt32 bound;
+ int posState = (int)((nowPos + globalPos) & posStateMask);
+
+ prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
+ IfBit0(prob)
+ {
+ int symbol = 1;
+ UpdateBit0(prob)
+ prob = p + Literal + (LZMA_LIT_SIZE *
+ ((((nowPos + globalPos)& literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+ if (state >= kNumLitStates)
+ {
+ int matchByte;
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ matchByte = dictionary[pos];
+ do
+ {
+ int bit;
+ CProb *probLit;
+ matchByte <<= 1;
+ bit = (matchByte & 0x100);
+ probLit = prob + 0x100 + bit + symbol;
+ RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break)
+ }
+ while (symbol < 0x100);
+ }
+ while (symbol < 0x100)
+ {
+ CProb *probLit = prob + symbol;
+ RC_GET_BIT(probLit, symbol)
+ }
+ previousByte = (unsigned char)symbol;
+
+ outStream[nowPos++] = previousByte;
+ if (distanceLimit < dictionarySize)
+ distanceLimit++;
+
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ if (state < 4) state = 0;
+ else if (state < 10) state -= 3;
+ else state -= 6;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ prob = p + IsRep + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ state = state < kNumLitStates ? 0 : 3;
+ prob = p + LenCoder;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ prob = p + IsRepG0 + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ IfBit0(prob)
+ {
+ UInt32 pos;
+ UpdateBit0(prob);
+ if (distanceLimit == 0)
+ return LZMA_RESULT_DATA_ERROR;
+ if (distanceLimit < dictionarySize)
+ distanceLimit++;
+ state = state < kNumLitStates ? 9 : 11;
+ pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ previousByte = dictionary[pos];
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ outStream[nowPos++] = previousByte;
+ continue;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ }
+ }
+ else
+ {
+ UInt32 distance;
+ UpdateBit1(prob);
+ prob = p + IsRepG1 + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ distance = rep1;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ prob = p + IsRepG2 + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ distance = rep2;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ state = state < kNumLitStates ? 8 : 11;
+ prob = p + RepLenCoder;
+ }
+ {
+ int numBits, offset;
+ CProb *probLen = prob + LenChoice;
+ IfBit0(probLen)
+ {
+ UpdateBit0(probLen);
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ numBits = kLenNumLowBits;
+ }
+ else
+ {
+ UpdateBit1(probLen);
+ probLen = prob + LenChoice2;
+ IfBit0(probLen)
+ {
+ UpdateBit0(probLen);
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ numBits = kLenNumMidBits;
+ }
+ else
+ {
+ UpdateBit1(probLen);
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ numBits = kLenNumHighBits;
+ }
+ }
+ RangeDecoderBitTreeDecode(probLen, numBits, len);
+ len += offset;
+ }
+
+ if (state < 4)
+ {
+ int posSlot;
+ state += kNumLitStates;
+ prob = p + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits);
+ RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ int numDirectBits = ((posSlot >> 1) - 1);
+ rep0 = (2 | ((UInt32)posSlot & 1));
+ if (posSlot < kEndPosModelIndex)
+ {
+ rep0 <<= numDirectBits;
+ prob = p + SpecPos + rep0 - posSlot - 1;
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ RC_NORMALIZE
+ Range >>= 1;
+ rep0 <<= 1;
+ if (Code >= Range)
+ {
+ Code -= Range;
+ rep0 |= 1;
+ }
+ }
+ while (--numDirectBits != 0);
+ prob = p + Align;
+ rep0 <<= kNumAlignBits;
+ numDirectBits = kNumAlignBits;
+ }
+ {
+ int i = 1;
+ int mi = 1;
+ do
+ {
+ CProb *prob3 = prob + mi;
+ RC_GET_BIT2(prob3, mi, ; , rep0 |= i);
+ i <<= 1;
+ }
+ while(--numDirectBits != 0);
+ }
+ }
+ else
+ rep0 = posSlot;
+ if (++rep0 == (UInt32)(0))
+ {
+ /* it's for stream version */
+ len = kLzmaStreamWasFinishedId;
+ break;
+ }
+ }
+
+ len += kMatchMinLen;
+ if (rep0 > distanceLimit)
+ return LZMA_RESULT_DATA_ERROR;
+ if (dictionarySize - distanceLimit > (UInt32)len)
+ distanceLimit += len;
+ else
+ distanceLimit = dictionarySize;
+
+ do
+ {
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ previousByte = dictionary[pos];
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ len--;
+ outStream[nowPos++] = previousByte;
+ }
+ while(len != 0 && nowPos < outSize);
+ }
+ }
+ }
+ RC_NORMALIZE;
+
+ BufferSize -= (int)(Buffer - vs->Buffer);
+ if (BufferSize < 0)
+ return LZMA_RESULT_DATA_ERROR;
+ {
+ int i;
+ for (i = 0; i < BufferSize; i++)
+ vs->Buffer[i] = Buffer[i];
+ }
+ vs->BufferSize = BufferSize;
+ vs->Range = Range;
+ vs->Code = Code;
+ vs->DictionaryPos = dictionaryPos;
+ vs->GlobalPos = (UInt32)(globalPos + nowPos);
+ vs->DistanceLimit = distanceLimit;
+ vs->Reps[0] = rep0;
+ vs->Reps[1] = rep1;
+ vs->Reps[2] = rep2;
+ vs->Reps[3] = rep3;
+ vs->State = state;
+ vs->RemainLen = len;
+ vs->TempDictionary[0] = tempDictionary[0];
+
+ (*outSizeProcessed) = nowPos;
+ return LZMA_RESULT_OK;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/LzmaStateDecode.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/LzmaStateDecode.h new file mode 100644 index 00000000..4e6aad89 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/LzmaStateDecode.h @@ -0,0 +1,115 @@ +/*
+ LzmaStateDecode.h
+ LZMA Decoder interface (State version)
+
+ LZMA SDK 4.21 Copyright (c) 1999-2005 Igor Pavlov (2005-06-08)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this code, expressly permits you to
+ statically or dynamically link your code (or bind by name) to the
+ interfaces of this file without subjecting your linked code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMASTATEDECODE_H
+#define __LZMASTATEDECODE_H
+
+/* #define _LZMA_PROB32 */
+/* It can increase speed on some 32-bit CPUs,
+ but memory usage will be doubled in that case */
+
+/* #define _LZMA_SYSTEM_SIZE_T */
+/* Use system's size_t. You can use it to enable 64-bit sizes supporting*/
+
+
+#ifndef UInt32
+#ifdef _LZMA_UINT32_IS_ULONG
+#define UInt32 unsigned long
+#else
+#define UInt32 unsigned int
+#endif
+#endif
+
+#ifndef SizeT
+#ifdef _LZMA_SYSTEM_SIZE_T
+#include <stddef.h>
+#define SizeT size_t
+#else
+#define SizeT UInt32
+#endif
+#endif
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb unsigned short
+#endif
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LZMA_PROPERTIES_SIZE 5
+
+typedef struct _CLzmaProperties
+{
+ int lc;
+ int lp;
+ int pb;
+ UInt32 DictionarySize;
+}CLzmaProperties;
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size);
+
+#define LzmaGetNumProbs(lzmaProps) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((lzmaProps)->lc + (lzmaProps)->lp)))
+
+#define kLzmaInBufferSize 64 /* don't change it. it must be larger than kRequiredInBufferSize */
+
+#define kLzmaNeedInitId (-2)
+
+typedef struct _CLzmaDecoderState
+{
+ CLzmaProperties Properties;
+ CProb *Probs;
+ unsigned char *Dictionary;
+
+ unsigned char Buffer[kLzmaInBufferSize];
+ int BufferSize;
+
+ UInt32 Range;
+ UInt32 Code;
+ UInt32 DictionaryPos;
+ UInt32 GlobalPos;
+ UInt32 DistanceLimit;
+ UInt32 Reps[4];
+ int State;
+ int RemainLen; /* -2: decoder needs internal initialization
+ -1: stream was finished,
+ 0: ok
+ > 0: need to write RemainLen bytes as match Reps[0],
+ */
+ unsigned char TempDictionary[4]; /* it's required when DictionarySize = 0 */
+} CLzmaDecoderState;
+
+#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; (vs)->BufferSize = 0; }
+
+/* LzmaDecode: decoding from input stream to output stream.
+ If finishDecoding != 0, then there are no more bytes in input stream
+ after inStream[inSize - 1]. */
+
+int LzmaDecode(CLzmaDecoderState *vs,
+ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed,
+ int finishDecoding);
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/LzmaStateTest.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/LzmaStateTest.c new file mode 100644 index 00000000..fa791d35 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/LzmaStateTest.c @@ -0,0 +1,195 @@ +/*
+LzmaStateTest.c
+Test application for LZMA Decoder (State version)
+
+This file written and distributed to public domain by Igor Pavlov.
+This file is part of LZMA SDK 4.26 (2005-08-02)
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "LzmaStateDecode.h"
+
+const char *kCantReadMessage = "Can not read input file";
+const char *kCantWriteMessage = "Can not write output file";
+const char *kCantAllocateMessage = "Can not allocate memory";
+
+#define kInBufferSize (1 << 15)
+#define kOutBufferSize (1 << 15)
+
+unsigned char g_InBuffer[kInBufferSize];
+unsigned char g_OutBuffer[kOutBufferSize];
+
+size_t MyReadFile(FILE *file, void *data, size_t size)
+ { return fread(data, 1, size, file); }
+
+int MyReadFileAndCheck(FILE *file, void *data, size_t size)
+ { return (MyReadFile(file, data, size) == size); }
+
+int PrintError(char *buffer, const char *message)
+{
+ sprintf(buffer + strlen(buffer), "\nError: ");
+ sprintf(buffer + strlen(buffer), message);
+ return 1;
+}
+
+int main3(FILE *inFile, FILE *outFile, char *rs)
+{
+ /* We use two 32-bit integers to construct 64-bit integer for file size.
+ You can remove outSizeHigh, if you don't need >= 4GB supporting,
+ or you can use UInt64 outSize, if your compiler supports 64-bit integers*/
+ UInt32 outSize = 0;
+ UInt32 outSizeHigh = 0;
+
+ int waitEOS = 1;
+ /* waitEOS = 1, if there is no uncompressed size in headers,
+ so decoder will wait EOS (End of Stream Marker) in compressed stream */
+
+ int i;
+ int res = 0;
+ CLzmaDecoderState state; /* it's about 140 bytes structure, if int is 32-bit */
+ unsigned char properties[LZMA_PROPERTIES_SIZE];
+ SizeT inAvail = 0;
+ unsigned char *inBuffer = 0;
+
+ if (sizeof(UInt32) < 4)
+ return PrintError(rs, "LZMA decoder needs correct UInt32");
+
+ /* Read LZMA properties for compressed stream */
+
+ if (!MyReadFileAndCheck(inFile, properties, sizeof(properties)))
+ return PrintError(rs, kCantReadMessage);
+
+ /* Read uncompressed size */
+
+ for (i = 0; i < 8; i++)
+ {
+ unsigned char b;
+ if (!MyReadFileAndCheck(inFile, &b, 1))
+ return PrintError(rs, kCantReadMessage);
+ if (b != 0xFF)
+ waitEOS = 0;
+ if (i < 4)
+ outSize += (UInt32)(b) << (i * 8);
+ else
+ outSizeHigh += (UInt32)(b) << ((i - 4) * 8);
+ }
+
+ /* Decode LZMA properties and allocate memory */
+
+ if (LzmaDecodeProperties(&state.Properties, properties, LZMA_PROPERTIES_SIZE) != LZMA_RESULT_OK)
+ return PrintError(rs, "Incorrect stream properties");
+ state.Probs = (CProb *)malloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
+ if (state.Probs == 0)
+ return PrintError(rs, kCantAllocateMessage);
+
+ if (state.Properties.DictionarySize == 0)
+ state.Dictionary = 0;
+ else
+ {
+ state.Dictionary = (unsigned char *)malloc(state.Properties.DictionarySize);
+ if (state.Dictionary == 0)
+ {
+ free(state.Probs);
+ return PrintError(rs, kCantAllocateMessage);
+ }
+ }
+
+ /* Decompress */
+
+ LzmaDecoderInit(&state);
+
+ do
+ {
+ SizeT inProcessed, outProcessed;
+ int finishDecoding;
+ UInt32 outAvail = kOutBufferSize;
+ if (!waitEOS && outSizeHigh == 0 && outAvail > outSize)
+ outAvail = outSize;
+ if (inAvail == 0)
+ {
+ inAvail = (SizeT)MyReadFile(inFile, g_InBuffer, kInBufferSize);
+ inBuffer = g_InBuffer;
+ }
+ finishDecoding = (inAvail == 0);
+ res = LzmaDecode(&state,
+ inBuffer, inAvail, &inProcessed,
+ g_OutBuffer, outAvail, &outProcessed,
+ finishDecoding);
+ if (res != 0)
+ {
+ sprintf(rs + strlen(rs), "\nDecoding error = %d\n", res);
+ res = 1;
+ break;
+ }
+ inAvail -= inProcessed;
+ inBuffer += inProcessed;
+
+ if (outFile != 0)
+ if (fwrite(g_OutBuffer, 1, outProcessed, outFile) != outProcessed)
+ {
+ PrintError(rs, kCantWriteMessage);
+ res = 1;
+ break;
+ }
+
+ if (outSize < outProcessed)
+ outSizeHigh--;
+ outSize -= (UInt32)outProcessed;
+ outSize &= 0xFFFFFFFF;
+
+ if (outProcessed == 0 && finishDecoding)
+ {
+ if (!waitEOS && (outSize != 0 || outSizeHigh != 0))
+ res = 1;
+ break;
+ }
+ }
+ while ((outSize != 0 && outSizeHigh == 0) || outSizeHigh != 0 || waitEOS);
+
+ free(state.Dictionary);
+ free(state.Probs);
+ return res;
+}
+
+int main2(int numArgs, const char *args[], char *rs)
+{
+ FILE *inFile = 0;
+ FILE *outFile = 0;
+ int res;
+
+ sprintf(rs + strlen(rs), "\nLZMA Decoder 4.26 Copyright (c) 1999-2005 Igor Pavlov 2005-08-02\n");
+ if (numArgs < 2 || numArgs > 3)
+ {
+ sprintf(rs + strlen(rs), "\nUsage: lzmadec file.lzma [outFile]\n");
+ return 1;
+ }
+
+ inFile = fopen(args[1], "rb");
+ if (inFile == 0)
+ return PrintError(rs, "Can not open input file");
+
+ if (numArgs > 2)
+ {
+ outFile = fopen(args[2], "wb+");
+ if (outFile == 0)
+ return PrintError(rs, "Can not open output file");
+ }
+
+ res = main3(inFile, outFile, rs);
+
+ if (outFile != 0)
+ fclose(outFile);
+ fclose(inFile);
+ return res;
+}
+
+int main(int numArgs, const char *args[])
+{
+ char rs[800] = { 0 };
+ int res = main2(numArgs, args, rs);
+ printf(rs);
+ return res;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/LzmaTest.c b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/LzmaTest.c new file mode 100644 index 00000000..370b9497 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/LzmaTest.c @@ -0,0 +1,342 @@ +/*
+LzmaTest.c
+Test application for LZMA Decoder
+
+This file written and distributed to public domain by Igor Pavlov.
+This file is part of LZMA SDK 4.26 (2005-08-05)
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "LzmaDecode.h"
+
+const char *kCantReadMessage = "Can not read input file";
+const char *kCantWriteMessage = "Can not write output file";
+const char *kCantAllocateMessage = "Can not allocate memory";
+
+size_t MyReadFile(FILE *file, void *data, size_t size)
+{
+ if (size == 0)
+ return 0;
+ return fread(data, 1, size, file);
+}
+
+int MyReadFileAndCheck(FILE *file, void *data, size_t size)
+ { return (MyReadFile(file, data, size) == size);}
+
+size_t MyWriteFile(FILE *file, const void *data, size_t size)
+{
+ if (size == 0)
+ return 0;
+ return fwrite(data, 1, size, file);
+}
+
+int MyWriteFileAndCheck(FILE *file, const void *data, size_t size)
+ { return (MyWriteFile(file, data, size) == size); }
+
+#ifdef _LZMA_IN_CB
+#define kInBufferSize (1 << 15)
+typedef struct _CBuffer
+{
+ ILzmaInCallback InCallback;
+ FILE *File;
+ unsigned char Buffer[kInBufferSize];
+} CBuffer;
+
+int LzmaReadCompressed(void *object, const unsigned char **buffer, SizeT *size)
+{
+ CBuffer *b = (CBuffer *)object;
+ *buffer = b->Buffer;
+ *size = (SizeT)MyReadFile(b->File, b->Buffer, kInBufferSize);
+ return LZMA_RESULT_OK;
+}
+CBuffer g_InBuffer;
+
+#endif
+
+#ifdef _LZMA_OUT_READ
+#define kOutBufferSize (1 << 15)
+unsigned char g_OutBuffer[kOutBufferSize];
+#endif
+
+int PrintError(char *buffer, const char *message)
+{
+ sprintf(buffer + strlen(buffer), "\nError: ");
+ sprintf(buffer + strlen(buffer), message);
+ return 1;
+}
+
+int main3(FILE *inFile, FILE *outFile, char *rs)
+{
+ /* We use two 32-bit integers to construct 64-bit integer for file size.
+ You can remove outSizeHigh, if you don't need >= 4GB supporting,
+ or you can use UInt64 outSize, if your compiler supports 64-bit integers*/
+ UInt32 outSize = 0;
+ UInt32 outSizeHigh = 0;
+ #ifndef _LZMA_OUT_READ
+ SizeT outSizeFull;
+ unsigned char *outStream;
+ #endif
+
+ int waitEOS = 1;
+ /* waitEOS = 1, if there is no uncompressed size in headers,
+ so decoder will wait EOS (End of Stream Marker) in compressed stream */
+
+ #ifndef _LZMA_IN_CB
+ SizeT compressedSize;
+ unsigned char *inStream;
+ #endif
+
+ CLzmaDecoderState state; /* it's about 24-80 bytes structure, if int is 32-bit */
+ unsigned char properties[LZMA_PROPERTIES_SIZE];
+
+ int res;
+
+ #ifdef _LZMA_IN_CB
+ g_InBuffer.File = inFile;
+ #endif
+
+ if (sizeof(UInt32) < 4)
+ return PrintError(rs, "LZMA decoder needs correct UInt32");
+
+ #ifndef _LZMA_IN_CB
+ {
+ long length;
+ fseek(inFile, 0, SEEK_END);
+ length = ftell(inFile);
+ fseek(inFile, 0, SEEK_SET);
+ if ((long)(SizeT)length != length)
+ return PrintError(rs, "Too big compressed stream");
+ compressedSize = (SizeT)(length - (LZMA_PROPERTIES_SIZE + 8));
+ }
+ #endif
+
+ /* Read LZMA properties for compressed stream */
+
+ if (!MyReadFileAndCheck(inFile, properties, sizeof(properties)))
+ return PrintError(rs, kCantReadMessage);
+
+ /* Read uncompressed size */
+
+ {
+ int i;
+ for (i = 0; i < 8; i++)
+ {
+ unsigned char b;
+ if (!MyReadFileAndCheck(inFile, &b, 1))
+ return PrintError(rs, kCantReadMessage);
+ if (b != 0xFF)
+ waitEOS = 0;
+ if (i < 4)
+ outSize += (UInt32)(b) << (i * 8);
+ else
+ outSizeHigh += (UInt32)(b) << ((i - 4) * 8);
+ }
+
+ #ifndef _LZMA_OUT_READ
+ if (waitEOS)
+ return PrintError(rs, "Stream with EOS marker is not supported");
+ outSizeFull = (SizeT)outSize;
+ if (sizeof(SizeT) >= 8)
+ outSizeFull |= (((SizeT)outSizeHigh << 16) << 16);
+ else if (outSizeHigh != 0 || (UInt32)(SizeT)outSize != outSize)
+ return PrintError(rs, "Too big uncompressed stream");
+ #endif
+ }
+
+ /* Decode LZMA properties and allocate memory */
+
+ if (LzmaDecodeProperties(&state.Properties, properties, LZMA_PROPERTIES_SIZE) != LZMA_RESULT_OK)
+ return PrintError(rs, "Incorrect stream properties");
+ state.Probs = (CProb *)malloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
+
+ #ifdef _LZMA_OUT_READ
+ if (state.Properties.DictionarySize == 0)
+ state.Dictionary = 0;
+ else
+ state.Dictionary = (unsigned char *)malloc(state.Properties.DictionarySize);
+ #else
+ if (outSizeFull == 0)
+ outStream = 0;
+ else
+ outStream = (unsigned char *)malloc(outSizeFull);
+ #endif
+
+ #ifndef _LZMA_IN_CB
+ if (compressedSize == 0)
+ inStream = 0;
+ else
+ inStream = (unsigned char *)malloc(compressedSize);
+ #endif
+
+ if (state.Probs == 0
+ #ifdef _LZMA_OUT_READ
+ || (state.Dictionary == 0 && state.Properties.DictionarySize != 0)
+ #else
+ || (outStream == 0 && outSizeFull != 0)
+ #endif
+ #ifndef _LZMA_IN_CB
+ || (inStream == 0 && compressedSize != 0)
+ #endif
+ )
+ {
+ free(state.Probs);
+ #ifdef _LZMA_OUT_READ
+ free(state.Dictionary);
+ #else
+ free(outStream);
+ #endif
+ #ifndef _LZMA_IN_CB
+ free(inStream);
+ #endif
+ return PrintError(rs, kCantAllocateMessage);
+ }
+
+ /* Decompress */
+
+ #ifdef _LZMA_IN_CB
+ g_InBuffer.InCallback.Read = LzmaReadCompressed;
+ #else
+ if (!MyReadFileAndCheck(inFile, inStream, compressedSize))
+ return PrintError(rs, kCantReadMessage);
+ #endif
+
+ #ifdef _LZMA_OUT_READ
+ {
+ #ifndef _LZMA_IN_CB
+ SizeT inAvail = compressedSize;
+ const unsigned char *inBuffer = inStream;
+ #endif
+ LzmaDecoderInit(&state);
+ do
+ {
+ #ifndef _LZMA_IN_CB
+ SizeT inProcessed;
+ #endif
+ SizeT outProcessed;
+ SizeT outAvail = kOutBufferSize;
+ if (!waitEOS && outSizeHigh == 0 && outAvail > outSize)
+ outAvail = (SizeT)outSize;
+ res = LzmaDecode(&state,
+ #ifdef _LZMA_IN_CB
+ &g_InBuffer.InCallback,
+ #else
+ inBuffer, inAvail, &inProcessed,
+ #endif
+ g_OutBuffer, outAvail, &outProcessed);
+ if (res != 0)
+ {
+ sprintf(rs + strlen(rs), "\nDecoding error = %d\n", res);
+ res = 1;
+ break;
+ }
+ #ifndef _LZMA_IN_CB
+ inAvail -= inProcessed;
+ inBuffer += inProcessed;
+ #endif
+
+ if (outFile != 0)
+ if (!MyWriteFileAndCheck(outFile, g_OutBuffer, (size_t)outProcessed))
+ {
+ PrintError(rs, kCantWriteMessage);
+ res = 1;
+ break;
+ }
+
+ if (outSize < outProcessed)
+ outSizeHigh--;
+ outSize -= (UInt32)outProcessed;
+ outSize &= 0xFFFFFFFF;
+
+ if (outProcessed == 0)
+ {
+ if (!waitEOS && (outSize != 0 || outSizeHigh != 0))
+ res = 1;
+ break;
+ }
+ }
+ while ((outSize != 0 && outSizeHigh == 0) || outSizeHigh != 0 || waitEOS);
+ }
+
+ #else
+ {
+ #ifndef _LZMA_IN_CB
+ SizeT inProcessed;
+ #endif
+ SizeT outProcessed;
+ res = LzmaDecode(&state,
+ #ifdef _LZMA_IN_CB
+ &g_InBuffer.InCallback,
+ #else
+ inStream, compressedSize, &inProcessed,
+ #endif
+ outStream, outSizeFull, &outProcessed);
+ if (res != 0)
+ {
+ sprintf(rs + strlen(rs), "\nDecoding error = %d\n", res);
+ res = 1;
+ }
+ else if (outFile != 0)
+ {
+ if (!MyWriteFileAndCheck(outFile, outStream, (size_t)outProcessed))
+ {
+ PrintError(rs, kCantWriteMessage);
+ res = 1;
+ }
+ }
+ }
+ #endif
+
+ free(state.Probs);
+ #ifdef _LZMA_OUT_READ
+ free(state.Dictionary);
+ #else
+ free(outStream);
+ #endif
+ #ifndef _LZMA_IN_CB
+ free(inStream);
+ #endif
+ return res;
+}
+
+int main2(int numArgs, const char *args[], char *rs)
+{
+ FILE *inFile = 0;
+ FILE *outFile = 0;
+ int res;
+
+ sprintf(rs + strlen(rs), "\nLZMA Decoder 4.26 Copyright (c) 1999-2005 Igor Pavlov 2005-08-05\n");
+ if (numArgs < 2 || numArgs > 3)
+ {
+ sprintf(rs + strlen(rs), "\nUsage: lzmadec file.lzma [outFile]\n");
+ return 1;
+ }
+
+ inFile = fopen(args[1], "rb");
+ if (inFile == 0)
+ return PrintError(rs, "Can not open input file");
+
+ if (numArgs > 2)
+ {
+ outFile = fopen(args[2], "wb+");
+ if (outFile == 0)
+ return PrintError(rs, "Can not open output file");
+ }
+
+ res = main3(inFile, outFile, rs);
+
+ if (outFile != 0)
+ fclose(outFile);
+ fclose(inFile);
+ return res;
+}
+
+int main(int numArgs, const char *args[])
+{
+ char rs[800] = { 0 };
+ int res = main2(numArgs, args, rs);
+ printf(rs);
+ return res;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/makefile b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/makefile new file mode 100644 index 00000000..f8e193b2 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/makefile @@ -0,0 +1,43 @@ +PROG = lzmaDec.exe
+
+!IFNDEF O
+!IFDEF CPU
+O=$(CPU)
+!ELSE
+O=O
+!ENDIF
+!ENDIF
+
+CFLAGS = $(CFLAGS) -nologo -c -Fo$O/ -GS-
+CFLAGS_O1 = $(CFLAGS) -O1
+CFLAGS_O2 = $(CFLAGS) -O2
+
+LFLAGS = $(LFLAGS) -nologo -OPT:NOWIN98
+
+PROGPATH = $O\$(PROG)
+
+COMPL_O1 = $(CPP) $(CFLAGS_O1) $**
+COMPL_O2 = $(CPP) $(CFLAGS_O2) $**
+COMPL = $(CPP) $(CFLAGS_O1) $**
+
+
+OBJS = \
+ $O\LzmaTest.obj \
+ $O\LzmaDecode.obj \
+
+all: $(PROGPATH)
+
+clean:
+ -del /Q $(PROGPATH) $O\*.exe $O\*.dll $O\*.obj $O\*.lib $O\*.exp $O\*.res $O\*.pch
+
+$O:
+ if not exist "$O" mkdir "$O"
+
+$(PROGPATH): $O $(OBJS)
+ link $(LFLAGS) -out:$(PROGPATH) $(OBJS) $(LIBS)
+
+
+$O\LzmaTest.obj: $(*B).c
+ $(COMPL)
+$O\LzmaDecode.obj: ../../Compress/LZMA_C/$(*B).c
+ $(COMPL_O2)
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/makefile.gcc b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/makefile.gcc new file mode 100644 index 00000000..43bbef17 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_C/makefile.gcc @@ -0,0 +1,23 @@ +PROG = lzmadec
+CXX = gcc
+LIB =
+RM = rm -f
+CFLAGS = -c -O2 -Wall -pedantic -D _LZMA_PROB32
+
+OBJS = LzmaTest.o LzmaDecode.o
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(CXX) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIB)
+
+LzmaTest.o: LzmaTest.c
+ $(CXX) $(CFLAGS) LzmaTest.c
+
+LzmaDecode.o: LzmaDecode.c
+ $(CXX) $(CFLAGS) LzmaDecode.c
+
+
+clean:
+ -$(RM) $(PROG) $(OBJS)
+
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Lib/ZLib.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Lib/ZLib.cpp new file mode 100644 index 00000000..931c13ac --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Lib/ZLib.cpp @@ -0,0 +1,273 @@ +/*
+ * lzma zlib simplified wrapper
+ *
+ * Copyright (c) 2005-2006 Oleg I. Vdovikin <oleg@cs.msu.su>
+ *
+ * This library is free software; you can redistribute
+ * it and/or modify it under the terms of the GNU Lesser
+ * General Public License as published by the Free Software
+ * Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * default values for encoder/decoder used by wrapper
+ */
+
+#include <zlib.h>
+
+#define ZLIB_LC 3
+#define ZLIB_LP 0
+#define ZLIB_PB 2
+
+#ifdef WIN32
+#include <initguid.h>
+#else
+#define INITGUID
+#endif
+
+#include "../../../Common/MyWindows.h"
+#include "../LZMA/LZMADecoder.h"
+#include "../LZMA/LZMAEncoder.h"
+
+#define STG_E_SEEKERROR ((HRESULT)0x80030019L)
+#define STG_E_MEDIUMFULL ((HRESULT)0x80030070L)
+
+class CInMemoryStream:
+ public IInStream,
+ public IStreamGetSize,
+ public CMyUnknownImp
+{
+public:
+ CInMemoryStream(const Bytef *data, UInt64 size) :
+ m_data(data), m_size(size), m_offset(0) {}
+
+ virtual ~CInMemoryStream() {}
+
+ MY_UNKNOWN_IMP2(IInStream, IStreamGetSize)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize)
+ {
+ if (size > m_size - m_offset)
+ size = m_size - m_offset;
+
+ if (size) {
+ memcpy(data, m_data + m_offset, size);
+ }
+
+ m_offset += size;
+
+ if (processedSize)
+ *processedSize = size;
+
+ return S_OK;
+ }
+
+ STDMETHOD(ReadPart)(void *data, UInt32 size, UInt32 *processedSize)
+ {
+ return Read(data, size, processedSize);
+ }
+
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+ {
+ UInt64 _offset;
+
+ if (seekOrigin == STREAM_SEEK_SET) _offset = offset;
+ else if (seekOrigin == STREAM_SEEK_CUR) _offset = m_offset + offset;
+ else if (seekOrigin == STREAM_SEEK_END) _offset = m_size;
+ else return STG_E_INVALIDFUNCTION;
+
+ if (_offset < 0 || _offset > m_size)
+ return STG_E_SEEKERROR;
+
+ m_offset = _offset;
+
+ if (newPosition)
+ *newPosition = m_offset;
+
+ return S_OK;
+ }
+
+ STDMETHOD(GetSize)(UInt64 *size)
+ {
+ *size = m_size;
+ return S_OK;
+ }
+protected:
+ const Bytef *m_data;
+ UInt64 m_size;
+ UInt64 m_offset;
+};
+
+class COutMemoryStream:
+ public IOutStream,
+ public CMyUnknownImp
+{
+public:
+ COutMemoryStream(Bytef *data, UInt64 maxsize) :
+ m_data(data), m_size(0), m_maxsize(maxsize), m_offset(0) {}
+ virtual ~COutMemoryStream() {}
+
+ MY_UNKNOWN_IMP1(IOutStream)
+
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize)
+ {
+ if (size > m_maxsize - m_offset)
+ size = m_maxsize - m_offset;
+
+ if (size) {
+ memcpy(m_data + m_offset, data, size);
+ }
+
+ m_offset += size;
+
+ if (m_offset > m_size)
+ m_size = m_offset;
+
+ if (processedSize)
+ *processedSize = size;
+
+ return S_OK;
+ }
+
+ STDMETHOD(WritePart)(const void *data, UInt32 size, UInt32 *processedSize)
+ {
+ return Write(data, size, processedSize);
+ }
+
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+ {
+ UInt64 _offset;
+
+ if (seekOrigin == STREAM_SEEK_SET) _offset = offset;
+ else if (seekOrigin == STREAM_SEEK_CUR) _offset = m_offset + offset;
+ else if (seekOrigin == STREAM_SEEK_END) _offset = m_size;
+ else return STG_E_INVALIDFUNCTION;
+
+ if (_offset < 0 || _offset > m_maxsize)
+ return STG_E_SEEKERROR;
+
+ m_offset = _offset;
+
+ if (newPosition)
+ *newPosition = m_offset;
+
+ return S_OK;
+ }
+
+ STDMETHOD(SetSize)(Int64 newSize)
+ {
+ if ((UInt64)newSize > m_maxsize)
+ return STG_E_MEDIUMFULL;
+
+ return S_OK;
+ }
+protected:
+ Bytef *m_data;
+ UInt64 m_size;
+ UInt64 m_maxsize;
+ UInt64 m_offset;
+};
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen,
+ int level))
+{
+ CInMemoryStream *inStreamSpec = new CInMemoryStream(source, sourceLen);
+ CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
+
+ COutMemoryStream *outStreamSpec = new COutMemoryStream(dest, *destLen);
+ CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+
+ NCompress::NLZMA::CEncoder *encoderSpec =
+ new NCompress::NLZMA::CEncoder;
+ CMyComPtr<ICompressCoder> encoder = encoderSpec;
+
+ PROPID propIDs[] =
+ {
+ NCoderPropID::kDictionarySize,
+ NCoderPropID::kPosStateBits,
+ NCoderPropID::kLitContextBits,
+ NCoderPropID::kLitPosBits,
+ NCoderPropID::kAlgorithm,
+ NCoderPropID::kNumFastBytes,
+ NCoderPropID::kMatchFinder,
+ NCoderPropID::kEndMarker
+ };
+ const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]);
+
+ PROPVARIANT properties[kNumProps];
+ for (int p = 0; p < 6; p++)
+ properties[p].vt = VT_UI4;
+ properties[0].ulVal = UInt32(1 << (level + 14));
+ properties[1].ulVal = UInt32(ZLIB_PB);
+ properties[2].ulVal = UInt32(ZLIB_LC); // for normal files
+ properties[3].ulVal = UInt32(ZLIB_LP); // for normal files
+ properties[4].ulVal = UInt32(2);
+ properties[5].ulVal = UInt32(128);
+
+ properties[6].vt = VT_BSTR;
+ properties[6].bstrVal = (BSTR)(const wchar_t *)L"BT4";
+
+ properties[7].vt = VT_BOOL;
+ properties[7].boolVal = VARIANT_TRUE;
+
+ if (encoderSpec->SetCoderProperties(propIDs, properties, kNumProps) != S_OK)
+ return Z_MEM_ERROR; // should not happen
+
+ HRESULT result = encoder->Code(inStream, outStream, 0, 0, 0);
+ if (result == E_OUTOFMEMORY)
+ {
+ return Z_MEM_ERROR;
+ }
+ else if (result != S_OK)
+ {
+ return Z_BUF_ERROR; // should not happen
+ }
+
+ UInt64 fileSize;
+ outStreamSpec->Seek(0, STREAM_SEEK_END, &fileSize);
+ *destLen = fileSize;
+
+ return Z_OK;
+}
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen))
+{
+ CInMemoryStream *inStreamSpec = new CInMemoryStream(source, sourceLen);
+ CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
+
+ COutMemoryStream *outStreamSpec = new COutMemoryStream(dest, *destLen);
+ CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+
+ NCompress::NLZMA::CDecoder *decoderSpec =
+ new NCompress::NLZMA::CDecoder;
+ CMyComPtr<ICompressCoder> decoder = decoderSpec;
+
+ if (decoderSpec->SetDecoderPropertiesRaw(ZLIB_LC,
+ ZLIB_LP, ZLIB_PB, (1 << 23)) != S_OK) return Z_DATA_ERROR;
+
+ UInt64 fileSize = *destLen;
+
+ if (decoder->Code(inStream, outStream, 0, &fileSize, 0) != S_OK)
+ {
+ return Z_DATA_ERROR;
+ }
+
+ outStreamSpec->Seek(0, STREAM_SEEK_END, &fileSize);
+ *destLen = fileSize;
+
+ return Z_OK;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Lib/makefile b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Lib/makefile new file mode 100644 index 00000000..bbf27459 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/LZMA_Lib/makefile @@ -0,0 +1,92 @@ +PROG = liblzma.a +CXX = g++ -O3 -Wall -Wno-non-virtual-dtor +AR = ar +RM = rm -f +CFLAGS = -c -I ../../../ + +OBJS = \ + ZLib.o \ + LZMADecoder.o \ + LZMAEncoder.o \ + LZInWindow.o \ + LZOutWindow.o \ + RangeCoderBit.o \ + InBuffer.o \ + OutBuffer.o \ + FileStreams.o \ + Alloc.o \ + C_FileIO.o \ + CommandLineParser.o \ + CRC.o \ + StreamUtils.o \ + String.o \ + StringConvert.o \ + StringToInt.o \ + Vector.o \ + + +all: $(PROG) + +$(PROG): $(OBJS) + $(AR) r $(PROG) $(OBJS) + +ZLib.o: ZLib.cpp + $(CXX) $(CFLAGS) ZLib.cpp + +LZMADecoder.o: ../LZMA/LZMADecoder.cpp + $(CXX) $(CFLAGS) ../LZMA/LZMADecoder.cpp + +LZMAEncoder.o: ../LZMA/LZMAEncoder.cpp + $(CXX) $(CFLAGS) ../LZMA/LZMAEncoder.cpp + +LZInWindow.o: ../LZ/LZInWindow.cpp + $(CXX) $(CFLAGS) ../LZ/LZInWindow.cpp + +LZOutWindow.o: ../LZ/LZOutWindow.cpp + $(CXX) $(CFLAGS) ../LZ/LZOutWindow.cpp + +RangeCoderBit.o: ../RangeCoder/RangeCoderBit.cpp + $(CXX) $(CFLAGS) ../RangeCoder/RangeCoderBit.cpp + +InBuffer.o: ../../Common/InBuffer.cpp + $(CXX) $(CFLAGS) ../../Common/InBuffer.cpp + +OutBuffer.o: ../../Common/OutBuffer.cpp + $(CXX) $(CFLAGS) ../../Common/OutBuffer.cpp + +StreamUtils.o: ../../Common/StreamUtils.cpp + $(CXX) $(CFLAGS) ../../Common/StreamUtils.cpp + +FileStreams.o: ../../Common/FileStreams.cpp + $(CXX) $(CFLAGS) ../../Common/FileStreams.cpp + +Alloc.o: ../../../Common/Alloc.cpp + $(CXX) $(CFLAGS) ../../../Common/Alloc.cpp + +C_FileIO.o: ../../../Common/C_FileIO.cpp + $(CXX) $(CFLAGS) ../../../Common/C_FileIO.cpp + +CommandLineParser.o: ../../../Common/CommandLineParser.cpp + $(CXX) $(CFLAGS) ../../../Common/CommandLineParser.cpp + +CRC.o: ../../../Common/CRC.cpp + $(CXX) $(CFLAGS) ../../../Common/CRC.cpp + +MyWindows.o: ../../../Common/MyWindows.cpp + $(CXX) $(CFLAGS) ../../../Common/MyWindows.cpp + +String.o: ../../../Common/String.cpp + $(CXX) $(CFLAGS) ../../../Common/String.cpp + +StringConvert.o: ../../../Common/StringConvert.cpp + $(CXX) $(CFLAGS) ../../../Common/StringConvert.cpp + +StringToInt.o: ../../../Common/StringToInt.cpp + $(CXX) $(CFLAGS) ../../../Common/StringToInt.cpp + +Vector.o: ../../../Common/Vector.cpp + $(CXX) $(CFLAGS) ../../../Common/Vector.cpp + +clean: + -$(RM) $(PROG) $(OBJS) + diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/RangeCoder/RangeCoder.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/RangeCoder/RangeCoder.h new file mode 100644 index 00000000..9828bc4b --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/RangeCoder/RangeCoder.h @@ -0,0 +1,205 @@ +// Compress/RangeCoder/RangeCoder.h
+
+#ifndef __COMPRESS_RANGECODER_H
+#define __COMPRESS_RANGECODER_H
+
+#include "../../Common/InBuffer.h"
+#include "../../Common/OutBuffer.h"
+
+namespace NCompress {
+namespace NRangeCoder {
+
+const int kNumTopBits = 24;
+const UInt32 kTopValue = (1 << kNumTopBits);
+
+class CEncoder
+{
+ UInt32 _cacheSize;
+ Byte _cache;
+public:
+ UInt64 Low;
+ UInt32 Range;
+ COutBuffer Stream;
+ bool Create(UInt32 bufferSize) { return Stream.Create(bufferSize); }
+
+ void SetStream(ISequentialOutStream *stream) { Stream.SetStream(stream); }
+ void Init()
+ {
+ Stream.Init();
+ Low = 0;
+ Range = 0xFFFFFFFF;
+ _cacheSize = 1;
+ _cache = 0;
+ }
+
+ void FlushData()
+ {
+ // Low += 1;
+ for(int i = 0; i < 5; i++)
+ ShiftLow();
+ }
+
+ HRESULT FlushStream() { return Stream.Flush(); }
+
+ void ReleaseStream() { Stream.ReleaseStream(); }
+
+ void Encode(UInt32 start, UInt32 size, UInt32 total)
+ {
+ Low += start * (Range /= total);
+ Range *= size;
+ while (Range < kTopValue)
+ {
+ Range <<= 8;
+ ShiftLow();
+ }
+ }
+
+ void ShiftLow()
+ {
+ if ((UInt32)Low < (UInt32)0xFF000000 || (int)(Low >> 32) != 0)
+ {
+ Byte temp = _cache;
+ do
+ {
+ Stream.WriteByte((Byte)(temp + (Byte)(Low >> 32)));
+ temp = 0xFF;
+ }
+ while(--_cacheSize != 0);
+ _cache = (Byte)((UInt32)Low >> 24);
+ }
+ _cacheSize++;
+ Low = (UInt32)Low << 8;
+ }
+
+ void EncodeDirectBits(UInt32 value, int numTotalBits)
+ {
+ for (int i = numTotalBits - 1; i >= 0; i--)
+ {
+ Range >>= 1;
+ if (((value >> i) & 1) == 1)
+ Low += Range;
+ if (Range < kTopValue)
+ {
+ Range <<= 8;
+ ShiftLow();
+ }
+ }
+ }
+
+ void EncodeBit(UInt32 size0, UInt32 numTotalBits, UInt32 symbol)
+ {
+ UInt32 newBound = (Range >> numTotalBits) * size0;
+ if (symbol == 0)
+ Range = newBound;
+ else
+ {
+ Low += newBound;
+ Range -= newBound;
+ }
+ while (Range < kTopValue)
+ {
+ Range <<= 8;
+ ShiftLow();
+ }
+ }
+
+ UInt64 GetProcessedSize() { return Stream.GetProcessedSize() + _cacheSize + 4; }
+};
+
+class CDecoder
+{
+public:
+ CInBuffer Stream;
+ UInt32 Range;
+ UInt32 Code;
+ bool Create(UInt32 bufferSize) { return Stream.Create(bufferSize); }
+
+ void Normalize()
+ {
+ while (Range < kTopValue)
+ {
+ Code = (Code << 8) | Stream.ReadByte();
+ Range <<= 8;
+ }
+ }
+
+ void SetStream(ISequentialInStream *stream) { Stream.SetStream(stream); }
+ void Init()
+ {
+ Stream.Init();
+ Code = 0;
+ Range = 0xFFFFFFFF;
+ for(int i = 0; i < 5; i++)
+ Code = (Code << 8) | Stream.ReadByte();
+ }
+
+ void ReleaseStream() { Stream.ReleaseStream(); }
+
+ UInt32 GetThreshold(UInt32 total)
+ {
+ return (Code) / ( Range /= total);
+ }
+
+ void Decode(UInt32 start, UInt32 size)
+ {
+ Code -= start * Range;
+ Range *= size;
+ Normalize();
+ }
+
+ UInt32 DecodeDirectBits(int numTotalBits)
+ {
+ UInt32 range = Range;
+ UInt32 code = Code;
+ UInt32 result = 0;
+ for (int i = numTotalBits; i != 0; i--)
+ {
+ range >>= 1;
+ /*
+ result <<= 1;
+ if (code >= range)
+ {
+ code -= range;
+ result |= 1;
+ }
+ */
+ UInt32 t = (code - range) >> 31;
+ code -= range & (t - 1);
+ result = (result << 1) | (1 - t);
+
+ if (range < kTopValue)
+ {
+ code = (code << 8) | Stream.ReadByte();
+ range <<= 8;
+ }
+ }
+ Range = range;
+ Code = code;
+ return result;
+ }
+
+ UInt32 DecodeBit(UInt32 size0, UInt32 numTotalBits)
+ {
+ UInt32 newBound = (Range >> numTotalBits) * size0;
+ UInt32 symbol;
+ if (Code < newBound)
+ {
+ symbol = 0;
+ Range = newBound;
+ }
+ else
+ {
+ symbol = 1;
+ Code -= newBound;
+ Range -= newBound;
+ }
+ Normalize();
+ return symbol;
+ }
+
+ UInt64 GetProcessedSize() {return Stream.GetProcessedSize(); }
+};
+
+}}
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/RangeCoder/RangeCoderBit.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/RangeCoder/RangeCoderBit.cpp new file mode 100644 index 00000000..8d273c8f --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/RangeCoder/RangeCoderBit.cpp @@ -0,0 +1,80 @@ +// Compress/RangeCoder/RangeCoderBit.cpp
+
+#include "StdAfx.h"
+
+#include "RangeCoderBit.h"
+
+namespace NCompress {
+namespace NRangeCoder {
+
+UInt32 CPriceTables::ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
+static CPriceTables g_PriceTables;
+
+CPriceTables::CPriceTables() { Init(); }
+
+void CPriceTables::Init()
+{
+ const int kNumBits = (kNumBitModelTotalBits - kNumMoveReducingBits);
+ for(int i = kNumBits - 1; i >= 0; i--)
+ {
+ UInt32 start = 1 << (kNumBits - i - 1);
+ UInt32 end = 1 << (kNumBits - i);
+ for (UInt32 j = start; j < end; j++)
+ ProbPrices[j] = (i << kNumBitPriceShiftBits) +
+ (((end - j) << kNumBitPriceShiftBits) >> (kNumBits - i - 1));
+ }
+
+ /*
+ // simplest: bad solution
+ for(UInt32 i = 1; i < (kBitModelTotal >> kNumMoveReducingBits) - 1; i++)
+ ProbPrices[i] = kBitPrice;
+ */
+
+ /*
+ const double kDummyMultMid = (1.0 / kBitPrice) / 2;
+ const double kDummyMultMid = 0;
+ // float solution
+ double ln2 = log(double(2));
+ double lnAll = log(double(kBitModelTotal >> kNumMoveReducingBits));
+ for(UInt32 i = 1; i < (kBitModelTotal >> kNumMoveReducingBits) - 1; i++)
+ ProbPrices[i] = UInt32((fabs(lnAll - log(double(i))) / ln2 + kDummyMultMid) * kBitPrice);
+ */
+
+ /*
+ // experimental, slow, solution:
+ for(UInt32 i = 1; i < (kBitModelTotal >> kNumMoveReducingBits) - 1; i++)
+ {
+ const int kCyclesBits = 5;
+ const UInt32 kCycles = (1 << kCyclesBits);
+
+ UInt32 range = UInt32(-1);
+ UInt32 bitCount = 0;
+ for (UInt32 j = 0; j < kCycles; j++)
+ {
+ range >>= (kNumBitModelTotalBits - kNumMoveReducingBits);
+ range *= i;
+ while(range < (1 << 31))
+ {
+ range <<= 1;
+ bitCount++;
+ }
+ }
+ bitCount <<= kNumBitPriceShiftBits;
+ range -= (1 << 31);
+ for (int k = kNumBitPriceShiftBits - 1; k >= 0; k--)
+ {
+ range <<= 1;
+ if (range > (1 << 31))
+ {
+ bitCount += (1 << k);
+ range -= (1 << 31);
+ }
+ }
+ ProbPrices[i] = (bitCount
+ // + (1 << (kCyclesBits - 1))
+ ) >> kCyclesBits;
+ }
+ */
+}
+
+}}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/RangeCoder/RangeCoderBit.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/RangeCoder/RangeCoderBit.h new file mode 100644 index 00000000..64538e68 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/RangeCoder/RangeCoderBit.h @@ -0,0 +1,120 @@ +// Compress/RangeCoder/RangeCoderBit.h
+
+#ifndef __COMPRESS_RANGECODER_BIT_H
+#define __COMPRESS_RANGECODER_BIT_H
+
+#include "RangeCoder.h"
+
+namespace NCompress {
+namespace NRangeCoder {
+
+const int kNumBitModelTotalBits = 11;
+const UInt32 kBitModelTotal = (1 << kNumBitModelTotalBits);
+
+const int kNumMoveReducingBits = 2;
+
+const int kNumBitPriceShiftBits = 6;
+const UInt32 kBitPrice = 1 << kNumBitPriceShiftBits;
+
+class CPriceTables
+{
+public:
+ static UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
+ static void Init();
+ CPriceTables();
+};
+
+template <int numMoveBits>
+class CBitModel
+{
+public:
+ UInt32 Prob;
+ void UpdateModel(UInt32 symbol)
+ {
+ /*
+ Prob -= (Prob + ((symbol - 1) & ((1 << numMoveBits) - 1))) >> numMoveBits;
+ Prob += (1 - symbol) << (kNumBitModelTotalBits - numMoveBits);
+ */
+ if (symbol == 0)
+ Prob += (kBitModelTotal - Prob) >> numMoveBits;
+ else
+ Prob -= (Prob) >> numMoveBits;
+ }
+public:
+ void Init() { Prob = kBitModelTotal / 2; }
+};
+
+template <int numMoveBits>
+class CBitEncoder: public CBitModel<numMoveBits>
+{
+public:
+ void Encode(CEncoder *encoder, UInt32 symbol)
+ {
+ /*
+ encoder->EncodeBit(this->Prob, kNumBitModelTotalBits, symbol);
+ this->UpdateModel(symbol);
+ */
+ UInt32 newBound = (encoder->Range >> kNumBitModelTotalBits) * this->Prob;
+ if (symbol == 0)
+ {
+ encoder->Range = newBound;
+ this->Prob += (kBitModelTotal - this->Prob) >> numMoveBits;
+ }
+ else
+ {
+ encoder->Low += newBound;
+ encoder->Range -= newBound;
+ this->Prob -= (this->Prob) >> numMoveBits;
+ }
+ if (encoder->Range < kTopValue)
+ {
+ encoder->Range <<= 8;
+ encoder->ShiftLow();
+ }
+ }
+ UInt32 GetPrice(UInt32 symbol) const
+ {
+ return CPriceTables::ProbPrices[
+ (((this->Prob - symbol) ^ ((-(int)symbol))) & (kBitModelTotal - 1)) >> kNumMoveReducingBits];
+ }
+ UInt32 GetPrice0() const { return CPriceTables::ProbPrices[this->Prob >> kNumMoveReducingBits]; }
+ UInt32 GetPrice1() const { return CPriceTables::ProbPrices[(kBitModelTotal - this->Prob) >> kNumMoveReducingBits]; }
+};
+
+
+template <int numMoveBits>
+class CBitDecoder: public CBitModel<numMoveBits>
+{
+public:
+ UInt32 Decode(CDecoder *decoder)
+ {
+ UInt32 newBound = (decoder->Range >> kNumBitModelTotalBits) * this->Prob;
+ if (decoder->Code < newBound)
+ {
+ decoder->Range = newBound;
+ this->Prob += (kBitModelTotal - this->Prob) >> numMoveBits;
+ if (decoder->Range < kTopValue)
+ {
+ decoder->Code = (decoder->Code << 8) | decoder->Stream.ReadByte();
+ decoder->Range <<= 8;
+ }
+ return 0;
+ }
+ else
+ {
+ decoder->Range -= newBound;
+ decoder->Code -= newBound;
+ this->Prob -= (this->Prob) >> numMoveBits;
+ if (decoder->Range < kTopValue)
+ {
+ decoder->Code = (decoder->Code << 8) | decoder->Stream.ReadByte();
+ decoder->Range <<= 8;
+ }
+ return 1;
+ }
+ }
+};
+
+}}
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/RangeCoder/RangeCoderBitTree.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/RangeCoder/RangeCoderBitTree.h new file mode 100644 index 00000000..1fa023f3 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/RangeCoder/RangeCoderBitTree.h @@ -0,0 +1,161 @@ +// Compress/RangeCoder/RangeCoderBitTree.h
+
+#ifndef __COMPRESS_RANGECODER_BIT_TREE_H
+#define __COMPRESS_RANGECODER_BIT_TREE_H
+
+#include "RangeCoderBit.h"
+#include "RangeCoderOpt.h"
+
+namespace NCompress {
+namespace NRangeCoder {
+
+template <int numMoveBits, int NumBitLevels>
+class CBitTreeEncoder
+{
+ CBitEncoder<numMoveBits> Models[1 << NumBitLevels];
+public:
+ void Init()
+ {
+ for(UInt32 i = 1; i < (1 << NumBitLevels); i++)
+ Models[i].Init();
+ }
+ void Encode(CEncoder *rangeEncoder, UInt32 symbol)
+ {
+ UInt32 modelIndex = 1;
+ for (int bitIndex = NumBitLevels; bitIndex != 0 ;)
+ {
+ bitIndex--;
+ UInt32 bit = (symbol >> bitIndex) & 1;
+ Models[modelIndex].Encode(rangeEncoder, bit);
+ modelIndex = (modelIndex << 1) | bit;
+ }
+ };
+ void ReverseEncode(CEncoder *rangeEncoder, UInt32 symbol)
+ {
+ UInt32 modelIndex = 1;
+ for (int i = 0; i < NumBitLevels; i++)
+ {
+ UInt32 bit = symbol & 1;
+ Models[modelIndex].Encode(rangeEncoder, bit);
+ modelIndex = (modelIndex << 1) | bit;
+ symbol >>= 1;
+ }
+ }
+ UInt32 GetPrice(UInt32 symbol) const
+ {
+ symbol |= (1 << NumBitLevels);
+ UInt32 price = 0;
+ while (symbol != 1)
+ {
+ price += Models[symbol >> 1].GetPrice(symbol & 1);
+ symbol >>= 1;
+ }
+ return price;
+ }
+ UInt32 ReverseGetPrice(UInt32 symbol) const
+ {
+ UInt32 price = 0;
+ UInt32 modelIndex = 1;
+ for (int i = NumBitLevels; i != 0; i--)
+ {
+ UInt32 bit = symbol & 1;
+ symbol >>= 1;
+ price += Models[modelIndex].GetPrice(bit);
+ modelIndex = (modelIndex << 1) | bit;
+ }
+ return price;
+ }
+};
+
+template <int numMoveBits, int NumBitLevels>
+class CBitTreeDecoder
+{
+ CBitDecoder<numMoveBits> Models[1 << NumBitLevels];
+public:
+ void Init()
+ {
+ for(UInt32 i = 1; i < (1 << NumBitLevels); i++)
+ Models[i].Init();
+ }
+ UInt32 Decode(CDecoder *rangeDecoder)
+ {
+ UInt32 modelIndex = 1;
+ RC_INIT_VAR
+ for(int bitIndex = NumBitLevels; bitIndex != 0; bitIndex--)
+ {
+ // modelIndex = (modelIndex << 1) + Models[modelIndex].Decode(rangeDecoder);
+ RC_GETBIT(numMoveBits, Models[modelIndex].Prob, modelIndex)
+ }
+ RC_FLUSH_VAR
+ return modelIndex - (1 << NumBitLevels);
+ };
+ UInt32 ReverseDecode(CDecoder *rangeDecoder)
+ {
+ UInt32 modelIndex = 1;
+ UInt32 symbol = 0;
+ RC_INIT_VAR
+ for(int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
+ {
+ // UInt32 bit = Models[modelIndex].Decode(rangeDecoder);
+ // modelIndex <<= 1;
+ // modelIndex += bit;
+ // symbol |= (bit << bitIndex);
+ RC_GETBIT2(numMoveBits, Models[modelIndex].Prob, modelIndex, ; , symbol |= (1 << bitIndex))
+ }
+ RC_FLUSH_VAR
+ return symbol;
+ }
+};
+
+template <int numMoveBits>
+void ReverseBitTreeEncode(CBitEncoder<numMoveBits> *Models,
+ CEncoder *rangeEncoder, int NumBitLevels, UInt32 symbol)
+{
+ UInt32 modelIndex = 1;
+ for (int i = 0; i < NumBitLevels; i++)
+ {
+ UInt32 bit = symbol & 1;
+ Models[modelIndex].Encode(rangeEncoder, bit);
+ modelIndex = (modelIndex << 1) | bit;
+ symbol >>= 1;
+ }
+}
+
+template <int numMoveBits>
+UInt32 ReverseBitTreeGetPrice(CBitEncoder<numMoveBits> *Models,
+ UInt32 NumBitLevels, UInt32 symbol)
+{
+ UInt32 price = 0;
+ UInt32 modelIndex = 1;
+ for (int i = NumBitLevels; i != 0; i--)
+ {
+ UInt32 bit = symbol & 1;
+ symbol >>= 1;
+ price += Models[modelIndex].GetPrice(bit);
+ modelIndex = (modelIndex << 1) | bit;
+ }
+ return price;
+}
+
+template <int numMoveBits>
+UInt32 ReverseBitTreeDecode(CBitDecoder<numMoveBits> *Models,
+ CDecoder *rangeDecoder, int NumBitLevels)
+{
+ UInt32 modelIndex = 1;
+ UInt32 symbol = 0;
+ RC_INIT_VAR
+ for(int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
+ {
+ // UInt32 bit = Models[modelIndex].Decode(rangeDecoder);
+ // modelIndex <<= 1;
+ // modelIndex += bit;
+ // symbol |= (bit << bitIndex);
+ RC_GETBIT2(numMoveBits, Models[modelIndex].Prob, modelIndex, ; , symbol |= (1 << bitIndex))
+ }
+ RC_FLUSH_VAR
+ return symbol;
+}
+
+}}
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/RangeCoder/RangeCoderOpt.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/RangeCoder/RangeCoderOpt.h new file mode 100644 index 00000000..829fc83d --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/RangeCoder/RangeCoderOpt.h @@ -0,0 +1,31 @@ +// Compress/RangeCoder/RangeCoderOpt.h
+
+#ifndef __COMPRESS_RANGECODER_OPT_H
+#define __COMPRESS_RANGECODER_OPT_H
+
+#define RC_INIT_VAR \
+ UInt32 range = rangeDecoder->Range; \
+ UInt32 code = rangeDecoder->Code;
+
+#define RC_FLUSH_VAR \
+ rangeDecoder->Range = range; \
+ rangeDecoder->Code = code;
+
+#define RC_NORMALIZE \
+ if (range < NCompress::NRangeCoder::kTopValue) \
+ { code = (code << 8) | rangeDecoder->Stream.ReadByte(); range <<= 8; }
+
+#define RC_GETBIT2(numMoveBits, prob, mi, A0, A1) \
+ { UInt32 bound = (range >> NCompress::NRangeCoder::kNumBitModelTotalBits) * prob; \
+ if (code < bound) \
+ { A0; range = bound; \
+ prob += (NCompress::NRangeCoder::kBitModelTotal - prob) >> numMoveBits; \
+ mi <<= 1; } \
+ else \
+ { A1; range -= bound; code -= bound; prob -= (prob) >> numMoveBits; \
+ mi = (mi + mi) + 1; }} \
+ RC_NORMALIZE
+
+#define RC_GETBIT(numMoveBits, prob, mi) RC_GETBIT2(numMoveBits, prob, mi, ; , ;)
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/RangeCoder/StdAfx.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/RangeCoder/StdAfx.h new file mode 100644 index 00000000..21c2fd78 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/Compress/RangeCoder/StdAfx.h @@ -0,0 +1,6 @@ +// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/ICoder.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/ICoder.h new file mode 100644 index 00000000..ce4594a0 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/ICoder.h @@ -0,0 +1,156 @@ +// ICoder.h
+
+#ifndef __ICODER_H
+#define __ICODER_H
+
+#include "IStream.h"
+
+// "23170F69-40C1-278A-0000-000400xx0000"
+#define CODER_INTERFACE(i, x) \
+DEFINE_GUID(IID_ ## i, \
+0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x04, 0x00, x, 0x00, 0x00); \
+struct i: public IUnknown
+
+CODER_INTERFACE(ICompressProgressInfo, 0x04)
+{
+ STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize) PURE;
+};
+
+CODER_INTERFACE(ICompressCoder, 0x05)
+{
+ STDMETHOD(Code)(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream,
+ const UInt64 *inSize,
+ const UInt64 *outSize,
+ ICompressProgressInfo *progress) PURE;
+};
+
+CODER_INTERFACE(ICompressCoder2, 0x18)
+{
+ STDMETHOD(Code)(ISequentialInStream **inStreams,
+ const UInt64 **inSizes,
+ UInt32 numInStreams,
+ ISequentialOutStream **outStreams,
+ const UInt64 **outSizes,
+ UInt32 numOutStreams,
+ ICompressProgressInfo *progress) PURE;
+};
+
+namespace NCoderPropID
+{
+ enum EEnum
+ {
+ kDictionarySize = 0x400,
+ kUsedMemorySize,
+ kOrder,
+ kPosStateBits = 0x440,
+ kLitContextBits,
+ kLitPosBits,
+ kNumFastBytes = 0x450,
+ kMatchFinder,
+ kNumPasses = 0x460,
+ kAlgorithm = 0x470,
+ kMultiThread = 0x480,
+ kEndMarker = 0x490
+ };
+}
+
+CODER_INTERFACE(ICompressSetCoderProperties, 0x20)
+{
+ STDMETHOD(SetCoderProperties)(const PROPID *propIDs,
+ const PROPVARIANT *properties, UInt32 numProperties) PURE;
+};
+
+/*
+CODER_INTERFACE(ICompressSetCoderProperties, 0x21)
+{
+ STDMETHOD(SetDecoderProperties)(ISequentialInStream *inStream) PURE;
+};
+*/
+
+CODER_INTERFACE(ICompressSetDecoderProperties2, 0x22)
+{
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size) PURE;
+};
+
+CODER_INTERFACE(ICompressWriteCoderProperties, 0x23)
+{
+ STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStreams) PURE;
+};
+
+CODER_INTERFACE(ICompressGetInStreamProcessedSize, 0x24)
+{
+ STDMETHOD(GetInStreamProcessedSize)(UInt64 *value) PURE;
+};
+
+CODER_INTERFACE(ICompressGetSubStreamSize, 0x30)
+{
+ STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value) PURE;
+};
+
+CODER_INTERFACE(ICompressSetInStream, 0x31)
+{
+ STDMETHOD(SetInStream)(ISequentialInStream *inStream) PURE;
+ STDMETHOD(ReleaseInStream)() PURE;
+};
+
+CODER_INTERFACE(ICompressSetOutStream, 0x32)
+{
+ STDMETHOD(SetOutStream)(ISequentialOutStream *outStream) PURE;
+ STDMETHOD(ReleaseOutStream)() PURE;
+};
+
+CODER_INTERFACE(ICompressSetInStreamSize, 0x33)
+{
+ STDMETHOD(SetInStreamSize)(const UInt64 *inSize) PURE;
+};
+
+CODER_INTERFACE(ICompressSetOutStreamSize, 0x34)
+{
+ STDMETHOD(SetOutStreamSize)(const UInt64 *outSize) PURE;
+};
+
+CODER_INTERFACE(ICompressFilter, 0x40)
+{
+ STDMETHOD(Init)() PURE;
+ STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size) PURE;
+ // Filter return outSize (UInt32)
+ // if (outSize <= size): Filter have converted outSize bytes
+ // if (outSize > size): Filter have not converted anything.
+ // and it needs at least outSize bytes to convert one block
+ // (it's for crypto block algorithms).
+};
+
+CODER_INTERFACE(ICryptoProperties, 0x80)
+{
+ STDMETHOD(SetKey)(const Byte *data, UInt32 size) PURE;
+ STDMETHOD(SetInitVector)(const Byte *data, UInt32 size) PURE;
+};
+
+CODER_INTERFACE(ICryptoSetPassword, 0x90)
+{
+ STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size) PURE;
+};
+
+CODER_INTERFACE(ICryptoSetCRC, 0xA0)
+{
+ STDMETHOD(CryptoSetCRC)(UInt32 crc) PURE;
+};
+
+//////////////////////
+// It's for DLL file
+namespace NMethodPropID
+{
+ enum EEnum
+ {
+ kID,
+ kName,
+ kDecoder,
+ kEncoder,
+ kInStreams,
+ kOutStreams,
+ kDescription
+ };
+}
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/IStream.h b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/IStream.h new file mode 100644 index 00000000..d92b89aa --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/7zip/IStream.h @@ -0,0 +1,62 @@ +// IStream.h
+
+#ifndef __ISTREAM_H
+#define __ISTREAM_H
+
+#include "../Common/MyUnknown.h"
+#include "../Common/Types.h"
+
+// "23170F69-40C1-278A-0000-000300xx0000"
+
+#define STREAM_INTERFACE_SUB(i, b, x) \
+DEFINE_GUID(IID_ ## i, \
+0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x03, 0x00, x, 0x00, 0x00); \
+struct i: public b
+
+#define STREAM_INTERFACE(i, x) STREAM_INTERFACE_SUB(i, IUnknown, x)
+
+STREAM_INTERFACE(ISequentialInStream, 0x01)
+{
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize) PURE;
+ /*
+ Out: if size != 0, return_value = S_OK and (*processedSize == 0),
+ then there are no more bytes in stream.
+ if (size > 0) && there are bytes in stream,
+ this function must read at least 1 byte.
+ This function is allowed to read less than number of remaining bytes in stream.
+ You must call Read function in loop, if you need exact amount of data
+ */
+};
+
+STREAM_INTERFACE(ISequentialOutStream, 0x02)
+{
+ STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize) PURE;
+ /*
+ if (size > 0) this function must write at least 1 byte.
+ This function is allowed to write less than "size".
+ You must call Write function in loop, if you need to write exact amount of data
+ */
+};
+
+STREAM_INTERFACE_SUB(IInStream, ISequentialInStream, 0x03)
+{
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) PURE;
+};
+
+STREAM_INTERFACE_SUB(IOutStream, ISequentialOutStream, 0x04)
+{
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) PURE;
+ STDMETHOD(SetSize)(Int64 newSize) PURE;
+};
+
+STREAM_INTERFACE(IStreamGetSize, 0x06)
+{
+ STDMETHOD(GetSize)(UInt64 *size) PURE;
+};
+
+STREAM_INTERFACE(IOutStreamFlush, 0x07)
+{
+ STDMETHOD(Flush)() PURE;
+};
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/Alloc.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/Alloc.cpp new file mode 100644 index 00000000..dcb331ee --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/Alloc.cpp @@ -0,0 +1,118 @@ +// Common/Alloc.cpp
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#include "MyWindows.h"
+#else
+#include <stdlib.h>
+#endif
+
+#include "Alloc.h"
+
+/* #define _SZ_ALLOC_DEBUG */
+/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
+#ifdef _SZ_ALLOC_DEBUG
+#include <stdio.h>
+int g_allocCount = 0;
+int g_allocCountMid = 0;
+int g_allocCountBig = 0;
+#endif
+
+void *MyAlloc(size_t size) throw()
+{
+ if (size == 0)
+ return 0;
+ #ifdef _SZ_ALLOC_DEBUG
+ fprintf(stderr, "\nAlloc %10d bytes; count = %10d", size, g_allocCount++);
+ #endif
+ return ::malloc(size);
+}
+
+void MyFree(void *address) throw()
+{
+ #ifdef _SZ_ALLOC_DEBUG
+ if (address != 0)
+ fprintf(stderr, "\nFree; count = %10d", --g_allocCount);
+ #endif
+
+ ::free(address);
+}
+
+#ifdef _WIN32
+
+void *MidAlloc(size_t size) throw()
+{
+ if (size == 0)
+ return 0;
+ #ifdef _SZ_ALLOC_DEBUG
+ fprintf(stderr, "\nAlloc_Mid %10d bytes; count = %10d", size, g_allocCountMid++);
+ #endif
+ return ::VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
+}
+
+void MidFree(void *address) throw()
+{
+ #ifdef _SZ_ALLOC_DEBUG
+ if (address != 0)
+ fprintf(stderr, "\nFree_Mid; count = %10d", --g_allocCountMid);
+ #endif
+ if (address == 0)
+ return;
+ ::VirtualFree(address, 0, MEM_RELEASE);
+}
+
+static SIZE_T g_LargePageSize =
+ #ifdef _WIN64
+ (1 << 21);
+ #else
+ (1 << 22);
+ #endif
+
+typedef SIZE_T (WINAPI *GetLargePageMinimumP)();
+
+bool SetLargePageSize()
+{
+ GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP)
+ ::GetProcAddress(::GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum");
+ if (largePageMinimum == 0)
+ return false;
+ SIZE_T size = largePageMinimum();
+ if (size == 0 || (size & (size - 1)) != 0)
+ return false;
+ g_LargePageSize = size;
+ return true;
+}
+
+
+void *BigAlloc(size_t size) throw()
+{
+ if (size == 0)
+ return 0;
+ #ifdef _SZ_ALLOC_DEBUG
+ fprintf(stderr, "\nAlloc_Big %10d bytes; count = %10d", size, g_allocCountBig++);
+ #endif
+
+ if (size >= (1 << 18))
+ {
+ void *res = ::VirtualAlloc(0, (size + g_LargePageSize - 1) & (~(g_LargePageSize - 1)),
+ MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
+ if (res != 0)
+ return res;
+ }
+ return ::VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
+}
+
+void BigFree(void *address) throw()
+{
+ #ifdef _SZ_ALLOC_DEBUG
+ if (address != 0)
+ fprintf(stderr, "\nFree_Big; count = %10d", --g_allocCountBig);
+ #endif
+
+ if (address == 0)
+ return;
+ ::VirtualFree(address, 0, MEM_RELEASE);
+}
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/Alloc.h b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/Alloc.h new file mode 100644 index 00000000..2ae3891d --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/Alloc.h @@ -0,0 +1,29 @@ +// Common/Alloc.h
+
+#ifndef __COMMON_ALLOC_H
+#define __COMMON_ALLOC_H
+
+#include <stddef.h>
+
+void *MyAlloc(size_t size) throw();
+void MyFree(void *address) throw();
+
+#ifdef _WIN32
+
+bool SetLargePageSize();
+
+void *MidAlloc(size_t size) throw();
+void MidFree(void *address) throw();
+void *BigAlloc(size_t size) throw();
+void BigFree(void *address) throw();
+
+#else
+
+#define MidAlloc(size) MyAlloc(size)
+#define MidFree(address) MyFree(address)
+#define BigAlloc(size) MyAlloc(size)
+#define BigFree(address) MyFree(address)
+
+#endif
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/CRC.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/CRC.cpp new file mode 100644 index 00000000..92bc009c --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/CRC.cpp @@ -0,0 +1,61 @@ +// Common/CRC.cpp
+
+#include "StdAfx.h"
+
+#include "CRC.h"
+
+static const UInt32 kCRCPoly = 0xEDB88320;
+
+UInt32 CCRC::Table[256];
+
+void CCRC::InitTable()
+{
+ for (UInt32 i = 0; i < 256; i++)
+ {
+ UInt32 r = i;
+ for (int j = 0; j < 8; j++)
+ if (r & 1)
+ r = (r >> 1) ^ kCRCPoly;
+ else
+ r >>= 1;
+ CCRC::Table[i] = r;
+ }
+}
+
+class CCRCTableInit
+{
+public:
+ CCRCTableInit() { CCRC::InitTable(); }
+} g_CRCTableInit;
+
+void CCRC::UpdateByte(Byte b)
+{
+ _value = Table[((Byte)(_value)) ^ b] ^ (_value >> 8);
+}
+
+void CCRC::UpdateUInt16(UInt16 v)
+{
+ UpdateByte(Byte(v));
+ UpdateByte(Byte(v >> 8));
+}
+
+void CCRC::UpdateUInt32(UInt32 v)
+{
+ for (int i = 0; i < 4; i++)
+ UpdateByte((Byte)(v >> (8 * i)));
+}
+
+void CCRC::UpdateUInt64(UInt64 v)
+{
+ for (int i = 0; i < 8; i++)
+ UpdateByte((Byte)(v >> (8 * i)));
+}
+
+void CCRC::Update(const void *data, size_t size)
+{
+ UInt32 v = _value;
+ const Byte *p = (const Byte *)data;
+ for (; size > 0 ; size--, p++)
+ v = Table[((Byte)(v)) ^ *p] ^ (v >> 8);
+ _value = v;
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/CRC.h b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/CRC.h new file mode 100644 index 00000000..c9d43d00 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/CRC.h @@ -0,0 +1,36 @@ +// Common/CRC.h
+
+#ifndef __COMMON_CRC_H
+#define __COMMON_CRC_H
+
+#include <stddef.h>
+#include "Types.h"
+
+class CCRC
+{
+ UInt32 _value;
+public:
+ static UInt32 Table[256];
+ static void InitTable();
+
+ CCRC(): _value(0xFFFFFFFF){};
+ void Init() { _value = 0xFFFFFFFF; }
+ void UpdateByte(Byte v);
+ void UpdateUInt16(UInt16 v);
+ void UpdateUInt32(UInt32 v);
+ void UpdateUInt64(UInt64 v);
+ void Update(const void *data, size_t size);
+ UInt32 GetDigest() const { return _value ^ 0xFFFFFFFF; }
+ static UInt32 CalculateDigest(const void *data, size_t size)
+ {
+ CCRC crc;
+ crc.Update(data, size);
+ return crc.GetDigest();
+ }
+ static bool VerifyDigest(UInt32 digest, const void *data, size_t size)
+ {
+ return (CalculateDigest(data, size) == digest);
+ }
+};
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/C_FileIO.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/C_FileIO.cpp new file mode 100644 index 00000000..48deb70a --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/C_FileIO.cpp @@ -0,0 +1,78 @@ +// Common/C_FileIO.h
+
+#include "C_FileIO.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+namespace NC {
+namespace NFile {
+namespace NIO {
+
+bool CFileBase::OpenBinary(const char *name, int flags)
+{
+ #ifdef O_BINARY
+ flags |= O_BINARY;
+ #endif
+ Close();
+ _handle = ::open(name, flags, 0666);
+ return _handle != -1;
+}
+
+bool CFileBase::Close()
+{
+ if(_handle == -1)
+ return true;
+ if (close(_handle) != 0)
+ return false;
+ _handle = -1;
+ return true;
+}
+
+bool CFileBase::GetLength(UInt64 &length) const
+{
+ off_t curPos = Seek(0, SEEK_CUR);
+ off_t lengthTemp = Seek(0, SEEK_END);
+ Seek(curPos, SEEK_SET);
+ length = (UInt64)lengthTemp;
+ return true;
+}
+
+off_t CFileBase::Seek(off_t distanceToMove, int moveMethod) const
+{
+ return ::lseek(_handle, distanceToMove, moveMethod);
+}
+
+/////////////////////////
+// CInFile
+
+bool CInFile::Open(const char *name)
+{
+ return CFileBase::OpenBinary(name, O_RDONLY);
+}
+
+ssize_t CInFile::Read(void *data, size_t size)
+{
+ return read(_handle, data, size);
+}
+
+/////////////////////////
+// COutFile
+
+bool COutFile::Create(const char *name, bool createAlways)
+{
+ if (createAlways)
+ {
+ Close();
+ _handle = ::creat(name, 0666);
+ return _handle != -1;
+ }
+ return OpenBinary(name, O_CREAT | O_EXCL | O_WRONLY);
+}
+
+ssize_t COutFile::Write(const void *data, size_t size)
+{
+ return write(_handle, data, size);
+}
+
+}}}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/C_FileIO.h b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/C_FileIO.h new file mode 100644 index 00000000..48836a15 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/C_FileIO.h @@ -0,0 +1,45 @@ +// Common/C_FileIO.h
+
+#ifndef __COMMON_C_FILEIO_H
+#define __COMMON_C_FILEIO_H
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "Types.h"
+#include "MyWindows.h"
+
+namespace NC {
+namespace NFile {
+namespace NIO {
+
+class CFileBase
+{
+protected:
+ int _handle;
+ bool OpenBinary(const char *name, int flags);
+public:
+ CFileBase(): _handle(-1) {};
+ ~CFileBase() { Close(); }
+ bool Close();
+ bool GetLength(UInt64 &length) const;
+ off_t Seek(off_t distanceToMove, int moveMethod) const;
+};
+
+class CInFile: public CFileBase
+{
+public:
+ bool Open(const char *name);
+ ssize_t Read(void *data, size_t size);
+};
+
+class COutFile: public CFileBase
+{
+public:
+ bool Create(const char *name, bool createAlways);
+ ssize_t Write(const void *data, size_t size);
+};
+
+}}}
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/ComTry.h b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/ComTry.h new file mode 100644 index 00000000..98e59276 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/ComTry.h @@ -0,0 +1,17 @@ +// ComTry.h
+
+#ifndef __COM_TRY_H
+#define __COM_TRY_H
+
+#include "MyWindows.h"
+// #include "Exception.h"
+// #include "NewHandler.h"
+
+#define COM_TRY_BEGIN try {
+#define COM_TRY_END } catch(...) { return E_OUTOFMEMORY; }
+
+ // catch(const CNewException &) { return E_OUTOFMEMORY; }\
+ // catch(const CSystemException &e) { return e.ErrorCode; }\
+ // catch(...) { return E_FAIL; }
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/CommandLineParser.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/CommandLineParser.cpp new file mode 100644 index 00000000..756e7166 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/CommandLineParser.cpp @@ -0,0 +1,263 @@ +// CommandLineParser.cpp
+
+#include "StdAfx.h"
+
+#include "CommandLineParser.h"
+
+namespace NCommandLineParser {
+
+void SplitCommandLine(const UString &src, UString &dest1, UString &dest2)
+{
+ dest1.Empty();
+ dest2.Empty();
+ bool quoteMode = false;
+ int i;
+ for (i = 0; i < src.Length(); i++)
+ {
+ wchar_t c = src[i];
+ if (c == L'\"')
+ quoteMode = !quoteMode;
+ else if (c == L' ' && !quoteMode)
+ {
+ i++;
+ break;
+ }
+ else
+ dest1 += c;
+ }
+ dest2 = src.Mid(i);
+}
+
+void SplitCommandLine(const UString &s, UStringVector &parts)
+{
+ UString sTemp = s;
+ sTemp.Trim();
+ parts.Clear();
+ while (true)
+ {
+ UString s1, s2;
+ SplitCommandLine(sTemp, s1, s2);
+ // s1.Trim();
+ // s2.Trim();
+ if (!s1.IsEmpty())
+ parts.Add(s1);
+ if (s2.IsEmpty())
+ return;
+ sTemp = s2;
+ }
+}
+
+
+static const wchar_t kSwitchID1 = '-';
+// static const wchar_t kSwitchID2 = '/';
+
+static const wchar_t kSwitchMinus = '-';
+static const wchar_t *kStopSwitchParsing = L"--";
+
+static bool IsItSwitchChar(wchar_t c)
+{
+ return (c == kSwitchID1 /*|| c == kSwitchID2 */);
+}
+
+CParser::CParser(int numSwitches):
+ _numSwitches(numSwitches)
+{
+ _switches = new CSwitchResult[_numSwitches];
+}
+
+CParser::~CParser()
+{
+ delete []_switches;
+}
+
+void CParser::ParseStrings(const CSwitchForm *switchForms,
+ const UStringVector &commandStrings)
+{
+ int numCommandStrings = commandStrings.Size();
+ bool stopSwitch = false;
+ for (int i = 0; i < numCommandStrings; i++)
+ {
+ const UString &s = commandStrings[i];
+ if (stopSwitch)
+ NonSwitchStrings.Add(s);
+ else
+ if (s == kStopSwitchParsing)
+ stopSwitch = true;
+ else
+ if (!ParseString(s, switchForms))
+ NonSwitchStrings.Add(s);
+ }
+}
+
+// if string contains switch then function updates switch structures
+// out: (string is a switch)
+bool CParser::ParseString(const UString &s, const CSwitchForm *switchForms)
+{
+ int len = s.Length();
+ if (len == 0)
+ return false;
+ int pos = 0;
+ if (!IsItSwitchChar(s[pos]))
+ return false;
+ while(pos < len)
+ {
+ if (IsItSwitchChar(s[pos]))
+ pos++;
+ const int kNoLen = -1;
+ int matchedSwitchIndex = 0; // GCC Warning
+ int maxLen = kNoLen;
+ for(int switchIndex = 0; switchIndex < _numSwitches; switchIndex++)
+ {
+ int switchLen = MyStringLen(switchForms[switchIndex].IDString);
+ if (switchLen <= maxLen || pos + switchLen > len)
+ continue;
+
+ UString temp = s + pos;
+ temp = temp.Left(switchLen);
+ if(temp.CompareNoCase(switchForms[switchIndex].IDString) == 0)
+ // if(_strnicmp(switchForms[switchIndex].IDString, LPCSTR(s) + pos, switchLen) == 0)
+ {
+ matchedSwitchIndex = switchIndex;
+ maxLen = switchLen;
+ }
+ }
+ if (maxLen == kNoLen)
+ throw "maxLen == kNoLen";
+ CSwitchResult &matchedSwitch = _switches[matchedSwitchIndex];
+ const CSwitchForm &switchForm = switchForms[matchedSwitchIndex];
+ if ((!switchForm.Multi) && matchedSwitch.ThereIs)
+ throw "switch must be single";
+ matchedSwitch.ThereIs = true;
+ pos += maxLen;
+ int tailSize = len - pos;
+ NSwitchType::EEnum type = switchForm.Type;
+ switch(type)
+ {
+ case NSwitchType::kPostMinus:
+ {
+ if (tailSize == 0)
+ matchedSwitch.WithMinus = false;
+ else
+ {
+ matchedSwitch.WithMinus = (s[pos] == kSwitchMinus);
+ if (matchedSwitch.WithMinus)
+ pos++;
+ }
+ break;
+ }
+ case NSwitchType::kPostChar:
+ {
+ if (tailSize < switchForm.MinLen)
+ throw "switch is not full";
+ UString set = switchForm.PostCharSet;
+ const int kEmptyCharValue = -1;
+ if (tailSize == 0)
+ matchedSwitch.PostCharIndex = kEmptyCharValue;
+ else
+ {
+ int index = set.Find(s[pos]);
+ if (index < 0)
+ matchedSwitch.PostCharIndex = kEmptyCharValue;
+ else
+ {
+ matchedSwitch.PostCharIndex = index;
+ pos++;
+ }
+ }
+ break;
+ }
+ case NSwitchType::kLimitedPostString:
+ case NSwitchType::kUnLimitedPostString:
+ {
+ int minLen = switchForm.MinLen;
+ if (tailSize < minLen)
+ throw "switch is not full";
+ if (type == NSwitchType::kUnLimitedPostString)
+ {
+ matchedSwitch.PostStrings.Add(s.Mid(pos));
+ return true;
+ }
+ int maxLen = switchForm.MaxLen;
+ UString stringSwitch = s.Mid(pos, minLen);
+ pos += minLen;
+ for(int i = minLen; i < maxLen && pos < len; i++, pos++)
+ {
+ wchar_t c = s[pos];
+ if (IsItSwitchChar(c))
+ break;
+ stringSwitch += c;
+ }
+ matchedSwitch.PostStrings.Add(stringSwitch);
+ break;
+ }
+ case NSwitchType::kSimple:
+ break;
+ }
+ }
+ return true;
+}
+
+const CSwitchResult& CParser::operator[](size_t index) const
+{
+ return _switches[index];
+}
+
+/////////////////////////////////
+// Command parsing procedures
+
+int ParseCommand(int numCommandForms, const CCommandForm *commandForms,
+ const UString &commandString, UString &postString)
+{
+ for(int i = 0; i < numCommandForms; i++)
+ {
+ const UString id = commandForms[i].IDString;
+ if (commandForms[i].PostStringMode)
+ {
+ if(commandString.Find(id) == 0)
+ {
+ postString = commandString.Mid(id.Length());
+ return i;
+ }
+ }
+ else
+ if (commandString == id)
+ {
+ postString.Empty();
+ return i;
+ }
+ }
+ return -1;
+}
+
+bool ParseSubCharsCommand(int numForms, const CCommandSubCharsSet *forms,
+ const UString &commandString, CIntVector &indices)
+{
+ indices.Clear();
+ int numUsedChars = 0;
+ for(int i = 0; i < numForms; i++)
+ {
+ const CCommandSubCharsSet &set = forms[i];
+ int currentIndex = -1;
+ int len = MyStringLen(set.Chars);
+ for(int j = 0; j < len; j++)
+ {
+ wchar_t c = set.Chars[j];
+ int newIndex = commandString.Find(c);
+ if (newIndex >= 0)
+ {
+ if (currentIndex >= 0)
+ return false;
+ if (commandString.Find(c, newIndex + 1) >= 0)
+ return false;
+ currentIndex = j;
+ numUsedChars++;
+ }
+ }
+ if(currentIndex == -1 && !set.EmptyAllowed)
+ return false;
+ indices.Add(currentIndex);
+ }
+ return (numUsedChars == commandString.Length());
+}
+
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/CommandLineParser.h b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/CommandLineParser.h new file mode 100644 index 00000000..75b3589c --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/CommandLineParser.h @@ -0,0 +1,82 @@ +// Common/CommandLineParser.h
+
+#ifndef __COMMON_COMMANDLINEPARSER_H
+#define __COMMON_COMMANDLINEPARSER_H
+
+#include "Common/String.h"
+
+namespace NCommandLineParser {
+
+void SplitCommandLine(const UString &src, UString &dest1, UString &dest2);
+void SplitCommandLine(const UString &s, UStringVector &parts);
+
+namespace NSwitchType {
+ enum EEnum
+ {
+ kSimple,
+ kPostMinus,
+ kLimitedPostString,
+ kUnLimitedPostString,
+ kPostChar
+ };
+}
+
+struct CSwitchForm
+{
+ const wchar_t *IDString;
+ NSwitchType::EEnum Type;
+ bool Multi;
+ int MinLen;
+ int MaxLen;
+ const wchar_t *PostCharSet;
+};
+
+struct CSwitchResult
+{
+ bool ThereIs;
+ bool WithMinus;
+ UStringVector PostStrings;
+ int PostCharIndex;
+ CSwitchResult(): ThereIs(false) {};
+};
+
+class CParser
+{
+ int _numSwitches;
+ CSwitchResult *_switches;
+ bool ParseString(const UString &s, const CSwitchForm *switchForms);
+public:
+ UStringVector NonSwitchStrings;
+ CParser(int numSwitches);
+ ~CParser();
+ void ParseStrings(const CSwitchForm *switchForms,
+ const UStringVector &commandStrings);
+ const CSwitchResult& operator[](size_t index) const;
+};
+
+/////////////////////////////////
+// Command parsing procedures
+
+struct CCommandForm
+{
+ wchar_t *IDString;
+ bool PostStringMode;
+};
+
+// Returns: Index of form and postString; -1, if there is no match
+int ParseCommand(int numCommandForms, const CCommandForm *commandForms,
+ const UString &commandString, UString &postString);
+
+struct CCommandSubCharsSet
+{
+ wchar_t *Chars;
+ bool EmptyAllowed;
+};
+
+// Returns: indices of finded chars; -1 if there is no match
+bool ParseSubCharsCommand(int numForms, const CCommandSubCharsSet *forms,
+ const UString &commandString, CIntVector &indices);
+
+}
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/Defs.h b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/Defs.h new file mode 100644 index 00000000..69b8ecea --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/Defs.h @@ -0,0 +1,20 @@ +// Common/Defs.h
+
+#ifndef __COMMON_DEFS_H
+#define __COMMON_DEFS_H
+
+template <class T> inline T MyMin(T a, T b)
+ { return a < b ? a : b; }
+template <class T> inline T MyMax(T a, T b)
+ { return a > b ? a : b; }
+
+template <class T> inline int MyCompare(T a, T b)
+ { return a < b ? -1 : (a == b ? 0 : 1); }
+
+inline int BoolToInt(bool value)
+ { return (value ? 1: 0); }
+
+inline bool IntToBool(int value)
+ { return (value != 0); }
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/MyCom.h b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/MyCom.h new file mode 100644 index 00000000..8476b572 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/MyCom.h @@ -0,0 +1,203 @@ +// MyCom.h
+
+#ifndef __MYCOM_H
+#define __MYCOM_H
+
+#include "MyWindows.h"
+
+#define RINOK(x) { HRESULT __result_ = (x); if(__result_ != S_OK) return __result_; }
+
+template <class T>
+class CMyComPtr
+{
+ T* _p;
+public:
+ // typedef T _PtrClass;
+ CMyComPtr() { _p = NULL;}
+ CMyComPtr(T* p) {if ((_p = p) != NULL) p->AddRef(); }
+ CMyComPtr(const CMyComPtr<T>& lp)
+ {
+ if ((_p = lp._p) != NULL)
+ _p->AddRef();
+ }
+ ~CMyComPtr() { if (_p) _p->Release(); }
+ void Release() { if (_p) { _p->Release(); _p = NULL; } }
+ operator T*() const { return (T*)_p; }
+ // T& operator*() const { return *_p; }
+ T** operator&() { return &_p; }
+ T* operator->() const { return _p; }
+ T* operator=(T* p)
+ {
+ if (p != 0)
+ p->AddRef();
+ if (_p)
+ _p->Release();
+ _p = p;
+ return p;
+ }
+ T* operator=(const CMyComPtr<T>& lp) { return (*this = lp._p); }
+ bool operator!() const { return (_p == NULL); }
+ // bool operator==(T* pT) const { return _p == pT; }
+ // Compare two objects for equivalence
+ void Attach(T* p2)
+ {
+ Release();
+ _p = p2;
+ }
+ T* Detach()
+ {
+ T* pt = _p;
+ _p = NULL;
+ return pt;
+ }
+ #ifdef _WIN32
+ HRESULT CoCreateInstance(REFCLSID rclsid, REFIID iid, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL)
+ {
+ return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, iid, (void**)&_p);
+ }
+ #endif
+ /*
+ HRESULT CoCreateInstance(LPCOLESTR szProgID, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL)
+ {
+ CLSID clsid;
+ HRESULT hr = CLSIDFromProgID(szProgID, &clsid);
+ ATLASSERT(_p == NULL);
+ if (SUCCEEDED(hr))
+ hr = ::CoCreateInstance(clsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&_p);
+ return hr;
+ }
+ */
+ template <class Q>
+ HRESULT QueryInterface(REFGUID iid, Q** pp) const
+ {
+ return _p->QueryInterface(iid, (void**)pp);
+ }
+};
+
+//////////////////////////////////////////////////////////
+
+class CMyComBSTR
+{
+public:
+ BSTR m_str;
+ CMyComBSTR() { m_str = NULL; }
+ CMyComBSTR(LPCOLESTR pSrc) { m_str = ::SysAllocString(pSrc); }
+ // CMyComBSTR(int nSize) { m_str = ::SysAllocStringLen(NULL, nSize); }
+ // CMyComBSTR(int nSize, LPCOLESTR sz) { m_str = ::SysAllocStringLen(sz, nSize); }
+ CMyComBSTR(const CMyComBSTR& src) { m_str = src.MyCopy(); }
+ /*
+ CMyComBSTR(REFGUID src)
+ {
+ LPOLESTR szGuid;
+ StringFromCLSID(src, &szGuid);
+ m_str = ::SysAllocString(szGuid);
+ CoTaskMemFree(szGuid);
+ }
+ */
+ ~CMyComBSTR() { ::SysFreeString(m_str); }
+ CMyComBSTR& operator=(const CMyComBSTR& src)
+ {
+ if (m_str != src.m_str)
+ {
+ if (m_str)
+ ::SysFreeString(m_str);
+ m_str = src.MyCopy();
+ }
+ return *this;
+ }
+ CMyComBSTR& operator=(LPCOLESTR pSrc)
+ {
+ ::SysFreeString(m_str);
+ m_str = ::SysAllocString(pSrc);
+ return *this;
+ }
+ unsigned int Length() const { return ::SysStringLen(m_str); }
+ operator BSTR() const { return m_str; }
+ BSTR* operator&() { return &m_str; }
+ BSTR MyCopy() const
+ {
+ int byteLen = ::SysStringByteLen(m_str);
+ BSTR res = ::SysAllocStringByteLen(NULL, byteLen);
+ memmove(res, m_str, byteLen);
+ return res;
+ }
+ void Attach(BSTR src) { m_str = src; }
+ BSTR Detach()
+ {
+ BSTR s = m_str;
+ m_str = NULL;
+ return s;
+ }
+ void Empty()
+ {
+ ::SysFreeString(m_str);
+ m_str = NULL;
+ }
+ bool operator!() const { return (m_str == NULL); }
+};
+
+
+//////////////////////////////////////////////////////////
+
+class CMyUnknownImp
+{
+public:
+ ULONG __m_RefCount;
+ CMyUnknownImp(): __m_RefCount(0) {}
+};
+
+#define MY_QUERYINTERFACE_BEGIN STDMETHOD(QueryInterface) \
+ (REFGUID iid, void **outObject) {
+
+#define MY_QUERYINTERFACE_ENTRY(i) if (iid == IID_ ## i) \
+ { *outObject = (void *)(i *)this; AddRef(); return S_OK; }
+
+#define MY_QUERYINTERFACE_END return E_NOINTERFACE; }
+
+#define MY_ADDREF_RELEASE \
+STDMETHOD_(ULONG, AddRef)() { return ++__m_RefCount; } \
+STDMETHOD_(ULONG, Release)() { if (--__m_RefCount != 0) \
+ return __m_RefCount; delete this; return 0; }
+
+#define MY_UNKNOWN_IMP_SPEC(i) \
+ MY_QUERYINTERFACE_BEGIN \
+ i \
+ MY_QUERYINTERFACE_END \
+ MY_ADDREF_RELEASE
+
+
+#define MY_UNKNOWN_IMP STDMETHOD(QueryInterface)(REFGUID, void **) { \
+ MY_QUERYINTERFACE_END \
+ MY_ADDREF_RELEASE
+
+#define MY_UNKNOWN_IMP1(i) MY_UNKNOWN_IMP_SPEC( \
+ MY_QUERYINTERFACE_ENTRY(i) \
+ )
+
+#define MY_UNKNOWN_IMP2(i1, i2) MY_UNKNOWN_IMP_SPEC( \
+ MY_QUERYINTERFACE_ENTRY(i1) \
+ MY_QUERYINTERFACE_ENTRY(i2) \
+ )
+
+#define MY_UNKNOWN_IMP3(i1, i2, i3) MY_UNKNOWN_IMP_SPEC( \
+ MY_QUERYINTERFACE_ENTRY(i1) \
+ MY_QUERYINTERFACE_ENTRY(i2) \
+ MY_QUERYINTERFACE_ENTRY(i3) \
+ )
+
+#define MY_UNKNOWN_IMP4(i1, i2, i3, i4) MY_UNKNOWN_IMP_SPEC( \
+ MY_QUERYINTERFACE_ENTRY(i1) \
+ MY_QUERYINTERFACE_ENTRY(i2) \
+ MY_QUERYINTERFACE_ENTRY(i3) \
+ MY_QUERYINTERFACE_ENTRY(i4) \
+ )
+
+#define MY_UNKNOWN_IMP5(i1, i2, i3, i4, i5) MY_UNKNOWN_IMP_SPEC( \
+ MY_QUERYINTERFACE_ENTRY(i1) \
+ MY_QUERYINTERFACE_ENTRY(i2) \
+ MY_QUERYINTERFACE_ENTRY(i3) \
+ MY_QUERYINTERFACE_ENTRY(i4) \
+ MY_QUERYINTERFACE_ENTRY(i5) \
+ )
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/MyGuidDef.h b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/MyGuidDef.h new file mode 100644 index 00000000..2cc8d199 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/MyGuidDef.h @@ -0,0 +1,54 @@ +// Common/MyGuidDef.h
+
+#ifndef GUID_DEFINED
+#define GUID_DEFINED
+
+#include "Types.h"
+
+typedef struct {
+ UInt32 Data1;
+ UInt16 Data2;
+ UInt16 Data3;
+ unsigned char Data4[8];
+} GUID;
+
+#ifdef __cplusplus
+#define REFGUID const GUID &
+#else
+#define REFGUID const GUID *
+#endif
+
+#define REFCLSID REFGUID
+#define REFIID REFGUID
+
+#ifdef __cplusplus
+inline bool operator==(REFGUID g1, REFGUID g2)
+{
+ for (int i = 0; i < (int)sizeof(g1); i++)
+ if (((unsigned char *)&g1)[i] != ((unsigned char *)&g2)[i])
+ return false;
+ return true;
+}
+inline bool operator!=(REFGUID g1, REFGUID g2) { return !(g1 == g2); }
+#endif
+
+#ifdef __cplusplus
+ #define MY_EXTERN_C extern "C"
+#else
+ #define MY_EXTERN_C extern
+#endif
+
+#endif // GUID_DEFINED
+
+
+#ifdef DEFINE_GUID
+#undef DEFINE_GUID
+#endif
+
+#ifdef INITGUID
+ #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ MY_EXTERN_C const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
+#else
+ #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ MY_EXTERN_C const GUID name
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/MyInitGuid.h b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/MyInitGuid.h new file mode 100644 index 00000000..53b0f034 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/MyInitGuid.h @@ -0,0 +1,13 @@ +// Common/MyInitGuid.h
+
+#ifndef __COMMON_MYINITGUID_H
+#define __COMMON_MYINITGUID_H
+
+#ifdef _WIN32
+#include <initguid.h>
+#else
+#define INITGUID
+#include "MyGuidDef.h"
+#endif
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/MyUnknown.h b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/MyUnknown.h new file mode 100644 index 00000000..6cd32cad --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/MyUnknown.h @@ -0,0 +1,24 @@ +// MyUnknown.h
+
+#ifndef __MYUNKNOWN_H
+#define __MYUNKNOWN_H
+
+#ifdef _WIN32
+
+#ifdef _WIN32_WCE
+#if (_WIN32_WCE > 300)
+#include <basetyps.h>
+#else
+#define MIDL_INTERFACE(x) struct
+#endif
+#else
+#include <basetyps.h>
+#endif
+
+#include <unknwn.h>
+
+#else
+#include "MyWindows.h"
+#endif
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/MyWindows.h b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/MyWindows.h new file mode 100644 index 00000000..65a4e9e7 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/MyWindows.h @@ -0,0 +1,183 @@ +// MyWindows.h
+
+#ifndef __MYWINDOWS_H
+#define __MYWINDOWS_H
+
+#ifdef _WIN32
+
+#include <windows.h>
+
+#else
+
+#include <stddef.h> // for wchar_t
+#include <string.h>
+
+#include "MyGuidDef.h"
+
+typedef char CHAR;
+typedef unsigned char UCHAR;
+typedef unsigned char BYTE;
+
+typedef short SHORT;
+typedef unsigned short USHORT;
+typedef unsigned short WORD;
+typedef short VARIANT_BOOL;
+
+typedef int INT;
+typedef Int32 INT32;
+typedef unsigned int UINT;
+typedef UInt32 UINT32;
+typedef INT32 LONG; // LONG, ULONG and DWORD must be 32-bit
+typedef UINT32 ULONG;
+typedef UINT32 DWORD;
+
+typedef Int64 LONGLONG;
+typedef UInt64 ULONGLONG;
+
+typedef struct LARGE_INTEGER { LONGLONG QuadPart; }LARGE_INTEGER;
+typedef struct _ULARGE_INTEGER { ULONGLONG QuadPart;} ULARGE_INTEGER;
+
+typedef const CHAR *LPCSTR;
+typedef CHAR TCHAR;
+typedef const TCHAR *LPCTSTR;
+typedef wchar_t WCHAR;
+typedef WCHAR OLECHAR;
+typedef const WCHAR *LPCWSTR;
+typedef OLECHAR *BSTR;
+typedef const OLECHAR *LPCOLESTR;
+typedef OLECHAR *LPOLESTR;
+
+typedef struct _FILETIME
+{
+ DWORD dwLowDateTime;
+ DWORD dwHighDateTime;
+}FILETIME;
+
+#define HRESULT LONG
+#define FAILED(Status) ((HRESULT)(Status)<0)
+typedef ULONG PROPID;
+typedef LONG SCODE;
+
+#define S_OK ((HRESULT)0x00000000L)
+#define S_FALSE ((HRESULT)0x00000001L)
+#define E_NOINTERFACE ((HRESULT)0x80004002L)
+#define E_ABORT ((HRESULT)0x80004004L)
+#define E_FAIL ((HRESULT)0x80004005L)
+#define STG_E_INVALIDFUNCTION ((HRESULT)0x80030001L)
+#define E_OUTOFMEMORY ((HRESULT)0x8007000EL)
+#define E_INVALIDARG ((HRESULT)0x80070057L)
+
+#ifdef _MSC_VER
+#define STDMETHODCALLTYPE __stdcall
+#else
+#define STDMETHODCALLTYPE
+#endif
+
+#define STDMETHOD_(t, f) virtual t STDMETHODCALLTYPE f
+#define STDMETHOD(f) STDMETHOD_(HRESULT, f)
+#define STDMETHODIMP_(type) type STDMETHODCALLTYPE
+#define STDMETHODIMP STDMETHODIMP_(HRESULT)
+
+#define PURE = 0
+
+#define MIDL_INTERFACE(x) struct
+
+struct IUnknown
+{
+ STDMETHOD(QueryInterface) (REFIID iid, void **outObject) PURE;
+ STDMETHOD_(ULONG, AddRef)() PURE;
+ STDMETHOD_(ULONG, Release)() PURE;
+};
+
+typedef IUnknown *LPUNKNOWN;
+
+#define VARIANT_TRUE ((VARIANT_BOOL)-1)
+#define VARIANT_FALSE ((VARIANT_BOOL)0)
+
+enum VARENUM
+{
+ VT_EMPTY = 0,
+ VT_NULL = 1,
+ VT_I2 = 2,
+ VT_I4 = 3,
+ VT_R4 = 4,
+ VT_R8 = 5,
+ VT_CY = 6,
+ VT_DATE = 7,
+ VT_BSTR = 8,
+ VT_DISPATCH = 9,
+ VT_ERROR = 10,
+ VT_BOOL = 11,
+ VT_VARIANT = 12,
+ VT_UNKNOWN = 13,
+ VT_DECIMAL = 14,
+ VT_I1 = 16,
+ VT_UI1 = 17,
+ VT_UI2 = 18,
+ VT_UI4 = 19,
+ VT_I8 = 20,
+ VT_UI8 = 21,
+ VT_INT = 22,
+ VT_UINT = 23,
+ VT_VOID = 24,
+ VT_HRESULT = 25,
+ VT_FILETIME = 64
+};
+
+typedef unsigned short VARTYPE;
+typedef WORD PROPVAR_PAD1;
+typedef WORD PROPVAR_PAD2;
+typedef WORD PROPVAR_PAD3;
+
+typedef struct tagPROPVARIANT
+{
+ VARTYPE vt;
+ PROPVAR_PAD1 wReserved1;
+ PROPVAR_PAD2 wReserved2;
+ PROPVAR_PAD3 wReserved3;
+ union
+ {
+ CHAR cVal;
+ UCHAR bVal;
+ SHORT iVal;
+ USHORT uiVal;
+ LONG lVal;
+ ULONG ulVal;
+ INT intVal;
+ UINT uintVal;
+ LARGE_INTEGER hVal;
+ ULARGE_INTEGER uhVal;
+ VARIANT_BOOL boolVal;
+ SCODE scode;
+ FILETIME filetime;
+ BSTR bstrVal;
+ };
+} PROPVARIANT;
+
+typedef PROPVARIANT tagVARIANT;
+typedef tagVARIANT VARIANT;
+typedef VARIANT VARIANTARG;
+
+MY_EXTERN_C BSTR SysAllocStringByteLen(LPCSTR psz, UINT len);
+MY_EXTERN_C BSTR SysAllocString(const OLECHAR *sz);
+MY_EXTERN_C void SysFreeString(BSTR bstr);
+MY_EXTERN_C UINT SysStringByteLen(BSTR bstr);
+MY_EXTERN_C UINT SysStringLen(BSTR bstr);
+
+MY_EXTERN_C DWORD GetLastError();
+MY_EXTERN_C HRESULT VariantClear(VARIANTARG *prop);
+MY_EXTERN_C HRESULT VariantCopy(VARIANTARG *dest, VARIANTARG *src);
+MY_EXTERN_C LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2);
+
+#define CP_ACP 0
+#define CP_OEMCP 1
+
+typedef enum tagSTREAM_SEEK
+{
+ STREAM_SEEK_SET = 0,
+ STREAM_SEEK_CUR = 1,
+ STREAM_SEEK_END = 2
+} STREAM_SEEK;
+
+#endif
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/NewHandler.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/NewHandler.cpp new file mode 100644 index 00000000..2f4e007b --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/NewHandler.cpp @@ -0,0 +1,114 @@ +// NewHandler.cpp
+
+#include "StdAfx.h"
+
+#include <stdlib.h>
+
+#include "NewHandler.h"
+
+// #define DEBUG_MEMORY_LEAK
+
+#ifndef DEBUG_MEMORY_LEAK
+
+void *
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator new(size_t size)
+{
+ // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size);
+ void *p = ::malloc(size);
+ if (p == 0)
+ throw CNewException();
+ return p;
+}
+
+void
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator delete(void *p) throw()
+{
+ /*
+ if (p == 0)
+ return;
+ ::HeapFree(::GetProcessHeap(), 0, p);
+ */
+ ::free(p);
+}
+
+#else
+
+#pragma init_seg(lib)
+const int kDebugSize = 1000000;
+static void *a[kDebugSize];
+static int index = 0;
+
+static int numAllocs = 0;
+void * __cdecl operator new(size_t size)
+{
+ numAllocs++;
+ void *p = HeapAlloc(GetProcessHeap(), 0, size);
+ if (index == 40)
+ {
+ int t = 1;
+ }
+ if (index < kDebugSize)
+ {
+ a[index] = p;
+ index++;
+ }
+ if (p == 0)
+ throw CNewException();
+ printf("Alloc %6d, size = %8d\n", numAllocs, size);
+ return p;
+}
+
+class CC
+{
+public:
+ CC()
+ {
+ for (int i = 0; i < kDebugSize; i++)
+ a[i] = 0;
+ }
+ ~CC()
+ {
+ for (int i = 0; i < kDebugSize; i++)
+ if (a[i] != 0)
+ return;
+ }
+} g_CC;
+
+
+void __cdecl operator delete(void *p)
+{
+ if (p == 0)
+ return;
+ /*
+ for (int i = 0; i < index; i++)
+ if (a[i] == p)
+ a[i] = 0;
+ */
+ HeapFree(GetProcessHeap(), 0, p);
+ numAllocs--;
+ printf("Free %d\n", numAllocs);
+}
+
+#endif
+
+/*
+int MemErrorVC(size_t)
+{
+ throw CNewException();
+ // return 1;
+}
+CNewHandlerSetter::CNewHandlerSetter()
+{
+ // MemErrorOldVCFunction = _set_new_handler(MemErrorVC);
+}
+CNewHandlerSetter::~CNewHandlerSetter()
+{
+ // _set_new_handler(MemErrorOldVCFunction);
+}
+*/
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/NewHandler.h b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/NewHandler.h new file mode 100644 index 00000000..b3a4f7e1 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/NewHandler.h @@ -0,0 +1,14 @@ +// Common/NewHandler.h
+
+#ifndef __COMMON_NEWHANDLER_H
+#define __COMMON_NEWHANDLER_H
+
+class CNewException {};
+
+void
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator delete(void *p) throw();
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/StdAfx.h b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/StdAfx.h new file mode 100644 index 00000000..2547611b --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/StdAfx.h @@ -0,0 +1,9 @@ +// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+// #include "MyWindows.h"
+#include "NewHandler.h"
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/String.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/String.cpp new file mode 100644 index 00000000..b6c12e99 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/String.cpp @@ -0,0 +1,198 @@ +// Common/String.cpp
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#include "StringConvert.h"
+#else
+#include <ctype.h>
+#endif
+
+#include "Common/String.h"
+
+
+#ifdef _WIN32
+
+#ifndef _UNICODE
+
+wchar_t MyCharUpper(wchar_t c)
+{
+ if (c == 0)
+ return 0;
+ wchar_t *res = CharUpperW((LPWSTR)(unsigned int)c);
+ if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+ return (wchar_t)(unsigned int)res;
+ const int kBufferSize = 4;
+ char s[kBufferSize + 1];
+ int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufferSize, 0, 0);
+ if (numChars == 0 || numChars > kBufferSize)
+ return c;
+ s[numChars] = 0;
+ ::CharUpperA(s);
+ ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1);
+ return c;
+}
+
+wchar_t MyCharLower(wchar_t c)
+{
+ if (c == 0)
+ return 0;
+ wchar_t *res = CharLowerW((LPWSTR)(unsigned int)c);
+ if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+ return (wchar_t)(unsigned int)res;
+ const int kBufferSize = 4;
+ char s[kBufferSize + 1];
+ int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufferSize, 0, 0);
+ if (numChars == 0 || numChars > kBufferSize)
+ return c;
+ s[numChars] = 0;
+ ::CharLowerA(s);
+ ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1);
+ return c;
+}
+
+wchar_t * MyStringUpper(wchar_t *s)
+{
+ if (s == 0)
+ return 0;
+ wchar_t *res = CharUpperW(s);
+ if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+ return res;
+ AString a = UnicodeStringToMultiByte(s);
+ a.MakeUpper();
+ return MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a));
+}
+
+wchar_t * MyStringLower(wchar_t *s)
+{
+ if (s == 0)
+ return 0;
+ wchar_t *res = CharLowerW(s);
+ if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+ return res;
+ AString a = UnicodeStringToMultiByte(s);
+ a.MakeLower();
+ return MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a));
+}
+
+#endif
+
+/*
+inline int ConvertCompareResult(int r) { return r - 2; }
+
+int MyStringCollate(const wchar_t *s1, const wchar_t *s2)
+{
+ int res = CompareStringW(
+ LOCALE_USER_DEFAULT, SORT_STRINGSORT, s1, -1, s2, -1);
+ #ifdef _UNICODE
+ return ConvertCompareResult(res);
+ #else
+ if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+ return ConvertCompareResult(res);
+ return MyStringCollate(UnicodeStringToMultiByte(s1),
+ UnicodeStringToMultiByte(s2));
+ #endif
+}
+
+#ifndef _WIN32_WCE
+int MyStringCollate(const char *s1, const char *s2)
+{
+ return ConvertCompareResult(CompareStringA(
+ LOCALE_USER_DEFAULT, SORT_STRINGSORT, s1, -1, s2, -1));
+}
+
+int MyStringCollateNoCase(const char *s1, const char *s2)
+{
+ return ConvertCompareResult(CompareStringA(
+ LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT, s1, -1, s2, -1));
+}
+#endif
+
+int MyStringCollateNoCase(const wchar_t *s1, const wchar_t *s2)
+{
+ int res = CompareStringW(
+ LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT, s1, -1, s2, -1);
+ #ifdef _UNICODE
+ return ConvertCompareResult(res);
+ #else
+ if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+ return ConvertCompareResult(res);
+ return MyStringCollateNoCase(UnicodeStringToMultiByte(s1),
+ UnicodeStringToMultiByte(s2));
+ #endif
+}
+*/
+
+#else
+
+wchar_t MyCharUpper(wchar_t c)
+{
+ return toupper(c);
+}
+
+/*
+int MyStringCollateNoCase(const wchar_t *s1, const wchar_t *s2)
+{
+ while (true)
+ {
+ wchar_t c1 = *s1++;
+ wchar_t c2 = *s2++;
+ wchar_t u1 = MyCharUpper(c1);
+ wchar_t u2 = MyCharUpper(c2);
+
+ if (u1 < u2) return -1;
+ if (u1 > u2) return 1;
+ if (u1 == 0) return 0;
+ }
+}
+*/
+
+#endif
+
+int MyStringCompare(const char *s1, const char *s2)
+{
+ while (true)
+ {
+ unsigned char c1 = (unsigned char)*s1++;
+ unsigned char c2 = (unsigned char)*s2++;
+ if (c1 < c2) return -1;
+ if (c1 > c2) return 1;
+ if (c1 == 0) return 0;
+ }
+}
+
+int MyStringCompare(const wchar_t *s1, const wchar_t *s2)
+{
+ while (true)
+ {
+ wchar_t c1 = *s1++;
+ wchar_t c2 = *s2++;
+ if (c1 < c2) return -1;
+ if (c1 > c2) return 1;
+ if (c1 == 0) return 0;
+ }
+}
+
+int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2)
+{
+ while (true)
+ {
+ wchar_t c1 = *s1++;
+ wchar_t c2 = *s2++;
+ if (c1 != c2)
+ {
+ wchar_t u1 = MyCharUpper(c1);
+ wchar_t u2 = MyCharUpper(c2);
+ if (u1 < u2) return -1;
+ if (u1 > u2) return 1;
+ }
+ if (c1 == 0) return 0;
+ }
+}
+
+#ifdef _WIN32
+int MyStringCompareNoCase(const char *s1, const char *s2)
+{
+ return MyStringCompareNoCase(MultiByteToUnicodeString(s1), MultiByteToUnicodeString(s2));
+}
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/String.h b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/String.h new file mode 100644 index 00000000..72a2c741 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/String.h @@ -0,0 +1,631 @@ +// Common/String.h
+
+#ifndef __COMMON_STRING_H
+#define __COMMON_STRING_H
+
+#include <string.h>
+// #include <wchar.h>
+
+#include "Vector.h"
+
+#ifdef _WIN32
+#include "MyWindows.h"
+#endif
+
+static const char *kTrimDefaultCharSet = " \n\t";
+
+template <class T>
+inline int MyStringLen(const T *s)
+{
+ int i;
+ for (i = 0; s[i] != '\0'; i++);
+ return i;
+}
+
+template <class T>
+inline T * MyStringCopy(T *dest, const T *src)
+{
+ T *destStart = dest;
+ while((*dest++ = *src++) != 0);
+ return destStart;
+}
+
+inline wchar_t* MyStringGetNextCharPointer(wchar_t *p)
+ { return (p + 1); }
+inline const wchar_t* MyStringGetNextCharPointer(const wchar_t *p)
+ { return (p + 1); }
+inline wchar_t* MyStringGetPrevCharPointer(const wchar_t *, wchar_t *p)
+ { return (p - 1); }
+inline const wchar_t* MyStringGetPrevCharPointer(const wchar_t *, const wchar_t *p)
+ { return (p - 1); }
+
+#ifdef _WIN32
+
+inline char* MyStringGetNextCharPointer(char *p)
+ { return CharNextA(p); }
+inline const char* MyStringGetNextCharPointer(const char *p)
+ { return CharNextA(p); }
+
+inline char* MyStringGetPrevCharPointer(char *base, char *p)
+ { return CharPrevA(base, p); }
+inline const char* MyStringGetPrevCharPointer(const char *base, const char *p)
+ { return CharPrevA(base, p); }
+
+inline char MyCharUpper(char c)
+ { return (char)(unsigned int)CharUpperA((LPSTR)(unsigned int)(unsigned char)c); }
+#ifdef _UNICODE
+inline wchar_t MyCharUpper(wchar_t c)
+ { return (wchar_t)CharUpperW((LPWSTR)c); }
+#else
+wchar_t MyCharUpper(wchar_t c);
+#endif
+
+inline char MyCharLower(char c)
+ { return (char)(unsigned int)CharLowerA((LPSTR)(unsigned int)(unsigned char)c); }
+#ifdef _UNICODE
+inline wchar_t MyCharLower(wchar_t c)
+ { return (wchar_t)CharLowerW((LPWSTR)c); }
+#else
+wchar_t MyCharLower(wchar_t c);
+#endif
+
+inline char * MyStringUpper(char *s) { return CharUpperA(s); }
+#ifdef _UNICODE
+inline wchar_t * MyStringUpper(wchar_t *s) { return CharUpperW(s); }
+#else
+wchar_t * MyStringUpper(wchar_t *s);
+#endif
+
+inline char * MyStringLower(char *s) { return CharLowerA(s); }
+#ifdef _UNICODE
+inline wchar_t * MyStringLower(wchar_t *s) { return CharLowerW(s); }
+#else
+wchar_t * MyStringLower(wchar_t *s);
+#endif
+
+#else // Standard-C
+wchar_t MyCharUpper(wchar_t c);
+#endif
+
+//////////////////////////////////////
+// Compare
+
+/*
+#ifndef _WIN32_WCE
+int MyStringCollate(const char *s1, const char *s2);
+int MyStringCollateNoCase(const char *s1, const char *s2);
+#endif
+int MyStringCollate(const wchar_t *s1, const wchar_t *s2);
+int MyStringCollateNoCase(const wchar_t *s1, const wchar_t *s2);
+*/
+
+int MyStringCompare(const char *s1, const char *s2);
+int MyStringCompare(const wchar_t *s1, const wchar_t *s2);
+
+#ifdef _WIN32
+int MyStringCompareNoCase(const char *s1, const char *s2);
+#endif
+
+int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2);
+
+template <class T>
+class CStringBase
+{
+ void TrimLeftWithCharSet(const CStringBase &charSet)
+ {
+ const T *p = _chars;
+ while (charSet.Find(*p) >= 0 && (*p != 0))
+ p = GetNextCharPointer(p);
+ Delete(0, (int)(p - _chars));
+ }
+ void TrimRightWithCharSet(const CStringBase &charSet)
+ {
+ const T *p = _chars;
+ const T *pLast = NULL;
+ while (*p != 0)
+ {
+ if (charSet.Find(*p) >= 0)
+ {
+ if (pLast == NULL)
+ pLast = p;
+ }
+ else
+ pLast = NULL;
+ p = GetNextCharPointer(p);
+ }
+ if(pLast != NULL)
+ {
+ int i = (int)(pLast - _chars);
+ Delete(i, _length - i);
+ }
+
+ }
+ void MoveItems(int destIndex, int srcIndex)
+ {
+ memmove(_chars + destIndex, _chars + srcIndex,
+ sizeof(T) * (_length - srcIndex + 1));
+ }
+
+ void InsertSpace(int &index, int size)
+ {
+ CorrectIndex(index);
+ GrowLength(size);
+ MoveItems(index + size, index);
+ }
+
+ static T *GetNextCharPointer(T *p)
+ { return MyStringGetNextCharPointer(p); }
+ static const T *GetNextCharPointer(const T *p)
+ { return MyStringGetNextCharPointer(p); }
+ static T *GetPrevCharPointer(T *base, T *p)
+ { return MyStringGetPrevCharPointer(base, p); }
+ static const T *GetPrevCharPointer(const T *base, const T *p)
+ { return MyStringGetPrevCharPointer(base, p); }
+protected:
+ T *_chars;
+ int _length;
+ int _capacity;
+
+ void SetCapacity(int newCapacity)
+ {
+ int realCapacity = newCapacity + 1;
+ if(realCapacity == _capacity)
+ return;
+ /*
+ const int kMaxStringSize = 0x20000000;
+ #ifndef _WIN32_WCE
+ if(newCapacity > kMaxStringSize || newCapacity < _length)
+ throw 1052337;
+ #endif
+ */
+ T *newBuffer = new T[realCapacity];
+ if(_capacity > 0)
+ {
+ for (int i = 0; i < (_length + 1); i++)
+ newBuffer[i] = _chars[i];
+ delete []_chars;
+ _chars = newBuffer;
+ }
+ else
+ {
+ _chars = newBuffer;
+ _chars[0] = 0;
+ }
+ _capacity = realCapacity;
+ }
+
+ void GrowLength(int n)
+ {
+ int freeSize = _capacity - _length - 1;
+ if (n <= freeSize)
+ return;
+ int delta;
+ if (_capacity > 64)
+ delta = _capacity / 2;
+ else if (_capacity > 8)
+ delta = 16;
+ else
+ delta = 4;
+ if (freeSize + delta < n)
+ delta = n - freeSize;
+ SetCapacity(_capacity + delta);
+ }
+
+ void CorrectIndex(int &index) const
+ {
+ if (index > _length)
+ index = _length;
+ }
+
+public:
+ CStringBase(): _chars(0), _length(0), _capacity(0)
+ { SetCapacity(16 - 1); }
+ CStringBase(T c): _chars(0), _length(0), _capacity(0)
+ {
+ SetCapacity(1);
+ _chars[0] = c;
+ _chars[1] = 0;
+ _length = 1;
+ }
+ CStringBase(const T *chars): _chars(0), _length(0), _capacity(0)
+ {
+ int length = MyStringLen(chars);
+ SetCapacity(length);
+ MyStringCopy(_chars, chars); // can be optimized by memove()
+ _length = length;
+ }
+ CStringBase(const CStringBase &s): _chars(0), _length(0), _capacity(0)
+ {
+ SetCapacity(s._length);
+ MyStringCopy(_chars, s._chars);
+ _length = s._length;
+ }
+ ~CStringBase() { delete []_chars; }
+
+ operator const T*() const { return _chars;}
+
+ // The minimum size of the character buffer in characters.
+ // This value does not include space for a null terminator.
+ T* GetBuffer(int minBufLength)
+ {
+ if(minBufLength >= _capacity)
+ SetCapacity(minBufLength + 1);
+ return _chars;
+ }
+ void ReleaseBuffer() { ReleaseBuffer(MyStringLen(_chars)); }
+ void ReleaseBuffer(int newLength)
+ {
+ /*
+ #ifndef _WIN32_WCE
+ if(newLength >= _capacity)
+ throw 282217;
+ #endif
+ */
+ _chars[newLength] = 0;
+ _length = newLength;
+ }
+
+ CStringBase& operator=(T c)
+ {
+ Empty();
+ SetCapacity(1);
+ _chars[0] = c;
+ _chars[1] = 0;
+ _length = 1;
+ return *this;
+ }
+ CStringBase& operator=(const T *chars)
+ {
+ Empty();
+ int length = MyStringLen(chars);
+ SetCapacity(length);
+ MyStringCopy(_chars, chars);
+ _length = length;
+ return *this;
+ }
+ CStringBase& operator=(const CStringBase& s)
+ {
+ if(&s == this)
+ return *this;
+ Empty();
+ SetCapacity(s._length);
+ MyStringCopy(_chars, s._chars);
+ _length = s._length;
+ return *this;
+ }
+
+ CStringBase& operator+=(T c)
+ {
+ GrowLength(1);
+ _chars[_length] = c;
+ _chars[++_length] = 0;
+ return *this;
+ }
+ CStringBase& operator+=(const T *s)
+ {
+ int len = MyStringLen(s);
+ GrowLength(len);
+ MyStringCopy(_chars + _length, s);
+ _length += len;
+ return *this;
+ }
+ CStringBase& operator+=(const CStringBase &s)
+ {
+ GrowLength(s._length);
+ MyStringCopy(_chars + _length, s._chars);
+ _length += s._length;
+ return *this;
+ }
+ void Empty()
+ {
+ _length = 0;
+ _chars[0] = 0;
+ }
+ int Length() const { return _length; }
+ bool IsEmpty() const { return (_length == 0); }
+
+ CStringBase Mid(int startIndex) const
+ { return Mid(startIndex, _length - startIndex); }
+ CStringBase Mid(int startIndex, int count ) const
+ {
+ if (startIndex + count > _length)
+ count = _length - startIndex;
+
+ if (startIndex == 0 && startIndex + count == _length)
+ return *this;
+
+ CStringBase<T> result;
+ result.SetCapacity(count);
+ // MyStringNCopy(result._chars, _chars + startIndex, count);
+ for (int i = 0; i < count; i++)
+ result._chars[i] = _chars[startIndex + i];
+ result._chars[count] = 0;
+ result._length = count;
+ return result;
+ }
+ CStringBase Left(int count) const
+ { return Mid(0, count); }
+ CStringBase Right(int count) const
+ {
+ if (count > _length)
+ count = _length;
+ return Mid(_length - count, count);
+ }
+
+ void MakeUpper()
+ { MyStringUpper(_chars); }
+ void MakeLower()
+ { MyStringLower(_chars); }
+
+ int Compare(const CStringBase& s) const
+ { return MyStringCompare(_chars, s._chars); }
+
+ int CompareNoCase(const CStringBase& s) const
+ { return MyStringCompareNoCase(_chars, s._chars); }
+ /*
+ int Collate(const CStringBase& s) const
+ { return MyStringCollate(_chars, s._chars); }
+ int CollateNoCase(const CStringBase& s) const
+ { return MyStringCollateNoCase(_chars, s._chars); }
+ */
+
+ int Find(T c) const { return Find(c, 0); }
+ int Find(T c, int startIndex) const
+ {
+ T *p = _chars + startIndex;
+ while (true)
+ {
+ if (*p == c)
+ return (int)(p - _chars);
+ if (*p == 0)
+ return -1;
+ p = GetNextCharPointer(p);
+ }
+ }
+ int Find(const CStringBase &s) const { return Find(s, 0); }
+ int Find(const CStringBase &s, int startIndex) const
+ {
+ if (s.IsEmpty())
+ return startIndex;
+ for (; startIndex < _length; startIndex++)
+ {
+ int j;
+ for (j = 0; j < s._length && startIndex + j < _length; j++)
+ if (_chars[startIndex+j] != s._chars[j])
+ break;
+ if (j == s._length)
+ return startIndex;
+ }
+ return -1;
+ }
+ int ReverseFind(T c) const
+ {
+ if (_length == 0)
+ return -1;
+ T *p = _chars + _length - 1;
+ while (true)
+ {
+ if (*p == c)
+ return (int)(p - _chars);
+ if (p == _chars)
+ return -1;
+ p = GetPrevCharPointer(_chars, p);
+ }
+ }
+ int FindOneOf(const CStringBase &s) const
+ {
+ for(int i = 0; i < _length; i++)
+ if (s.Find(_chars[i]) >= 0)
+ return i;
+ return -1;
+ }
+
+ void TrimLeft(T c)
+ {
+ const T *p = _chars;
+ while (c == *p)
+ p = GetNextCharPointer(p);
+ Delete(0, p - _chars);
+ }
+ private:
+ CStringBase GetTrimDefaultCharSet()
+ {
+ CStringBase<T> charSet;
+ for(int i = 0; i < (int)(sizeof(kTrimDefaultCharSet) /
+ sizeof(kTrimDefaultCharSet[0])); i++)
+ charSet += (T)kTrimDefaultCharSet[i];
+ return charSet;
+ }
+ public:
+
+ void TrimLeft()
+ {
+ TrimLeftWithCharSet(GetTrimDefaultCharSet());
+ }
+ void TrimRight()
+ {
+ TrimRightWithCharSet(GetTrimDefaultCharSet());
+ }
+ void TrimRight(T c)
+ {
+ const T *p = _chars;
+ const T *pLast = NULL;
+ while (*p != 0)
+ {
+ if (*p == c)
+ {
+ if (pLast == NULL)
+ pLast = p;
+ }
+ else
+ pLast = NULL;
+ p = GetNextCharPointer(p);
+ }
+ if(pLast != NULL)
+ {
+ int i = pLast - _chars;
+ Delete(i, _length - i);
+ }
+ }
+ void Trim()
+ {
+ TrimRight();
+ TrimLeft();
+ }
+
+ int Insert(int index, T c)
+ {
+ InsertSpace(index, 1);
+ _chars[index] = c;
+ _length++;
+ return _length;
+ }
+ int Insert(int index, const CStringBase &s)
+ {
+ CorrectIndex(index);
+ if (s.IsEmpty())
+ return _length;
+ int numInsertChars = s.Length();
+ InsertSpace(index, numInsertChars);
+ for(int i = 0; i < numInsertChars; i++)
+ _chars[index + i] = s[i];
+ _length += numInsertChars;
+ return _length;
+ }
+
+ // !!!!!!!!!!!!!!! test it if newChar = '\0'
+ int Replace(T oldChar, T newChar)
+ {
+ if (oldChar == newChar)
+ return 0;
+ int number = 0;
+ int pos = 0;
+ while (pos < Length())
+ {
+ pos = Find(oldChar, pos);
+ if (pos < 0)
+ break;
+ _chars[pos] = newChar;
+ pos++;
+ number++;
+ }
+ return number;
+ }
+ int Replace(const CStringBase &oldString, const CStringBase &newString)
+ {
+ if (oldString.IsEmpty())
+ return 0;
+ if (oldString == newString)
+ return 0;
+ int oldStringLength = oldString.Length();
+ int newStringLength = newString.Length();
+ int number = 0;
+ int pos = 0;
+ while (pos < _length)
+ {
+ pos = Find(oldString, pos);
+ if (pos < 0)
+ break;
+ Delete(pos, oldStringLength);
+ Insert(pos, newString);
+ pos += newStringLength;
+ number++;
+ }
+ return number;
+ }
+ int Delete(int index, int count = 1 )
+ {
+ if (index + count > _length)
+ count = _length - index;
+ if (count > 0)
+ {
+ MoveItems(index, index + count);
+ _length -= count;
+ }
+ return _length;
+ }
+};
+
+template <class T>
+CStringBase<T> operator+(const CStringBase<T>& s1, const CStringBase<T>& s2)
+{
+ CStringBase<T> result(s1);
+ result += s2;
+ return result;
+}
+
+template <class T>
+CStringBase<T> operator+(const CStringBase<T>& s, T c)
+{
+ CStringBase<T> result(s);
+ result += c;
+ return result;
+}
+
+template <class T>
+CStringBase<T> operator+(T c, const CStringBase<T>& s)
+{
+ CStringBase<T> result(c);
+ result += s;
+ return result;
+}
+
+template <class T>
+CStringBase<T> operator+(const CStringBase<T>& s, const T * chars)
+{
+ CStringBase<T> result(s);
+ result += chars;
+ return result;
+}
+
+template <class T>
+CStringBase<T> operator+(const T * chars, const CStringBase<T>& s)
+{
+ CStringBase<T> result(chars);
+ result += s;
+ return result;
+}
+
+template <class T>
+bool operator==(const CStringBase<T>& s1, const CStringBase<T>& s2)
+ { return (s1.Compare(s2) == 0); }
+
+template <class T>
+bool operator<(const CStringBase<T>& s1, const CStringBase<T>& s2)
+ { return (s1.Compare(s2) < 0); }
+
+template <class T>
+bool operator==(const T *s1, const CStringBase<T>& s2)
+ { return (s2.Compare(s1) == 0); }
+
+template <class T>
+bool operator==(const CStringBase<T>& s1, const T *s2)
+ { return (s1.Compare(s2) == 0); }
+
+template <class T>
+bool operator!=(const CStringBase<T>& s1, const CStringBase<T>& s2)
+ { return (s1.Compare(s2) != 0); }
+
+template <class T>
+bool operator!=(const T *s1, const CStringBase<T>& s2)
+ { return (s2.Compare(s1) != 0); }
+
+template <class T>
+bool operator!=(const CStringBase<T>& s1, const T *s2)
+ { return (s1.Compare(s2) != 0); }
+
+typedef CStringBase<char> AString;
+typedef CStringBase<wchar_t> UString;
+
+typedef CObjectVector<AString> AStringVector;
+typedef CObjectVector<UString> UStringVector;
+
+#ifdef _UNICODE
+ typedef UString CSysString;
+#else
+ typedef AString CSysString;
+#endif
+
+typedef CObjectVector<CSysString> CSysStringVector;
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/StringConvert.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/StringConvert.cpp new file mode 100644 index 00000000..4b5913ad --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/StringConvert.cpp @@ -0,0 +1,93 @@ +// Common/StringConvert.cpp
+
+#include "StdAfx.h"
+
+#include "StringConvert.h"
+
+#ifndef _WIN32
+#include <stdlib.h>
+#endif
+
+#ifdef _WIN32
+UString MultiByteToUnicodeString(const AString &srcString, UINT codePage)
+{
+ UString resultString;
+ if(!srcString.IsEmpty())
+ {
+ int numChars = MultiByteToWideChar(codePage, 0, srcString,
+ srcString.Length(), resultString.GetBuffer(srcString.Length()),
+ srcString.Length() + 1);
+ #ifndef _WIN32_WCE
+ if(numChars == 0)
+ throw 282228;
+ #endif
+ resultString.ReleaseBuffer(numChars);
+ }
+ return resultString;
+}
+
+AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage)
+{
+ AString resultString;
+ if(!srcString.IsEmpty())
+ {
+ int numRequiredBytes = srcString.Length() * 2;
+ int numChars = WideCharToMultiByte(codePage, 0, srcString,
+ srcString.Length(), resultString.GetBuffer(numRequiredBytes),
+ numRequiredBytes + 1, NULL, NULL);
+ #ifndef _WIN32_WCE
+ if(numChars == 0)
+ throw 282229;
+ #endif
+ resultString.ReleaseBuffer(numChars);
+ }
+ return resultString;
+}
+
+#ifndef _WIN32_WCE
+AString SystemStringToOemString(const CSysString &srcString)
+{
+ AString result;
+ CharToOem(srcString, result.GetBuffer(srcString.Length() * 2));
+ result.ReleaseBuffer();
+ return result;
+}
+#endif
+
+#else
+
+UString MultiByteToUnicodeString(const AString &srcString, UINT codePage)
+{
+ UString resultString;
+ for (int i = 0; i < srcString.Length(); i++)
+ resultString += wchar_t(srcString[i]);
+ /*
+ if(!srcString.IsEmpty())
+ {
+ int numChars = mbstowcs(resultString.GetBuffer(srcString.Length()), srcString, srcString.Length() + 1);
+ if (numChars < 0) throw "Your environment does not support UNICODE";
+ resultString.ReleaseBuffer(numChars);
+ }
+ */
+ return resultString;
+}
+
+AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage)
+{
+ AString resultString;
+ for (int i = 0; i < srcString.Length(); i++)
+ resultString += char(srcString[i]);
+ /*
+ if(!srcString.IsEmpty())
+ {
+ int numRequiredBytes = srcString.Length() * 6 + 1;
+ int numChars = wcstombs(resultString.GetBuffer(numRequiredBytes), srcString, numRequiredBytes);
+ if (numChars < 0) throw "Your environment does not support UNICODE";
+ resultString.ReleaseBuffer(numChars);
+ }
+ */
+ return resultString;
+}
+
+#endif
+
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/StringConvert.h b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/StringConvert.h new file mode 100644 index 00000000..921e33c7 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/StringConvert.h @@ -0,0 +1,71 @@ +// Common/StringConvert.h
+
+#ifndef __COMMON_STRINGCONVERT_H
+#define __COMMON_STRINGCONVERT_H
+
+#include "MyWindows.h"
+#include "Common/String.h"
+#include "Types.h"
+
+UString MultiByteToUnicodeString(const AString &srcString, UINT codePage = CP_ACP);
+AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage = CP_ACP);
+
+inline const wchar_t* GetUnicodeString(const wchar_t* unicodeString)
+ { return unicodeString; }
+inline const UString& GetUnicodeString(const UString &unicodeString)
+ { return unicodeString; }
+inline UString GetUnicodeString(const AString &ansiString)
+ { return MultiByteToUnicodeString(ansiString); }
+inline UString GetUnicodeString(const AString &multiByteString, UINT codePage)
+ { return MultiByteToUnicodeString(multiByteString, codePage); }
+inline const wchar_t* GetUnicodeString(const wchar_t* unicodeString, UINT)
+ { return unicodeString; }
+inline const UString& GetUnicodeString(const UString &unicodeString, UINT)
+ { return unicodeString; }
+
+inline const char* GetAnsiString(const char* ansiString)
+ { return ansiString; }
+inline const AString& GetAnsiString(const AString &ansiString)
+ { return ansiString; }
+inline AString GetAnsiString(const UString &unicodeString)
+ { return UnicodeStringToMultiByte(unicodeString); }
+
+inline const char* GetOemString(const char* oemString)
+ { return oemString; }
+inline const AString& GetOemString(const AString &oemString)
+ { return oemString; }
+inline AString GetOemString(const UString &unicodeString)
+ { return UnicodeStringToMultiByte(unicodeString, CP_OEMCP); }
+
+
+#ifdef _UNICODE
+ inline const wchar_t* GetSystemString(const wchar_t* unicodeString)
+ { return unicodeString;}
+ inline const UString& GetSystemString(const UString &unicodeString)
+ { return unicodeString;}
+ inline const wchar_t* GetSystemString(const wchar_t* unicodeString, UINT codePage)
+ { return unicodeString;}
+ inline const UString& GetSystemString(const UString &unicodeString, UINT codePage)
+ { return unicodeString;}
+ inline UString GetSystemString(const AString &multiByteString, UINT codePage)
+ { return MultiByteToUnicodeString(multiByteString, codePage);}
+ inline UString GetSystemString(const AString &multiByteString)
+ { return MultiByteToUnicodeString(multiByteString);}
+#else
+ inline const char* GetSystemString(const char *ansiString)
+ { return ansiString; }
+ inline const AString& GetSystemString(const AString &multiByteString, UINT)
+ { return multiByteString; }
+ inline const char * GetSystemString(const char *multiByteString, UINT)
+ { return multiByteString; }
+ inline AString GetSystemString(const UString &unicodeString)
+ { return UnicodeStringToMultiByte(unicodeString); }
+ inline AString GetSystemString(const UString &unicodeString, UINT codePage)
+ { return UnicodeStringToMultiByte(unicodeString, codePage); }
+#endif
+
+#ifndef _WIN32_WCE
+AString SystemStringToOemString(const CSysString &srcString);
+#endif
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/StringToInt.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/StringToInt.cpp new file mode 100644 index 00000000..18ecad5a --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/StringToInt.cpp @@ -0,0 +1,68 @@ +// Common/StringToInt.cpp
+
+#include "StdAfx.h"
+
+#include "StringToInt.h"
+
+UInt64 ConvertStringToUInt64(const char *s, const char **end)
+{
+ UInt64 result = 0;
+ while(true)
+ {
+ char c = *s;
+ if (c < '0' || c > '9')
+ {
+ if (end != NULL)
+ *end = s;
+ return result;
+ }
+ result *= 10;
+ result += (c - '0');
+ s++;
+ }
+}
+
+UInt64 ConvertOctStringToUInt64(const char *s, const char **end)
+{
+ UInt64 result = 0;
+ while(true)
+ {
+ char c = *s;
+ if (c < '0' || c > '7')
+ {
+ if (end != NULL)
+ *end = s;
+ return result;
+ }
+ result <<= 3;
+ result += (c - '0');
+ s++;
+ }
+}
+
+
+UInt64 ConvertStringToUInt64(const wchar_t *s, const wchar_t **end)
+{
+ UInt64 result = 0;
+ while(true)
+ {
+ wchar_t c = *s;
+ if (c < '0' || c > '9')
+ {
+ if (end != NULL)
+ *end = s;
+ return result;
+ }
+ result *= 10;
+ result += (c - '0');
+ s++;
+ }
+}
+
+
+Int64 ConvertStringToInt64(const char *s, const char **end)
+{
+ if (*s == '-')
+ return -(Int64)ConvertStringToUInt64(s + 1, end);
+ return ConvertStringToUInt64(s, end);
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/StringToInt.h b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/StringToInt.h new file mode 100644 index 00000000..d5614ef5 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/StringToInt.h @@ -0,0 +1,17 @@ +// Common/StringToInt.h
+
+#ifndef __COMMON_STRINGTOINT_H
+#define __COMMON_STRINGTOINT_H
+
+#include <string.h>
+#include "Types.h"
+
+UInt64 ConvertStringToUInt64(const char *s, const char **end);
+UInt64 ConvertOctStringToUInt64(const char *s, const char **end);
+UInt64 ConvertStringToUInt64(const wchar_t *s, const wchar_t **end);
+
+Int64 ConvertStringToInt64(const char *s, const char **end);
+
+#endif
+
+
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/Types.h b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/Types.h new file mode 100644 index 00000000..52d07081 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/Types.h @@ -0,0 +1,19 @@ +// Common/Types.h
+
+#ifndef __COMMON_TYPES_H
+#define __COMMON_TYPES_H
+
+typedef unsigned char Byte;
+typedef short Int16;
+typedef unsigned short UInt16;
+typedef int Int32;
+typedef unsigned int UInt32;
+#ifdef _MSC_VER
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#else
+typedef long long int Int64;
+typedef unsigned long long int UInt64;
+#endif
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/Vector.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/Vector.cpp new file mode 100644 index 00000000..f74d4c6c --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/Vector.cpp @@ -0,0 +1,74 @@ +// Common/Vector.cpp
+
+#include "StdAfx.h"
+
+#include <string.h>
+
+#include "Vector.h"
+
+CBaseRecordVector::~CBaseRecordVector()
+ { delete []((unsigned char *)_items); }
+void CBaseRecordVector::Clear()
+ { DeleteFrom(0); }
+void CBaseRecordVector::DeleteBack()
+ { Delete(_size - 1); }
+void CBaseRecordVector::DeleteFrom(int index)
+ { Delete(index, _size - index); }
+
+void CBaseRecordVector::ReserveOnePosition()
+{
+ if(_size != _capacity)
+ return;
+ int delta;
+ if (_capacity > 64)
+ delta = _capacity / 2;
+ else if (_capacity > 8)
+ delta = 8;
+ else
+ delta = 4;
+ Reserve(_capacity + delta);
+}
+
+void CBaseRecordVector::Reserve(int newCapacity)
+{
+ if(newCapacity <= _capacity)
+ return;
+ /*
+ #ifndef _DEBUG
+ static const unsigned int kMaxVectorSize = 0xF0000000;
+ if(newCapacity < _size ||
+ ((unsigned int )newCapacity * (unsigned int )_itemSize) > kMaxVectorSize)
+ throw 1052354;
+ #endif
+ */
+ unsigned char *p = new unsigned char[newCapacity * _itemSize];
+ int numRecordsToMove = _capacity;
+ memmove(p, _items, _itemSize * numRecordsToMove);
+ delete [](unsigned char *)_items;
+ _items = p;
+ _capacity = newCapacity;
+}
+
+void CBaseRecordVector::MoveItems(int destIndex, int srcIndex)
+{
+ memmove(((unsigned char *)_items) + destIndex * _itemSize,
+ ((unsigned char *)_items) + srcIndex * _itemSize,
+ _itemSize * (_size - srcIndex));
+}
+
+void CBaseRecordVector::InsertOneItem(int index)
+{
+ ReserveOnePosition();
+ MoveItems(index + 1, index);
+ _size++;
+}
+
+void CBaseRecordVector::Delete(int index, int num)
+{
+ TestIndexAndCorrectNum(index, num);
+ if (num > 0)
+ {
+ MoveItems(index, index + num);
+ _size -= num;
+ }
+}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Common/Vector.h b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/Vector.h new file mode 100644 index 00000000..0c7292a1 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Common/Vector.h @@ -0,0 +1,211 @@ +// Common/Vector.h
+
+#ifndef __COMMON_VECTOR_H
+#define __COMMON_VECTOR_H
+
+#include "Defs.h"
+
+class CBaseRecordVector
+{
+ void MoveItems(int destIndex, int srcIndex);
+protected:
+ int _capacity;
+ int _size;
+ void *_items;
+ size_t _itemSize;
+
+ void ReserveOnePosition();
+ void InsertOneItem(int index);
+ void TestIndexAndCorrectNum(int index, int &num) const
+ { if (index + num > _size) num = _size - index; }
+public:
+ CBaseRecordVector(size_t itemSize):
+ _capacity(0), _size(0), _items(0), _itemSize(itemSize) {}
+ virtual ~CBaseRecordVector();
+ int Size() const { return _size; }
+ bool IsEmpty() const { return (_size == 0); }
+ void Reserve(int newCapacity);
+ virtual void Delete(int index, int num = 1);
+ void Clear();
+ void DeleteFrom(int index);
+ void DeleteBack();
+};
+
+template <class T>
+class CRecordVector: public CBaseRecordVector
+{
+public:
+ CRecordVector():CBaseRecordVector(sizeof(T)){};
+ CRecordVector(const CRecordVector &v):
+ CBaseRecordVector(sizeof(T)) { *this = v;}
+ CRecordVector& operator=(const CRecordVector &v)
+ {
+ Clear();
+ return (*this += v);
+ }
+ CRecordVector& operator+=(const CRecordVector &v)
+ {
+ int size = v.Size();
+ Reserve(Size() + size);
+ for(int i = 0; i < size; i++)
+ Add(v[i]);
+ return *this;
+ }
+ int Add(T item)
+ {
+ ReserveOnePosition();
+ ((T *)_items)[_size] = item;
+ return _size++;
+ }
+ void Insert(int index, T item)
+ {
+ InsertOneItem(index);
+ ((T *)_items)[index] = item;
+ }
+ // T* GetPointer() const { return (T*)_items; }
+ // operator const T *() const { return _items; };
+ const T& operator[](int index) const { return ((T *)_items)[index]; }
+ T& operator[](int index) { return ((T *)_items)[index]; }
+ const T& Front() const { return operator[](0); }
+ T& Front() { return operator[](0); }
+ const T& Back() const { return operator[](_size - 1); }
+ T& Back() { return operator[](_size - 1); }
+
+ void Swap(int i, int j)
+ {
+ T temp = operator[](i);
+ operator[](i) = operator[](j);
+ operator[](j) = temp;
+ }
+
+ void Sort(int left, int right)
+ {
+ if (right - left < 2)
+ return;
+ Swap(left, (left + right) / 2);
+ int last = left;
+ for (int i = left; i < right; i++)
+ if (operator[](i) < operator[](left))
+ Swap(++last, i);
+ Swap(left, last);
+ Sort(left, last);
+ Sort(last + 1, right);
+ }
+ void Sort() { Sort(0, Size()); }
+ void Sort(int left, int right, int (*compare)(const T*, const T*, void *), void *param)
+ {
+ if (right - left < 2)
+ return;
+ Swap(left, (left + right) / 2);
+ int last = left;
+ for (int i = left; i < right; i++)
+ if (compare(&operator[](i), &operator[](left), param) < 0)
+ Swap(++last, i);
+ Swap(left, last);
+ Sort(left, last, compare, param);
+ Sort(last + 1, right, compare, param);
+ }
+
+ void Sort(int (*compare)(const T*, const T*, void *), void *param)
+ {
+ Sort(0, Size(), compare, param);
+ }
+};
+
+typedef CRecordVector<int> CIntVector;
+typedef CRecordVector<unsigned int> CUIntVector;
+typedef CRecordVector<bool> CBoolVector;
+typedef CRecordVector<unsigned char> CByteVector;
+typedef CRecordVector<void *> CPointerVector;
+
+template <class T>
+class CObjectVector: public CPointerVector
+{
+public:
+ CObjectVector(){};
+ ~CObjectVector() { Clear(); }
+ CObjectVector(const CObjectVector &objectVector)
+ { *this = objectVector; }
+ CObjectVector& operator=(const CObjectVector &objectVector)
+ {
+ Clear();
+ return (*this += objectVector);
+ }
+ CObjectVector& operator+=(const CObjectVector &objectVector)
+ {
+ int size = objectVector.Size();
+ Reserve(Size() + size);
+ for(int i = 0; i < size; i++)
+ Add(objectVector[i]);
+ return *this;
+ }
+ const T& operator[](int index) const { return *((T *)CPointerVector::operator[](index)); }
+ T& operator[](int index) { return *((T *)CPointerVector::operator[](index)); }
+ T& Front() { return operator[](0); }
+ const T& Front() const { return operator[](0); }
+ T& Back() { return operator[](_size - 1); }
+ const T& Back() const { return operator[](_size - 1); }
+ int Add(const T& item)
+ { return CPointerVector::Add(new T(item)); }
+ void Insert(int index, const T& item)
+ { CPointerVector::Insert(index, new T(item)); }
+ virtual void Delete(int index, int num = 1)
+ {
+ TestIndexAndCorrectNum(index, num);
+ for(int i = 0; i < num; i++)
+ delete (T *)(((void **)_items)[index + i]);
+ CPointerVector::Delete(index, num);
+ }
+ int Find(const T& item) const
+ {
+ for(int i = 0; i < Size(); i++)
+ if (item == (*this)[i])
+ return i;
+ return -1;
+ }
+ int FindInSorted(const T& item) const
+ {
+ int left = 0, right = Size();
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ const T& midValue = (*this)[mid];
+ if (item == midValue)
+ return mid;
+ if (item < midValue)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+ }
+ int AddToSorted(const T& item)
+ {
+ int left = 0, right = Size();
+ while (left != right)
+ {
+ int mid = (left + right) / 2;
+ const T& midValue = (*this)[mid];
+ if (item == midValue)
+ {
+ right = mid + 1;
+ break;
+ }
+ if (item < midValue)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ Insert(right, item);
+ return right;
+ }
+
+ void Sort(int (*compare)(void *const *, void *const *, void *), void *param)
+ { CPointerVector::Sort(compare, param); }
+
+ static int CompareObjectItems(void *const *a1, void *const *a2, void *param)
+ { return MyCompare(*(*((const T **)a1)), *(*((const T **)a2))); }
+ void Sort() { CPointerVector::Sort(CompareObjectItems, 0); }
+};
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Windows/Defs.h b/release/src/linux/linux/scripts/squashfs/lzma/C/Windows/Defs.h new file mode 100644 index 00000000..1b0c97a5 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Windows/Defs.h @@ -0,0 +1,18 @@ +// Windows/Defs.h
+
+#ifndef __WINDOWS_DEFS_H
+#define __WINDOWS_DEFS_H
+
+inline bool BOOLToBool(BOOL value)
+ { return (value != FALSE); }
+
+inline BOOL BoolToBOOL(bool value)
+ { return (value ? TRUE: FALSE); }
+
+inline VARIANT_BOOL BoolToVARIANT_BOOL(bool value)
+ { return (value ? VARIANT_TRUE: VARIANT_FALSE); }
+
+inline bool VARIANT_BOOLToBool(VARIANT_BOOL value)
+ { return (value != VARIANT_FALSE); }
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Windows/FileIO.cpp b/release/src/linux/linux/scripts/squashfs/lzma/C/Windows/FileIO.cpp new file mode 100644 index 00000000..20b5fc15 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Windows/FileIO.cpp @@ -0,0 +1,245 @@ +// Windows/FileIO.cpp
+
+#include "StdAfx.h"
+
+#include "FileIO.h"
+#include "Defs.h"
+#ifndef _UNICODE
+#include "../Common/StringConvert.h"
+#endif
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NFile {
+namespace NIO {
+
+CFileBase::~CFileBase() { Close(); }
+
+bool CFileBase::Create(LPCTSTR fileName, DWORD desiredAccess,
+ DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+{
+ Close();
+ _handle = ::CreateFile(fileName, desiredAccess, shareMode,
+ (LPSECURITY_ATTRIBUTES)NULL, creationDisposition,
+ flagsAndAttributes, (HANDLE) NULL);
+ return (_fileIsOpen = (_handle != INVALID_HANDLE_VALUE));
+}
+
+#ifndef _UNICODE
+bool CFileBase::Create(LPCWSTR fileName, DWORD desiredAccess,
+ DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+{
+ if (g_IsNT)
+ {
+ Close();
+ _handle = ::CreateFileW(fileName, desiredAccess, shareMode,
+ (LPSECURITY_ATTRIBUTES)NULL, creationDisposition,
+ flagsAndAttributes, (HANDLE) NULL);
+ return (_fileIsOpen = (_handle != INVALID_HANDLE_VALUE));
+ }
+ return Create(UnicodeStringToMultiByte(fileName, ::AreFileApisANSI() ? CP_ACP : CP_OEMCP),
+ desiredAccess, shareMode, creationDisposition, flagsAndAttributes);
+}
+#endif
+
+bool CFileBase::Close()
+{
+ if(!_fileIsOpen)
+ return true;
+ bool result = BOOLToBool(::CloseHandle(_handle));
+ _fileIsOpen = !result;
+ return result;
+}
+
+bool CFileBase::GetPosition(UInt64 &position) const
+{
+ return Seek(0, FILE_CURRENT, position);
+}
+
+bool CFileBase::GetLength(UInt64 &length) const
+{
+ DWORD sizeHigh;
+ DWORD sizeLow = ::GetFileSize(_handle, &sizeHigh);
+ if(sizeLow == 0xFFFFFFFF)
+ if(::GetLastError() != NO_ERROR)
+ return false;
+ length = (((UInt64)sizeHigh) << 32) + sizeLow;
+ return true;
+}
+
+bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const
+{
+ LARGE_INTEGER value;
+ value.QuadPart = distanceToMove;
+ value.LowPart = ::SetFilePointer(_handle, value.LowPart, &value.HighPart, moveMethod);
+ if (value.LowPart == 0xFFFFFFFF)
+ if(::GetLastError() != NO_ERROR)
+ return false;
+ newPosition = value.QuadPart;
+ return true;
+}
+
+bool CFileBase::Seek(UInt64 position, UInt64 &newPosition)
+{
+ return Seek(position, FILE_BEGIN, newPosition);
+}
+
+bool CFileBase::SeekToBegin()
+{
+ UInt64 newPosition;
+ return Seek(0, newPosition);
+}
+
+bool CFileBase::SeekToEnd(UInt64 &newPosition)
+{
+ return Seek(0, FILE_END, newPosition);
+}
+
+bool CFileBase::GetFileInformation(CByHandleFileInfo &fileInfo) const
+{
+ BY_HANDLE_FILE_INFORMATION winFileInfo;
+ if(!::GetFileInformationByHandle(_handle, &winFileInfo))
+ return false;
+ fileInfo.Attributes = winFileInfo.dwFileAttributes;
+ fileInfo.CreationTime = winFileInfo.ftCreationTime;
+ fileInfo.LastAccessTime = winFileInfo.ftLastAccessTime;
+ fileInfo.LastWriteTime = winFileInfo.ftLastWriteTime;
+ fileInfo.VolumeSerialNumber = winFileInfo.dwFileAttributes;
+ fileInfo.Size = (((UInt64)winFileInfo.nFileSizeHigh) << 32) + winFileInfo.nFileSizeLow;
+ fileInfo.NumberOfLinks = winFileInfo.nNumberOfLinks;
+ fileInfo.FileIndex = (((UInt64)winFileInfo.nFileIndexHigh) << 32) + winFileInfo.nFileIndexLow;
+ return true;
+}
+
+/////////////////////////
+// CInFile
+
+bool CInFile::Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+ { return Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes); }
+
+bool CInFile::Open(LPCTSTR fileName)
+ { return Open(fileName, FILE_SHARE_READ, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); }
+
+#ifndef _UNICODE
+bool CInFile::Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+ { return Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes); }
+
+bool CInFile::Open(LPCWSTR fileName)
+ { return Open(fileName, FILE_SHARE_READ, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); }
+#endif
+
+// ReadFile and WriteFile functions in Windows have BUG:
+// If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
+// from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
+// (Insufficient system resources exist to complete the requested service).
+
+static UInt32 kChunkSizeMax = (1 << 24);
+
+bool CInFile::ReadPart(void *data, UInt32 size, UInt32 &processedSize)
+{
+ if (size > kChunkSizeMax)
+ size = kChunkSizeMax;
+ DWORD processedLoc = 0;
+ bool res = BOOLToBool(::ReadFile(_handle, data, size, &processedLoc, NULL));
+ processedSize = (UInt32)processedLoc;
+ return res;
+}
+
+bool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize)
+{
+ processedSize = 0;
+ do
+ {
+ UInt32 processedLoc = 0;
+ bool res = ReadPart(data, size, processedLoc);
+ processedSize += processedLoc;
+ if (!res)
+ return false;
+ if (processedLoc == 0)
+ return true;
+ data = (void *)((unsigned char *)data + processedLoc);
+ size -= processedLoc;
+ }
+ while (size > 0);
+ return true;
+}
+
+/////////////////////////
+// COutFile
+
+bool COutFile::Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+ { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); }
+
+static inline DWORD GetCreationDisposition(bool createAlways)
+ { return createAlways? CREATE_ALWAYS: CREATE_NEW; }
+
+bool COutFile::Open(LPCTSTR fileName, DWORD creationDisposition)
+ { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); }
+
+bool COutFile::Create(LPCTSTR fileName, bool createAlways)
+ { return Open(fileName, GetCreationDisposition(createAlways)); }
+
+#ifndef _UNICODE
+
+bool COutFile::Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+ { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); }
+
+bool COutFile::Open(LPCWSTR fileName, DWORD creationDisposition)
+ { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); }
+
+bool COutFile::Create(LPCWSTR fileName, bool createAlways)
+ { return Open(fileName, GetCreationDisposition(createAlways)); }
+
+#endif
+
+bool COutFile::SetTime(const FILETIME *creationTime, const FILETIME *lastAccessTime, const FILETIME *lastWriteTime)
+ { return BOOLToBool(::SetFileTime(_handle, creationTime, lastAccessTime, lastWriteTime)); }
+
+bool COutFile::SetLastWriteTime(const FILETIME *lastWriteTime)
+ { return SetTime(NULL, NULL, lastWriteTime); }
+
+bool COutFile::WritePart(const void *data, UInt32 size, UInt32 &processedSize)
+{
+ if (size > kChunkSizeMax)
+ size = kChunkSizeMax;
+ DWORD processedLoc = 0;
+ bool res = BOOLToBool(::WriteFile(_handle, data, size, &processedLoc, NULL));
+ processedSize = (UInt32)processedLoc;
+ return res;
+}
+
+bool COutFile::Write(const void *data, UInt32 size, UInt32 &processedSize)
+{
+ processedSize = 0;
+ do
+ {
+ UInt32 processedLoc = 0;
+ bool res = WritePart(data, size, processedLoc);
+ processedSize += processedLoc;
+ if (!res)
+ return false;
+ if (processedLoc == 0)
+ return true;
+ data = (const void *)((const unsigned char *)data + processedLoc);
+ size -= processedLoc;
+ }
+ while (size > 0);
+ return true;
+}
+
+bool COutFile::SetEndOfFile() { return BOOLToBool(::SetEndOfFile(_handle)); }
+
+bool COutFile::SetLength(UInt64 length)
+{
+ UInt64 newPosition;
+ if(!Seek(length, newPosition))
+ return false;
+ if(newPosition != length)
+ return false;
+ return SetEndOfFile();
+}
+
+}}}
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Windows/FileIO.h b/release/src/linux/linux/scripts/squashfs/lzma/C/Windows/FileIO.h new file mode 100644 index 00000000..de66d7f3 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Windows/FileIO.h @@ -0,0 +1,98 @@ +// Windows/FileIO.h
+
+#ifndef __WINDOWS_FILEIO_H
+#define __WINDOWS_FILEIO_H
+
+#include "../Common/Types.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NIO {
+
+struct CByHandleFileInfo
+{
+ DWORD Attributes;
+ FILETIME CreationTime;
+ FILETIME LastAccessTime;
+ FILETIME LastWriteTime;
+ DWORD VolumeSerialNumber;
+ UInt64 Size;
+ DWORD NumberOfLinks;
+ UInt64 FileIndex;
+};
+
+class CFileBase
+{
+protected:
+ bool _fileIsOpen;
+ HANDLE _handle;
+ bool Create(LPCTSTR fileName, DWORD desiredAccess,
+ DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+ #ifndef _UNICODE
+ bool Create(LPCWSTR fileName, DWORD desiredAccess,
+ DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+ #endif
+
+public:
+ CFileBase(): _fileIsOpen(false){};
+ virtual ~CFileBase();
+
+ virtual bool Close();
+
+ bool GetPosition(UInt64 &position) const;
+ bool GetLength(UInt64 &length) const;
+
+ bool Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const;
+ bool Seek(UInt64 position, UInt64 &newPosition);
+ bool SeekToBegin();
+ bool SeekToEnd(UInt64 &newPosition);
+
+ bool GetFileInformation(CByHandleFileInfo &fileInfo) const;
+};
+
+class CInFile: public CFileBase
+{
+public:
+ bool Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+ bool Open(LPCTSTR fileName);
+ #ifndef _UNICODE
+ bool Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+ bool Open(LPCWSTR fileName);
+ #endif
+ bool ReadPart(void *data, UInt32 size, UInt32 &processedSize);
+ bool Read(void *data, UInt32 size, UInt32 &processedSize);
+};
+
+class COutFile: public CFileBase
+{
+ // DWORD m_CreationDisposition;
+public:
+ // COutFile(): m_CreationDisposition(CREATE_NEW){};
+ bool Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+ bool Open(LPCTSTR fileName, DWORD creationDisposition);
+ bool Create(LPCTSTR fileName, bool createAlways);
+
+ #ifndef _UNICODE
+ bool Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+ bool Open(LPCWSTR fileName, DWORD creationDisposition);
+ bool Create(LPCWSTR fileName, bool createAlways);
+ #endif
+
+ /*
+ void SetOpenCreationDisposition(DWORD creationDisposition)
+ { m_CreationDisposition = creationDisposition; }
+ void SetOpenCreationDispositionCreateAlways()
+ { m_CreationDisposition = CREATE_ALWAYS; }
+ */
+
+ bool SetTime(const FILETIME *creationTime, const FILETIME *lastAccessTime, const FILETIME *lastWriteTime);
+ bool SetLastWriteTime(const FILETIME *lastWriteTime);
+ bool WritePart(const void *data, UInt32 size, UInt32 &processedSize);
+ bool Write(const void *data, UInt32 size, UInt32 &processedSize);
+ bool SetEndOfFile();
+ bool SetLength(UInt64 length);
+};
+
+}}}
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/C/Windows/StdAfx.h b/release/src/linux/linux/scripts/squashfs/lzma/C/Windows/StdAfx.h new file mode 100644 index 00000000..e0f76050 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/C/Windows/StdAfx.h @@ -0,0 +1,9 @@ +// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../Common/MyWindows.h"
+#include "../Common/NewHandler.h"
+
+#endif
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/CPL.html b/release/src/linux/linux/scripts/squashfs/lzma/CPL.html new file mode 100644 index 00000000..f1d3be11 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/CPL.html @@ -0,0 +1,224 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<HTML><HEAD><TITLE>Common Public License - v 1.0</TITLE>
+<META http-equiv=Content-Type content="text/html; charset=ISO-8859-1">
+<BODY vLink=#800000 bgColor=#ffffff>
+<P align=center><B>Common Public License - v 1.0</B>
+<P><B></B><FONT size=3></FONT>
+<P><FONT size=3></FONT><FONT size=2>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER
+THE TERMS OF THIS COMMON PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR
+DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS
+AGREEMENT.</FONT>
+<P><FONT size=2></FONT>
+<P><FONT size=2><B>1. DEFINITIONS</B></FONT>
+<P><FONT size=2>"Contribution" means:</FONT>
+<UL><FONT size=2>a) in the case of the initial Contributor, the initial code
+ and documentation distributed under this Agreement, and<BR clear=left>b) in
+ the case of each subsequent Contributor:</FONT></UL>
+<UL><FONT size=2>i) changes to the Program, and</FONT></UL>
+<UL><FONT size=2>ii) additions to the Program;</FONT></UL>
+<UL><FONT size=2>where such changes and/or additions to the Program originate
+ from and are distributed by that particular Contributor. </FONT><FONT size=2>A
+ Contribution 'originates' from a Contributor if it was added to the Program by
+ such Contributor itself or anyone acting on such Contributor's behalf.
+ </FONT><FONT size=2>Contributions do not include additions to the Program
+ which: (i) are separate modules of software distributed in conjunction with
+ the Program under their own license agreement, and (ii) are not derivative
+ works of the Program. </FONT></UL>
+<P><FONT size=2></FONT>
+<P><FONT size=2>"Contributor" means any person or entity that distributes the
+Program.</FONT>
+<P><FONT size=2></FONT><FONT size=2></FONT>
+<P><FONT size=2>"Licensed Patents " mean patent claims licensable by a
+Contributor which are necessarily infringed by the use or sale of its
+Contribution alone or when combined with the Program. </FONT>
+<P><FONT size=2></FONT><FONT size=2></FONT>
+<P><FONT size=2></FONT><FONT size=2>"Program" means the Contributions
+distributed in accordance with this Agreement.</FONT>
+<P><FONT size=2></FONT>
+<P><FONT size=2>"Recipient" means anyone who receives the Program under this
+Agreement, including all Contributors.</FONT>
+<P><FONT size=2><B></B></FONT>
+<P><FONT size=2><B>2. GRANT OF RIGHTS</B></FONT>
+<UL><FONT size=2></FONT><FONT size=2>a) </FONT><FONT size=2>Subject to the
+ terms of this Agreement, each Contributor hereby grants</FONT><FONT size=2>
+ Recipient a non-exclusive, worldwide, royalty-free copyright license
+ to</FONT><FONT color=#ff0000 size=2> </FONT><FONT size=2>reproduce, prepare
+ derivative works of, publicly display, publicly perform, distribute and
+ sublicense the Contribution of such Contributor, if any, and such derivative
+ works, in source code and object code form.</FONT></UL>
+<UL><FONT size=2></FONT></UL>
+<UL><FONT size=2></FONT><FONT size=2>b) Subject to the terms of this
+ Agreement, each Contributor hereby grants </FONT><FONT size=2>Recipient a
+ non-exclusive, worldwide,</FONT><FONT color=#008000 size=2> </FONT><FONT
+ size=2>royalty-free patent license under Licensed Patents to make, use, sell,
+ offer to sell, import and otherwise transfer the Contribution of such
+ Contributor, if any, in source code and object code form. This patent license
+ shall apply to the combination of the Contribution and the Program if, at the
+ time the Contribution is added by the Contributor, such addition of the
+ Contribution causes such combination to be covered by the Licensed Patents.
+ The patent license shall not apply to any other combinations which include the
+ Contribution. No hardware per se is licensed hereunder. </FONT></UL>
+<UL><FONT size=2></FONT></UL>
+<UL><FONT size=2>c) Recipient understands that although each Contributor
+ grants the licenses to its Contributions set forth herein, no assurances are
+ provided by any Contributor that the Program does not infringe the patent or
+ other intellectual property rights of any other entity. Each Contributor
+ disclaims any liability to Recipient for claims brought by any other entity
+ based on infringement of intellectual property rights or otherwise. As a
+ condition to exercising the rights and licenses granted hereunder, each
+ Recipient hereby assumes sole responsibility to secure any other intellectual
+ property rights needed, if any. For example, if a third party patent license
+ is required to allow Recipient to distribute the Program, it is Recipient's
+ responsibility to acquire that license before distributing the
+Program.</FONT></UL>
+<UL><FONT size=2></FONT></UL>
+<UL><FONT size=2>d) Each Contributor represents that to its knowledge it has
+ sufficient copyright rights in its Contribution, if any, to grant the
+ copyright license set forth in this Agreement. </FONT></UL>
+<UL><FONT size=2></FONT></UL>
+<P><FONT size=2><B>3. REQUIREMENTS</B></FONT>
+<P><FONT size=2><B></B>A Contributor may choose to distribute the Program in
+object code form under its own license agreement, provided that:</FONT>
+<UL><FONT size=2>a) it complies with the terms and conditions of this
+ Agreement; and</FONT></UL>
+<UL><FONT size=2>b) its license agreement:</FONT></UL>
+<UL><FONT size=2>i) effectively disclaims</FONT><FONT size=2> on behalf of all
+ Contributors all warranties and conditions, express and implied, including
+ warranties or conditions of title and non-infringement, and implied warranties
+ or conditions of merchantability and fitness for a particular purpose;
+</FONT></UL>
+<UL><FONT size=2>ii) effectively excludes on behalf of all Contributors all
+ liability for damages, including direct, indirect, special, incidental and
+ consequential damages, such as lost profits; </FONT></UL>
+<UL><FONT size=2>iii)</FONT><FONT size=2> states that any provisions which
+ differ from this Agreement are offered by that Contributor alone and not by
+ any other party; and</FONT></UL>
+<UL><FONT size=2>iv) states that source code for the Program is available from
+ such Contributor, and informs licensees how to obtain it in a reasonable
+ manner on or through a medium customarily used for software
+ exchange.</FONT><FONT color=#0000ff size=2> </FONT><FONT color=#ff0000
+ size=2></FONT></UL>
+<UL><FONT color=#ff0000 size=2></FONT><FONT size=2></FONT></UL>
+<P><FONT size=2>When the Program is made available in source code form:</FONT>
+<UL><FONT size=2>a) it must be made available under this Agreement; and
+</FONT></UL>
+<UL><FONT size=2>b) a copy of this Agreement must be included with each copy
+ of the Program. </FONT></UL>
+<P><FONT size=2></FONT><FONT color=#0000ff size=2><STRIKE></STRIKE></FONT>
+<P><FONT color=#0000ff size=2><STRIKE></STRIKE></FONT><FONT size=2>Contributors
+may not remove or alter any copyright notices contained within the Program.
+</FONT>
+<P><FONT size=2></FONT>
+<P><FONT size=2>Each Contributor must identify itself as the originator of its
+Contribution, if any, in a manner that reasonably allows subsequent Recipients
+to identify the originator of the Contribution. </FONT>
+<P><FONT size=2></FONT>
+<P><FONT size=2><B>4. COMMERCIAL DISTRIBUTION</B></FONT>
+<P><FONT size=2>Commercial distributors of software may accept certain
+responsibilities with respect to end users, business partners and the like.
+While this license is intended to facilitate the commercial use of the Program,
+the Contributor who includes the Program in a commercial product offering should
+do so in a manner which does not create potential liability for other
+Contributors. Therefore, if a Contributor includes the Program in a commercial
+product offering, such Contributor ("Commercial Contributor") hereby agrees to
+defend and indemnify every other Contributor ("Indemnified Contributor") against
+any losses, damages and costs (collectively "Losses") arising from claims,
+lawsuits and other legal actions brought by a third party against the
+Indemnified Contributor to the extent caused by the acts or omissions of such
+Commercial Contributor in connection with its distribution of the Program in a
+commercial product offering. The obligations in this section do not apply to any
+claims or Losses relating to any actual or alleged intellectual property
+infringement. In order to qualify, an Indemnified Contributor must: a) promptly
+notify the Commercial Contributor in writing of such claim, and b) allow the
+Commercial Contributor to control, and cooperate with the Commercial Contributor
+in, the defense and any related settlement negotiations. The Indemnified
+Contributor may participate in any such claim at its own expense.</FONT>
+<P><FONT size=2></FONT>
+<P><FONT size=2>For example, a Contributor might include the Program in a
+commercial product offering, Product X. That Contributor is then a Commercial
+Contributor. If that Commercial Contributor then makes performance claims, or
+offers warranties related to Product X, those performance claims and warranties
+are such Commercial Contributor's responsibility alone. Under this section, the
+Commercial Contributor would have to defend claims against the other
+Contributors related to those performance claims and warranties, and if a court
+requires any other Contributor to pay any damages as a result, the Commercial
+Contributor must pay those damages.</FONT>
+<P><FONT size=2></FONT><FONT color=#0000ff size=2></FONT>
+<P><FONT color=#0000ff size=2></FONT><FONT size=2><B>5. NO WARRANTY</B></FONT>
+<P><FONT size=2>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
+PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR
+CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A
+PARTICULAR PURPOSE. Each Recipient is</FONT><FONT size=2> solely responsible for
+determining the appropriateness of using and distributing </FONT><FONT
+size=2>the Program</FONT><FONT size=2> and assumes all risks associated with its
+exercise of rights under this Agreement</FONT><FONT size=2>, including but not
+limited to the risks and costs of program errors, compliance with applicable
+laws, damage to or loss of data, </FONT><FONT size=2>programs or equipment, and
+unavailability or interruption of operations</FONT><FONT size=2>. </FONT><FONT
+size=2></FONT>
+<P><FONT size=2></FONT>
+<P><FONT size=2></FONT><FONT size=2><B>6. DISCLAIMER OF LIABILITY</B></FONT>
+<P><FONT size=2></FONT><FONT size=2>EXCEPT AS EXPRESSLY SET FORTH IN THIS
+AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+</FONT><FONT size=2>(INCLUDING WITHOUT LIMITATION LOST PROFITS),</FONT><FONT
+size=2> 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS
+GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</FONT>
+<P><FONT size=2></FONT><FONT size=2></FONT>
+<P><FONT size=2><B>7. GENERAL</B></FONT>
+<P><FONT size=2></FONT><FONT size=2>If any provision of this Agreement is
+invalid or unenforceable under applicable law, it shall not affect the validity
+or enforceability of the remainder of the terms of this Agreement, and without
+further action by the parties hereto, such provision shall be reformed to the
+minimum extent necessary to make such provision valid and enforceable.</FONT>
+<P><FONT size=2></FONT>
+<P><FONT size=2>If Recipient institutes patent litigation against a Contributor
+with respect to a patent applicable to software (including a cross-claim or
+counterclaim in a lawsuit), then any patent licenses granted by that Contributor
+to such Recipient under this Agreement shall terminate as of the date such
+litigation is filed. In addition, if Recipient institutes patent litigation
+against any entity (including a cross-claim or counterclaim in a lawsuit)
+alleging that the Program itself (excluding combinations of the Program with
+other software or hardware) infringes such Recipient's patent(s), then such
+Recipient's rights granted under Section 2(b) shall terminate as of the date
+such litigation is filed. </FONT><FONT size=2></FONT>
+<P><FONT size=2></FONT>
+<P><FONT size=2>All Recipient's rights under this Agreement shall terminate if
+it fails to comply with any of the material terms or conditions of this
+Agreement and does not cure such failure in a reasonable period of time after
+becoming aware of such noncompliance. If all Recipient's rights under this
+Agreement terminate, Recipient agrees to cease use and distribution of the
+Program as soon as reasonably practicable. However, Recipient's obligations
+under this Agreement and any licenses granted by Recipient relating to the
+Program shall continue and survive. </FONT><FONT size=2></FONT>
+<P><FONT size=2></FONT>
+<P><FONT size=2></FONT><FONT size=2>Everyone is permitted to copy and distribute
+copies of this Agreement, but in order to avoid inconsistency the Agreement is
+copyrighted and may only be modified in the following manner. The Agreement
+Steward reserves the right to </FONT><FONT size=2>publish new versions
+(including revisions) of this Agreement from time to </FONT><FONT size=2>time.
+No one other than the Agreement Steward has the right to modify this Agreement.
+IBM is the initial Agreement Steward. IBM may assign the responsibility to serve
+as the Agreement Steward to a suitable separate entity. </FONT><FONT size=2>Each
+new version of the Agreement will be given a distinguishing version number. The
+Program (including Contributions) may always be distributed subject to the
+version of the Agreement under which it was received. In addition, after a new
+version of the Agreement is published, Contributor may elect to distribute the
+Program (including its Contributions) under the new </FONT><FONT size=2>version.
+</FONT><FONT size=2>Except as expressly stated in Sections 2(a) and 2(b) above,
+Recipient receives no rights or licenses to the intellectual property of any
+Contributor under this Agreement, whether expressly, </FONT><FONT size=2>by
+implication, estoppel or otherwise</FONT><FONT size=2>.</FONT><FONT size=2> All
+rights in the Program not expressly granted under this Agreement are
+reserved.</FONT>
+<P><FONT size=2></FONT>
+<P><FONT size=2>This Agreement is governed by the laws of the State of New York
+and the intellectual property laws of the United States of America. No party to
+this Agreement will bring a legal action under this Agreement more than one year
+after the cause of action arose. Each party waives its rights to a jury trial in
+any resulting litigation.</FONT>
+<P><FONT size=2></FONT><FONT size=2></FONT>
+<P><FONT size=2></FONT></P></BODY></HTML>
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/LGPL.txt b/release/src/linux/linux/scripts/squashfs/lzma/LGPL.txt new file mode 100644 index 00000000..f3926a61 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/LGPL.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 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.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+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 and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, 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 library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete 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 distribute a copy of this License along with the
+Library.
+
+ 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 Library or any portion
+of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+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 Library, 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 Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you 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.
+
+ If distribution of 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 satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be 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.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library 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.
+
+ 9. 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 Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+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 with
+this License.
+
+ 11. 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 Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library 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 Library.
+
+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.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library 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.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser 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 Library
+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 Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+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
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. 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 LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; 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.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/Methods.txt b/release/src/linux/linux/scripts/squashfs/lzma/Methods.txt new file mode 100644 index 00000000..5d1661e4 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/Methods.txt @@ -0,0 +1,114 @@ +Compression method IDs (4.27)
+-----------------------------
+
+Each compression method in 7z has unique binary value (ID).
+The length of ID in bytes is arbitrary but it can not exceed 15 bytes.
+
+List of defined IDs
+-------------------
+
+00 - Copy
+01 - Reserved
+02 - Common
+ 03 Swap
+ - 2 Swap2
+ - 4 Swap4
+ 04 Delta (subject to change)
+
+03 - 7z
+ 01 - LZMA
+ 01 - Version
+
+ 03 - Branch
+ 01 - x86
+ 03 - BCJ
+ 1B - BCJ2
+ 02 - PPC
+ 05 - BC_PPC_B (Big Endian)
+ 03 - Alpha
+ 01 - BC_Alpha
+ 04 - IA64
+ 01 - BC_IA64
+ 05 - ARM
+ 01 - BC_ARM
+ 06 - M68
+ 05 - BC_M68_B (Big Endian)
+ 07 - ARM Thumb
+ 01 - BC_ARMThumb
+ 08 - SPARC
+ 05 - BC_SPARC
+
+ 04 - PPMD
+ 01 - Version
+
+04 - Misc
+ 00 - Reserved
+ 01 - Zip
+ 00 - Copy (not used). Use {00} instead
+ 01 - Shrink
+ 06 - Implode
+ 08 - Deflate
+ 09 - Deflate64
+ 12 - BZip2 (not used). Use {04 02 02} instead
+ 02 - BZip
+ 02 - BZip2
+ 03 - Rar
+ 01 - Rar15
+ 02 - Rar20
+ 03 - Rar29
+ 04 - Arj
+ 01 - Arj (1,2,3)
+ 02 - Arj 4
+ 05 - Z
+ 06 - Lzh
+ 07 - Reserved for 7z
+ 08 - Cab
+
+
+06 - Crypto
+ 00 -
+ 01 - AES
+ 0x - AES-128
+ 4x - AES-192
+ 8x - AES-256
+
+ x0 - ECB
+ x1 - CBC
+ x2 - CFB
+ x3 - OFB
+
+ 07 - Reserved
+ 0F - Reserved
+
+ F0 - Misc Ciphers (Real Ciphers without hashing algo)
+
+ F1 - Misc Ciphers (Combine)
+ 01 - Zip
+ 01 - Main Zip crypto algo
+ 03 - RAR
+ 02 -
+ 03 - Rar29 AES-128 + (modified SHA-1)
+ 07 - 7z
+ 01 - AES-256 + SHA-256
+
+07 - Hash (subject to change)
+ 00 -
+ 01 - CRC
+ 02 - SHA-1
+ 03 - SHA-256
+ 04 - SHA-384
+ 05 - SHA-512
+
+ F0 - Misc Hash
+
+ F1 - Misc
+ 03 - RAR
+ 03 - Rar29 Password Hashing (modified SHA1)
+ 07 - 7z
+ 01 - SHA-256 Password Hashing
+
+
+
+
+---
+End of document
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/history.txt b/release/src/linux/linux/scripts/squashfs/lzma/history.txt new file mode 100644 index 00000000..167fdf1e --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/history.txt @@ -0,0 +1,147 @@ +HISTORY of the LZMA SDK
+-----------------------
+
+ Version 4.32 2005-12-09
+ --------------------------------------
+ - Java version of LZMA SDK was included
+
+
+ Version 4.30 2005-11-20
+ --------------------------------------
+ - Compression ratio was improved in -a2 mode
+ - Speed optimizations for compressing in -a2 mode
+ - -fb switch now supports values up to 273
+ - Bug in 7z_C (7zIn.c) was fixed:
+ It used Alloc/Free functions from different memory pools.
+ So if program used two memory pools, it worked incorrectly.
+ - 7z_C: .7z format supporting was improved
+ - LZMA# SDK (C#.NET version) was included
+
+
+ Version 4.27 (Updated) 2005-09-21
+ --------------------------------------
+ - Some GUIDs/interfaces in C++ were changed.
+ IStream.h:
+ ISequentialInStream::Read now works as old ReadPart
+ ISequentialOutStream::Write now works as old WritePart
+
+
+ Version 4.27 2005-08-07
+ --------------------------------------
+ - Bug in LzmaDecodeSize.c was fixed:
+ if _LZMA_IN_CB and _LZMA_OUT_READ were defined,
+ decompressing worked incorrectly.
+
+
+ Version 4.26 2005-08-05
+ --------------------------------------
+ - Fixes in 7z_C code and LzmaTest.c:
+ previous versions could work incorrectly,
+ if malloc(0) returns 0
+
+
+ Version 4.23 2005-06-29
+ --------------------------------------
+ - Small fixes in C++ code
+
+
+ Version 4.22 2005-06-10
+ --------------------------------------
+ - Small fixes
+
+
+ Version 4.21 2005-06-08
+ --------------------------------------
+ - Interfaces for ANSI-C LZMA Decoder (LzmaDecode.c) were changed
+ - New additional version of ANSI-C LZMA Decoder with zlib-like interface:
+ - LzmaStateDecode.h
+ - LzmaStateDecode.c
+ - LzmaStateTest.c
+ - ANSI-C LZMA Decoder now can decompress files larger than 4 GB
+
+
+ Version 4.17 2005-04-18
+ --------------------------------------
+ - New example for RAM->RAM compressing/decompressing:
+ LZMA + BCJ (filter for x86 code):
+ - LzmaRam.h
+ - LzmaRam.cpp
+ - LzmaRamDecode.h
+ - LzmaRamDecode.c
+ - -f86 switch for lzma.exe
+
+
+ Version 4.16 2005-03-29
+ --------------------------------------
+ - Bug was fixed in LzmaDecode.c (ANSI-C LZMA Decoder):
+ If _LZMA_OUT_READ was defined, and if encoded stream was corrupted,
+ decoder could access memory outside of allocated range.
+ - Speed optimization of ANSI-C LZMA Decoder (now it's about 20% faster).
+ Old version of LZMA Decoder now is in file LzmaDecodeSize.c.
+ LzmaDecodeSize.c can provide slightly smaller code than LzmaDecode.c
+ - Small speed optimization in LZMA C++ code
+ - filter for SPARC's code was added
+ - Simplified version of .7z ANSI-C Decoder was included
+
+
+ Version 4.06 2004-09-05
+ --------------------------------------
+ - Bug in v4.05 was fixed:
+ LZMA-Encoder didn't release output stream in some cases.
+
+
+ Version 4.05 2004-08-25
+ --------------------------------------
+ - Source code of filters for x86, IA-64, ARM, ARM-Thumb
+ and PowerPC code was included to SDK
+ - Some internal minor changes
+
+
+ Version 4.04 2004-07-28
+ --------------------------------------
+ - More compatibility with some C++ compilers
+
+
+ Version 4.03 2004-06-18
+ --------------------------------------
+ - "Benchmark" command was added. It measures compressing
+ and decompressing speed and shows rating values.
+ Also it checks hardware errors.
+
+
+ Version 4.02 2004-06-10
+ --------------------------------------
+ - C++ LZMA Encoder/Decoder code now is more portable
+ and it can be compiled by GCC on Linux.
+
+
+ Version 4.01 2004-02-15
+ --------------------------------------
+ - Some detection of data corruption was enabled.
+ LzmaDecode.c / RangeDecoderReadByte
+ .....
+ {
+ rd->ExtraBytes = 1;
+ return 0xFF;
+ }
+
+
+ Version 4.00 2004-02-13
+ --------------------------------------
+ - Original version of LZMA SDK
+
+
+
+HISTORY of the LZMA
+-------------------
+ 2001-2004: Improvements to LZMA compressing/decompressing code,
+ keeping compatibility with original LZMA format
+ 1996-2001: Development of LZMA compression format
+
+ Some milestones:
+
+ 2001-08-30: LZMA compression was added to 7-Zip
+ 1999-01-02: First version of 7-Zip was released
+
+
+End of document
diff --git a/release/src/linux/linux/scripts/squashfs/lzma/lzma.txt b/release/src/linux/linux/scripts/squashfs/lzma/lzma.txt new file mode 100644 index 00000000..8b5825fb --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/lzma/lzma.txt @@ -0,0 +1,637 @@ +LZMA SDK 4.32
+-------------
+
+LZMA SDK 4.32 Copyright (C) 1999-2005 Igor Pavlov
+
+LZMA SDK provides the documentation, samples, header files, libraries,
+and tools you need to develop applications that use LZMA compression.
+
+LZMA is default and general compression method of 7z format
+in 7-Zip compression program (www.7-zip.org). LZMA provides high
+compression ratio and very fast decompression.
+
+LZMA is an improved version of famous LZ77 compression algorithm.
+It was improved in way of maximum increasing of compression ratio,
+keeping high decompression speed and low memory requirements for
+decompressing.
+
+
+
+LICENSE
+-------
+
+LZMA SDK is available under any of the following licenses:
+
+1) GNU Lesser General Public License (GNU LGPL)
+2) Common Public License (CPL)
+3) Simplified license for unmodified code (read SPECIAL EXCEPTION)
+4) Proprietary license
+
+It means that you can select one of these four options and follow rules of that license.
+
+
+1,2) GNU LGPL and CPL licenses are pretty similar and both these
+licenses are classified as
+ - "Free software licenses" at http://www.gnu.org/
+ - "OSI-approved" at http://www.opensource.org/
+
+
+3) SPECIAL EXCEPTION
+
+Igor Pavlov, as the author of this code, expressly permits you
+to statically or dynamically link your code (or bind by name)
+to the files from LZMA SDK without subjecting your linked
+code to the terms of the CPL or GNU LGPL.
+Any modifications or additions to files from LZMA SDK, however,
+are subject to the GNU LGPL or CPL terms.
+
+SPECIAL EXCEPTION allows you to use LZMA SDK in applications with closed code,
+while you keep LZMA SDK code unmodified.
+
+
+SPECIAL EXCEPTION #2: Igor Pavlov, as the author of this code, expressly permits
+you to use this code under the same terms and conditions contained in the License
+Agreement you have for any previous version of LZMA SDK developed by Igor Pavlov.
+
+SPECIAL EXCEPTION #2 allows owners of proprietary licenses to use latest version
+of LZMA SDK as update for previous versions.
+
+
+SPECIAL EXCEPTION #3: Igor Pavlov, as the author of this code, expressly permits
+you to use code of examples (LzmaTest.c, LzmaStateTest.c, LzmaAlone.cpp,
+LzmaAlone.cs, LzmaAlone.java) as public domain code.
+
+
+4) Proprietary license
+
+LZMA SDK also can be available under a proprietary license which
+can include:
+
+1) Right to modify code without subjecting modified code to the
+terms of the CPL or GNU LGPL
+2) Technical support for code
+
+To request such proprietary license or any additional consultations,
+send email message from that page:
+http://www.7-zip.org/support.html
+
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You should have received a copy of the Common Public License
+along with this library.
+
+
+LZMA SDK Contents
+-----------------
+
+LZMA SDK includes:
+
+ - C++ source code of LZMA compressing and decompressing
+ - ANSI-C compatible source code for LZMA decompressing
+ - C# source code for LZMA compressing and decompressing
+ - Java source code for LZMA compressing and decompressing
+ - Compiled file->file LZMA compressing/decompressing program for Windows system
+
+ANSI-C LZMA decompression code was ported from original C++ sources to C.
+Also it was simplified and optimized for code size.
+But it is fully compatible with LZMA from 7-Zip.
+
+
+UNIX/Linux version
+------------------
+To compile C++ version of file->file LZMA, go to directory
+C/7zip/Compress/LZMA_Alone
+and type "make" or "make clean all" to recompile all.
+
+In some UNIX/Linux versions you must compile LZMA with static libraries.
+To compile with static libraries, change string in makefile
+LIB = -lm
+to string
+LIB = -lm -static
+
+
+Files
+---------------------
+C - C / CPP source code
+CS - C# source code
+Java - Java source code
+lzma.txt - LZMA SDK description (this file)
+7zFormat.txt - 7z Format description
+7zC.txt - 7z ANSI-C Decoder description (this file)
+methods.txt - Compression method IDs for .7z
+LGPL.txt - GNU Lesser General Public License
+CPL.html - Common Public License
+lzma.exe - Compiled file->file LZMA encoder/decoder for Windows
+history.txt - history of the LZMA SDK
+
+
+Source code structure
+---------------------
+
+C - C / CPP files
+ Common - common files for C++ projects
+ Windows - common files for Windows related code
+ 7zip - files related to 7-Zip Project
+ Common - common files for 7-Zip
+ Compress - files related to compression/decompression
+ LZ - files related to LZ (Lempel-Ziv) compression algorithm
+ BinTree - Binary Tree Match Finder for LZ algorithm
+ HashChain - Hash Chain Match Finder for LZ algorithm
+ Patricia - Patricia Match Finder for LZ algorithm
+ RangeCoder - Range Coder (special code of compression/decompression)
+ LZMA - LZMA compression/decompression on C++
+ LZMA_Alone - file->file LZMA compression/decompression
+ LZMA_C - ANSI-C compatible LZMA decompressor
+ LzmaDecode.h - interface for LZMA decoding on ANSI-C
+ LzmaDecode.c - LZMA decoding on ANSI-C (new fastest version)
+ LzmaDecodeSize.c - LZMA decoding on ANSI-C (old size-optimized version)
+ LzmaTest.c - test application that decodes LZMA encoded file
+ LzmaStateDecode.h - interface for LZMA decoding (State version)
+ LzmaStateDecode.c - LZMA decoding on ANSI-C (State version)
+ LzmaStateTest.c - test application (State version)
+ Branch - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code
+ Archive - files related to archiving
+ 7z_C - 7z ANSI-C Decoder
+
+CS - C# files
+ 7zip
+ Common - some common files for 7-Zip
+ Compress - files related to compression/decompression
+ LZ - files related to LZ (Lempel-Ziv) compression algorithm
+ LZMA - LZMA compression/decompression
+ LzmaAlone - file->file LZMA compression/decompression
+ RangeCoder - Range Coder (special code of compression/decompression)
+
+Java - Java files
+ SevenZip
+ Compression - files related to compression/decompression
+ LZ - files related to LZ (Lempel-Ziv) compression algorithm
+ LZMA - LZMA compression/decompression
+ RangeCoder - Range Coder (special code of compression/decompression)
+
+C/C++ source code of LZMA SDK is part of 7-Zip project.
+
+You can find ANSI-C LZMA decompressing code at folder
+ C/7zip/Compress/LZMA_C
+7-Zip doesn't use that ANSI-C LZMA code and that code was developed
+specially for this SDK. And files from LZMA_C do not need files from
+other directories of SDK for compiling.
+
+7-Zip source code can be downloaded from 7-Zip's SourceForge page:
+
+ http://sourceforge.net/projects/sevenzip/
+
+
+LZMA Decompression features
+---------------------------
+ - Variable dictionary size (up to 256 MB)
+ - Estimated compressing speed: about 500 KB/s on 1 GHz CPU
+ - Estimated decompressing speed:
+ - 8-12 MB/s on 1 GHz Intel Pentium 3 or AMD Athlon
+ - 500-1000 KB/s on 100 MHz ARM, MIPS, PowerPC or other simple RISC
+ - Small memory requirements for decompressing (8-32 KB + DictionarySize)
+ - Small code size for decompressing: 2-8 KB (depending from
+ speed optimizations)
+
+LZMA decoder uses only integer operations and can be
+implemented in any modern 32-bit CPU (or on 16-bit CPU with some conditions).
+
+Some critical operations that affect to speed of LZMA decompression:
+ 1) 32*16 bit integer multiply
+ 2) Misspredicted branches (penalty mostly depends from pipeline length)
+ 3) 32-bit shift and arithmetic operations
+
+Speed of LZMA decompressing mostly depends from CPU speed.
+Memory speed has no big meaning. But if your CPU has small data cache,
+overall weight of memory speed will slightly increase.
+
+
+How To Use
+----------
+
+Using LZMA encoder/decoder executable
+--------------------------------------
+
+Usage: LZMA <e|d> inputFile outputFile [<switches>...]
+
+ e: encode file
+
+ d: decode file
+
+ b: Benchmark. There are two tests: compressing and decompressing
+ with LZMA method. Benchmark shows rating in MIPS (million
+ instructions per second). Rating value is calculated from
+ measured speed and it is normalized with AMD Athlon XP CPU
+ results. Also Benchmark checks possible hardware errors (RAM
+ errors in most cases). Benchmark uses these settings:
+ (-a1, -d21, -fb32, -mfbt4). You can change only -d. Also you
+ can change number of iterations. Example for 30 iterations:
+ LZMA b 30
+ Default number of iterations is 10.
+
+<Switches>
+
+
+ -a{N}: set compression mode 0 = fast, 1 = normal, 2 = max
+ default: 2 (max)
+
+ d{N}: Sets Dictionary size - [0, 28], default: 23 (8MB)
+ The maximum value for dictionary size is 256 MB = 2^28 bytes.
+ Dictionary size is calculated as DictionarySize = 2^N bytes.
+ For decompressing file compressed by LZMA method with dictionary
+ size D = 2^N you need about D bytes of memory (RAM).
+
+ -fb{N}: set number of fast bytes - [5, 273], default: 128
+ Usually big number gives a little bit better compression ratio
+ and slower compression process.
+
+ -lc{N}: set number of literal context bits - [0, 8], default: 3
+ Sometimes lc=4 gives gain for big files.
+
+ -lp{N}: set number of literal pos bits - [0, 4], default: 0
+ lp switch is intended for periodical data when period is
+ equal 2^N. For example, for 32-bit (4 bytes)
+ periodical data you can use lp=2. Often it's better to set lc0,
+ if you change lp switch.
+
+ -pb{N}: set number of pos bits - [0, 4], default: 2
+ pb switch is intended for periodical data
+ when period is equal 2^N.
+
+ -mf{MF_ID}: set Match Finder. Default: bt4.
+ Compression ratio for all bt* and pat* almost the same.
+ Algorithms from hc* group doesn't provide good compression
+ ratio, but they often works pretty fast in combination with
+ fast mode (-a0). Methods from bt* group require less memory
+ than methods from pat* group. Usually bt4 works faster than
+ any pat*, but for some types of files pat* can work faster.
+
+ Memory requirements depend from dictionary size
+ (parameter "d" in table below).
+
+ MF_ID Memory Description
+
+ bt2 d*9.5 + 1MB Binary Tree with 2 bytes hashing.
+ bt3 d*9.5 + 65MB Binary Tree with 2-3(full) bytes hashing.
+ bt4 d*9.5 + 6MB Binary Tree with 2-3-4 bytes hashing.
+ bt4b d*9.5 + 34MB Binary Tree with 2-3-4(big) bytes hashing.
+ pat2r d*26 + 1MB Patricia Tree with 2-bits nodes, removing.
+ pat2 d*38 + 1MB Patricia Tree with 2-bits nodes.
+ pat2h d*38 + 77MB Patricia Tree with 2-bits nodes, 2-3 bytes hashing.
+ pat3h d*62 + 85MB Patricia Tree with 3-bits nodes, 2-3 bytes hashing.
+ pat4h d*110 +101MB Patricia Tree with 4-bits nodes, 2-3 bytes hashing.
+ hc3 d*5.5 + 1MB Hash Chain with 2-3 bytes hashing.
+ hc4 d*5.5 + 6MB Hash Chain with 2-3-4 bytes hashing.
+
+ -eos: write End Of Stream marker. By default LZMA doesn't write
+ eos marker, since LZMA decoder knows uncompressed size
+ stored in .lzma file header.
+
+ -si: Read data from stdin (it will write End Of Stream marker).
+ -so: Write data to stdout
+
+
+Examples:
+
+1) LZMA e file.bin file.lzma -d16 -lc0
+
+compresses file.bin to file.lzma with 64 KB dictionary (2^16=64K)
+and 0 literal context bits. -lc0 allows to reduce memory requirements
+for decompression.
+
+
+2) LZMA e file.bin file.lzma -lc0 -lp2
+
+compresses file.bin to file.lzma with settings suitable
+for 32-bit periodical data (for example, ARM or MIPS code).
+
+3) LZMA d file.lzma file.bin
+
+decompresses file.lzma to file.bin.
+
+
+Compression ratio hints
+-----------------------
+
+Recommendations
+---------------
+
+To increase compression ratio for LZMA compressing it's desirable
+to have aligned data (if it's possible) and also it's desirable to locate
+data in such order, where code is grouped in one place and data is
+grouped in other place (it's better than such mixing: code, data, code,
+data, ...).
+
+
+Using Filters
+-------------
+You can increase compression ratio for some data types, using
+special filters before compressing. For example, it's possible to
+increase compression ratio on 5-10% for code for those CPU ISAs:
+x86, IA-64, ARM, ARM-Thumb, PowerPC, SPARC.
+
+You can find C/C++ source code of such filters in folder "7zip/Compress/Branch"
+
+You can check compression ratio gain of these filters with such
+7-Zip commands (example for ARM code):
+No filter:
+ 7z a a1.7z a.bin -m0=lzma
+
+With filter for little-endian ARM code:
+ 7z a a2.7z a.bin -m0=bc_arm -m1=lzma
+
+With filter for big-endian ARM code (using additional Swap4 filter):
+ 7z a a3.7z a.bin -m0=swap4 -m1=bc_arm -m2=lzma
+
+It works in such manner:
+Compressing = Filter_encoding + LZMA_encoding
+Decompressing = LZMA_decoding + Filter_decoding
+
+Compressing and decompressing speed of such filters is very high,
+so it will not increase decompressing time too much.
+Moreover, it reduces decompression time for LZMA_decoding,
+since compression ratio with filtering is higher.
+
+These filters convert CALL (calling procedure) instructions
+from relative offsets to absolute addresses, so such data becomes more
+compressible. Source code of these CALL filters is pretty simple
+(about 20 lines of C++), so you can convert it from C++ version yourself.
+
+For some ISAs (for example, for MIPS) it's impossible to get gain from such filter.
+
+
+LZMA compressed file format
+---------------------------
+Offset Size Description
+ 0 1 Special LZMA properties for compressed data
+ 1 4 Dictionary size (little endian)
+ 5 8 Uncompressed size (little endian). -1 means unknown size
+ 13 Compressed data
+
+
+ANSI-C LZMA Decoder
+~~~~~~~~~~~~~~~~~~~
+
+To compile ANSI-C LZMA Decoder you can use one of the following files sets:
+1) LzmaDecode.h + LzmaDecode.c + LzmaTest.c (fastest version)
+2) LzmaDecode.h + LzmaDecodeSize.c + LzmaTest.c (old size-optimized version)
+3) LzmaStateDecode.h + LzmaStateDecode.c + LzmaStateTest.c (zlib-like interface)
+
+
+Memory requirements for LZMA decoding
+-------------------------------------
+
+LZMA decoder doesn't allocate memory itself, so you must
+allocate memory and send it to LZMA.
+
+Stack usage of LZMA decoding function for local variables is not
+larger than 200 bytes.
+
+How To decompress data
+----------------------
+
+LZMA Decoder (ANSI-C version) now supports 5 interfaces:
+1) Single-call Decompressing
+2) Single-call Decompressing with input stream callback
+3) Multi-call Decompressing with output buffer
+4) Multi-call Decompressing with input callback and output buffer
+5) Multi-call State Decompressing (zlib-like interface)
+
+Variant-5 is similar to Variant-4, but Variant-5 doesn't use callback functions.
+
+Decompressing steps
+-------------------
+
+1) read LZMA properties (5 bytes):
+ unsigned char properties[LZMA_PROPERTIES_SIZE];
+
+2) read uncompressed size (8 bytes, little-endian)
+
+3) Decode properties:
+
+ CLzmaDecoderState state; /* it's 24-140 bytes structure, if int is 32-bit */
+
+ if (LzmaDecodeProperties(&state.Properties, properties, LZMA_PROPERTIES_SIZE) != LZMA_RESULT_OK)
+ return PrintError(rs, "Incorrect stream properties");
+
+4) Allocate memory block for internal Structures:
+
+ state.Probs = (CProb *)malloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
+ if (state.Probs == 0)
+ return PrintError(rs, kCantAllocateMessage);
+
+ LZMA decoder uses array of CProb variables as internal structure.
+ By default, CProb is unsigned_short. But you can define _LZMA_PROB32 to make
+ it unsigned_int. It can increase speed on some 32-bit CPUs, but memory
+ usage will be doubled in that case.
+
+
+5) Main Decompressing
+
+You must use one of the following interfaces:
+
+5.1 Single-call Decompressing
+-----------------------------
+When to use: RAM->RAM decompressing
+Compile files: LzmaDecode.h, LzmaDecode.c
+Compile defines: no defines
+Memory Requirements:
+ - Input buffer: compressed size
+ - Output buffer: uncompressed size
+ - LZMA Internal Structures (~16 KB for default settings)
+
+Interface:
+ int res = LzmaDecode(&state,
+ inStream, compressedSize, &inProcessed,
+ outStream, outSize, &outProcessed);
+
+
+5.2 Single-call Decompressing with input stream callback
+--------------------------------------------------------
+When to use: File->RAM or Flash->RAM decompressing.
+Compile files: LzmaDecode.h, LzmaDecode.c
+Compile defines: _LZMA_IN_CB
+Memory Requirements:
+ - Buffer for input stream: any size (for example, 16 KB)
+ - Output buffer: uncompressed size
+ - LZMA Internal Structures (~16 KB for default settings)
+
+Interface:
+ typedef struct _CBuffer
+ {
+ ILzmaInCallback InCallback;
+ FILE *File;
+ unsigned char Buffer[kInBufferSize];
+ } CBuffer;
+
+ int LzmaReadCompressed(void *object, const unsigned char **buffer, SizeT *size)
+ {
+ CBuffer *bo = (CBuffer *)object;
+ *buffer = bo->Buffer;
+ *size = MyReadFile(bo->File, bo->Buffer, kInBufferSize);
+ return LZMA_RESULT_OK;
+ }
+
+ CBuffer g_InBuffer;
+
+ g_InBuffer.File = inFile;
+ g_InBuffer.InCallback.Read = LzmaReadCompressed;
+ int res = LzmaDecode(&state,
+ &g_InBuffer.InCallback,
+ outStream, outSize, &outProcessed);
+
+
+5.3 Multi-call decompressing with output buffer
+-----------------------------------------------
+When to use: RAM->File decompressing
+Compile files: LzmaDecode.h, LzmaDecode.c
+Compile defines: _LZMA_OUT_READ
+Memory Requirements:
+ - Input buffer: compressed size
+ - Buffer for output stream: any size (for example, 16 KB)
+ - LZMA Internal Structures (~16 KB for default settings)
+ - LZMA dictionary (dictionary size is encoded in stream properties)
+
+Interface:
+
+ state.Dictionary = (unsigned char *)malloc(state.Properties.DictionarySize);
+
+ LzmaDecoderInit(&state);
+ do
+ {
+ LzmaDecode(&state,
+ inBuffer, inAvail, &inProcessed,
+ g_OutBuffer, outAvail, &outProcessed);
+ inAvail -= inProcessed;
+ inBuffer += inProcessed;
+ }
+ while you need more bytes
+
+ see LzmaTest.c for more details.
+
+
+5.4 Multi-call decompressing with input callback and output buffer
+------------------------------------------------------------------
+When to use: File->File decompressing
+Compile files: LzmaDecode.h, LzmaDecode.c
+Compile defines: _LZMA_IN_CB, _LZMA_OUT_READ
+Memory Requirements:
+ - Buffer for input stream: any size (for example, 16 KB)
+ - Buffer for output stream: any size (for example, 16 KB)
+ - LZMA Internal Structures (~16 KB for default settings)
+ - LZMA dictionary (dictionary size is encoded in stream properties)
+
+Interface:
+
+ state.Dictionary = (unsigned char *)malloc(state.Properties.DictionarySize);
+
+ LzmaDecoderInit(&state);
+ do
+ {
+ LzmaDecode(&state,
+ &bo.InCallback,
+ g_OutBuffer, outAvail, &outProcessed);
+ }
+ while you need more bytes
+
+ see LzmaTest.c for more details:
+
+
+5.5 Multi-call State Decompressing (zlib-like interface)
+------------------------------------------------------------------
+When to use: file->file decompressing
+Compile files: LzmaStateDecode.h, LzmaStateDecode.c
+Compile defines:
+Memory Requirements:
+ - Buffer for input stream: any size (for example, 16 KB)
+ - Buffer for output stream: any size (for example, 16 KB)
+ - LZMA Internal Structures (~16 KB for default settings)
+ - LZMA dictionary (dictionary size is encoded in stream properties)
+
+Interface:
+
+ state.Dictionary = (unsigned char *)malloc(state.Properties.DictionarySize);
+
+
+ LzmaDecoderInit(&state);
+ do
+ {
+ res = LzmaDecode(&state,
+ inBuffer, inAvail, &inProcessed,
+ g_OutBuffer, outAvail, &outProcessed,
+ finishDecoding);
+ inAvail -= inProcessed;
+ inBuffer += inProcessed;
+ }
+ while you need more bytes
+
+ see LzmaStateTest.c for more details:
+
+
+6) Free all allocated blocks
+
+
+Note
+----
+LzmaDecodeSize.c is size-optimized version of LzmaDecode.c.
+But compiled code of LzmaDecodeSize.c can be larger than
+compiled code of LzmaDecode.c. So it's better to use
+LzmaDecode.c in most cases.
+
+
+EXIT codes
+-----------
+
+LZMA decoder can return one of the following codes:
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+
+If you use callback function for input data and you return some
+error code, LZMA Decoder also returns that code.
+
+
+
+LZMA Defines
+------------
+
+_LZMA_IN_CB - Use callback for input data
+
+_LZMA_OUT_READ - Use read function for output data
+
+_LZMA_LOC_OPT - Enable local speed optimizations inside code.
+ _LZMA_LOC_OPT is only for LzmaDecodeSize.c (size-optimized version).
+ _LZMA_LOC_OPT doesn't affect LzmaDecode.c (speed-optimized version)
+ and LzmaStateDecode.c
+
+_LZMA_PROB32 - It can increase speed on some 32-bit CPUs,
+ but memory usage will be doubled in that case
+
+_LZMA_UINT32_IS_ULONG - Define it if int is 16-bit on your compiler
+ and long is 32-bit.
+
+_LZMA_SYSTEM_SIZE_T - Define it if you want to use system's size_t.
+ You can use it to enable 64-bit sizes supporting
+
+
+
+C++ LZMA Encoder/Decoder
+~~~~~~~~~~~~~~~~~~~~~~~~
+C++ LZMA code use COM-like interfaces. So if you want to use it,
+you can study basics of COM/OLE.
+
+By default, LZMA Encoder contains all Match Finders.
+But for compressing it's enough to have just one of them.
+So for reducing size of compressing code you can define:
+ #define COMPRESS_MF_BT
+ #define COMPRESS_MF_BT4
+and it will use only bt4 match finder.
+
+
+---
+
+http://www.7-zip.org
+http://www.7-zip.org/support.html
diff --git a/release/src/linux/linux/scripts/squashfs/mksquashfs.c b/release/src/linux/linux/scripts/squashfs/mksquashfs.c index fbe25e6d..e773f53c 100644 --- a/release/src/linux/linux/scripts/squashfs/mksquashfs.c +++ b/release/src/linux/linux/scripts/squashfs/mksquashfs.c @@ -1,7 +1,8 @@ /* * Create a squashfs filesystem. This is a highly compressed read only filesystem. * - * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.net> + * Copyright (c) 2002, 2003, 2004, 2005, 2006 + * Phillip Lougher <phillip@lougher.org.uk> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,7 +21,9 @@ * mksquashfs.c */ +#define FALSE 0 #define TRUE 1 + #include <pwd.h> #include <grp.h> #include <time.h> @@ -33,44 +36,70 @@ #include <dirent.h> #include <string.h> #include <zlib.h> -#include <endian.h> #include <stdlib.h> #include <signal.h> #include <setjmp.h> #include <sys/mman.h> -#include "mksquashfs.h" +#ifndef linux +#define __BYTE_ORDER BYTE_ORDER +#define __BIG_ENDIAN BIG_ENDIAN +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#else +#include <endian.h> +#endif + #include <squashfs_fs.h> +#include "mksquashfs.h" +#include "global.h" +#include "sort.h" #ifdef SQUASHFS_TRACE -#define TRACE(s, args...) printf("mksquashfs: "s, ## args) +#define TRACE(s, args...) do { \ + printf("mksquashfs: "s, ## args); \ + } while(0) #else #define TRACE(s, args...) #endif -#define INFO(s, args...) do { if(!silent) printf("mksquashfs: "s, ## args); } while(0) -#define ERROR(s, args...) do { fprintf(stderr, s, ## args); } while(0) -#define EXIT_MKSQUASHFS() do { if(restore)\ - restorefs();\ - exit(1); } while(0) -#define BAD_ERROR(s, args...) do {\ +#define INFO(s, args...) do {\ + if(!silent)\ + printf("mksquashfs: "s, ## args);\ + } while(0) +#define ERROR(s, args...) do {\ + fprintf(stderr, s, ## args);\ + } while(0) +#define EXIT_MKSQUASHFS() do {\ + if(restore)\ + restorefs();\ + if(delete && destination_file && !block_device)\ + unlink(destination_file);\ + exit(1);\ + } while(0) +#define BAD_ERROR(s, args...) do {\ fprintf(stderr, "FATAL ERROR:" s, ##args);\ EXIT_MKSQUASHFS();\ - } while(0) - -int duplicate_checking = 1, noF = 0, no_fragments = 0, always_use_fragments = 0; -int total_compressed = 0, total_uncompressed = 0; + } while(0) +int delete = FALSE; +long long total_compressed = 0, total_uncompressed = 0; int fd; +/* filesystem flags for building */ +int duplicate_checking = 1, noF = 0, no_fragments = 0, always_use_fragments = 0; +int noI = 0, noD = 0, check_data = 0; +int swap, silent = TRUE; +long long global_uid = -1, global_gid = -1; + /* superblock attributes */ -int noI = 0, noD = 0, check_data = 0, block_size = SQUASHFS_FILE_SIZE, block_log; +int block_size = SQUASHFS_FILE_SIZE, block_log; unsigned short uid_count = 0, guid_count = 0; squashfs_uid uids[SQUASHFS_UIDS], guids[SQUASHFS_GUIDS]; int block_offset; +int file_count = 0, sym_count = 0, dev_count = 0, dir_count = 0, fifo_count = 0, sock_count = 0; /* write position within data section */ -unsigned int bytes = 0, total_bytes = 0; +long long bytes = 0, total_bytes = 0; /* in memory directory table - possibly compressed */ char *directory_table = NULL; @@ -88,22 +117,38 @@ unsigned int inode_bytes = 0, inode_size = 0, total_inode_bytes = 0; char *data_cache = NULL; unsigned int cache_bytes = 0, cache_size = 0, inode_count = 0; -/* in memory directory header */ +/* in memory directory data */ +#define I_COUNT_SIZE 128 +#define DIR_ENTRIES 32 +#define INODE_HASH_SIZE 65536 +#define INODE_HASH_MASK (INODE_HASH_SIZE - 1) +#define INODE_HASH(dev, ino) (ino & INODE_HASH_MASK) + +struct cached_dir_index { + squashfs_dir_index index; + char *name; +}; + struct directory { unsigned int start_block; unsigned int size; unsigned char *buff; unsigned char *p; unsigned int entry_count; - squashfs_dir_header *entry_count_p; + unsigned char *entry_count_p; + unsigned int i_count; + unsigned int i_size; + struct cached_dir_index *index; + unsigned char *index_count_p; + unsigned int inode_number; }; +struct inode_info *inode_info[INODE_HASH_SIZE]; + +/* hash tables used to do fast duplicate searches in duplicate check */ struct file_info *dupl[65536], *frag_dups[65536]; int dup_files = 0; -int swap, silent = TRUE; -int file_count = 0, sym_count = 0, dev_count = 0, dir_count = 0, fifo_count = 0, sock_count = 0; - /* list of exclude dirs/files */ struct exclude_info { dev_t st_dev; @@ -117,18 +162,22 @@ int excluded(char *filename, struct stat *buf); /* fragment block data structures */ int fragments = 0; -static char *fragment_data; -static int fragment_size = 0; +char fragment_data[SQUASHFS_FILE_SIZE]; +int fragment_size = 0; struct fragment { unsigned int index; int offset; int size; }; - - #define FRAG_SIZE 32768 squashfs_fragment_entry *fragment_table = NULL; + +/* current inode number for directories and non directories */ +unsigned int dir_inode_no = 1; +unsigned int inode_no = 0; +unsigned int root_inode_number = 0; + /* list of source dirs/files */ int source = 0; char **source_path; @@ -139,13 +188,15 @@ struct old_root_entry_info { char name[SQUASHFS_NAME_LEN + 1]; squashfs_inode inode; int type; + int inode_number; }; +struct old_root_entry_info *old_root_entry; /* in memory file info */ struct file_info { - unsigned int bytes; + long long bytes; unsigned short checksum; - unsigned int start; + long long start; unsigned int *block_list; struct file_info *next; struct fragment *fragment; @@ -158,46 +209,51 @@ int interrupted = 0; /* restore orignal filesystem state if appending to existing filesystem is cancelled */ jmp_buf env; char *sdata_cache, *sdirectory_data_cache; -unsigned int sbytes, sinode_bytes, scache_bytes, sdirectory_bytes, + +long long sbytes, stotal_bytes; + +unsigned int sinode_bytes, scache_bytes, sdirectory_bytes, sdirectory_cache_bytes, suid_count, sguid_count, - stotal_bytes, stotal_inode_bytes, stotal_directory_bytes, + stotal_inode_bytes, stotal_directory_bytes, sinode_count, sfile_count, ssym_count, sdev_count, - sdir_count, sdup_files; + sdir_count, sfifo_count, ssock_count, sdup_files; int sfragments; int restore = 0; -/*flag whether destination file is a block device */ +/* flag whether destination file is a block device */ int block_device = 0; /* flag indicating whether files are sorted using sort list(s) */ int sorted = 0; -long long global_uid = -1, global_gid = -1; +/* save destination file name for deleting on error */ +char *destination_file = NULL; /* structure to used to pass in a pointer or an integer * to duplicate buffer read helper functions. */ struct duplicate_buffer_handle { - unsigned char *ptr; - unsigned int start; + char *ptr; + long long start; }; -struct old_root_entry_info *old_root_entry; -void add_old_root_entry(char *name, squashfs_inode inode, int type); +void add_old_root_entry(char *name, squashfs_inode inode, int inode_number, int type); extern int read_super(int fd, squashfs_super_block *sBlk, int *be, char *source); -extern int read_filesystem(char *root_name, int fd, squashfs_super_block *sBlk, char **inode_table, int *inode_bytes, - char **data_cache, int *cache_bytes, int *cache_size, char **directory_table, int *directory_bytes, - char **directory_data_cache, int *directory_cache_bytes, int *directory_cache_size, - int *file_count, int *sym_count, int *dev_count, int *dir_count, int *fifo_count, int *sock_count, - squashfs_uid *uids, unsigned short *uid_count, squashfs_uid *guids, unsigned short *guid_count, - unsigned int *uncompressed_file, unsigned int *uncompressed_inode, unsigned int *uncompressed_directory, - void (push_directory_entry)(char *, squashfs_inode, int), squashfs_fragment_entry **fragment_table); -squashfs_inode get_sorted_inode(struct stat *buf); +extern long long read_filesystem(char *root_name, int fd, squashfs_super_block *sBlk, char **cinode_table, + char **data_cache, char **cdirectory_table, char **directory_data_cache, + unsigned int *last_directory_block, unsigned int *inode_dir_offset, unsigned int *inode_dir_file_size, + unsigned int *root_inode_size, unsigned int *inode_dir_start_block, int *file_count, int *sym_count, + int *dev_count, int *dir_count, int *fifo_count, int *sock_count, squashfs_uid *uids, + unsigned short *uid_count, squashfs_uid *guids, unsigned short *guid_count, + long long *uncompressed_file, unsigned int *uncompressed_inode, unsigned int *uncompressed_directory, + unsigned int *inode_dir_inode_number, unsigned int *inode_dir_parent_inode, + void (push_directory_entry)(char *, squashfs_inode, int, int), + squashfs_fragment_entry **fragment_table); +int get_sorted_inode(squashfs_inode *inode, struct stat *buf); int read_sort_file(char *filename, int source, char *source_path[]); -void sort_files_and_write(int source, char *source_path[]); -struct file_info *duplicate(unsigned char *(get_next_file_block)(struct duplicate_buffer_handle *, unsigned int), struct duplicate_buffer_handle *file_start, int bytes, unsigned int **block_list, int *start, int blocks, struct fragment **fragment, char *frag_data, int frag_bytes); - -#define FALSE 0 +void sort_files_and_write(struct dir_info *dir); +struct file_info *duplicate(char *(get_next_file_block)(struct duplicate_buffer_handle *, unsigned int), struct duplicate_buffer_handle *file_start, long long bytes, unsigned int **block_list, long long *start, int blocks, struct fragment **fragment, char *frag_data, int frag_bytes); +struct dir_info *dir_scan1(char *, int (_readdir)(char *, char *, struct dir_info *)); #define MKINODE(A) ((squashfs_inode)(((squashfs_inode) inode_bytes << 16) + (((char *)A) - data_cache))) @@ -220,6 +276,8 @@ void restorefs() sym_count = ssym_count; dev_count = sdev_count; dir_count = sdir_count; + fifo_count = sfifo_count; + sock_count = ssock_count; dup_files = sdup_files; fragments = sfragments; fragment_size = 0; @@ -239,12 +297,18 @@ void sighandler() } +void sighandler2() +{ + EXIT_MKSQUASHFS(); +} + + unsigned int mangle(char *d, char *s, int size, int block_size, int uncompressed, int data_block) { unsigned long c_byte = block_size << 1; unsigned int res; - if(!uncompressed && (res = compress2(d, &c_byte, s, size, 9)) != Z_OK) { + if(!uncompressed && (res = compress2((unsigned char *) d, &c_byte, (unsigned char *) s, size, 9)) != Z_OK) { if(res == Z_MEM_ERROR) BAD_ERROR("zlib::compress failed, not enough memory\n"); else if(res == Z_BUF_ERROR) @@ -281,7 +345,7 @@ squashfs_base_inode_header *get_inode(int req_size) SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE, noI, 0); TRACE("Inode block @ %x, size %d\n", inode_bytes, c_byte); if(!swap) - memcpy((void *) (inode_table + inode_bytes), (void *) &c_byte, sizeof(unsigned short)); + memcpy(inode_table + inode_bytes, &c_byte, sizeof(unsigned short)); else SQUASHFS_SWAP_SHORTS((&c_byte), (inode_table + inode_bytes), 1); if(check_data) @@ -311,7 +375,7 @@ failed: } -void read_bytes(int fd, unsigned int byte, int bytes, char *buff) +void read_bytes(int fd, long long byte, int bytes, char *buff) { off_t off = byte; @@ -327,13 +391,10 @@ void read_bytes(int fd, unsigned int byte, int bytes, char *buff) } -void write_bytes(int fd, unsigned int byte, int bytes, char *buff) +void write_bytes(int fd, long long byte, int bytes, char *buff) { off_t off = byte; - if(off + bytes > ((long long)1<<32) - 1 ) - BAD_ERROR("Filesystem greater than maximum size 2^32 - 1\n"); - if(lseek(fd, off, SEEK_SET) == -1) { perror("Lseek on destination failed"); EXIT_MKSQUASHFS(); @@ -346,12 +407,12 @@ void write_bytes(int fd, unsigned int byte, int bytes, char *buff) } -unsigned int write_inodes() +long long write_inodes() { unsigned short c_byte; int avail_bytes; char *datap = data_cache; - unsigned int start_bytes = bytes; + long long start_bytes = bytes; while(cache_bytes) { if(inode_size - inode_bytes < ((SQUASHFS_METADATA_SIZE << 1) + 2)) { @@ -364,7 +425,7 @@ unsigned int write_inodes() c_byte = mangle(inode_table + inode_bytes + block_offset, datap, avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0); TRACE("Inode block @ %x, size %d\n", inode_bytes, c_byte); if(!swap) - memcpy((void *) (inode_table + inode_bytes), (void *) &c_byte, sizeof(unsigned short)); + memcpy(inode_table + inode_bytes, &c_byte, sizeof(unsigned short)); else SQUASHFS_SWAP_SHORTS((&c_byte), (inode_table + inode_bytes), 1); if(check_data) @@ -382,12 +443,12 @@ unsigned int write_inodes() } -unsigned int write_directories() +long long write_directories() { unsigned short c_byte; int avail_bytes; char *directoryp = directory_data_cache; - unsigned int start_bytes = bytes; + long long start_bytes = bytes; while(directory_cache_bytes) { if(directory_size - directory_bytes < ((SQUASHFS_METADATA_SIZE << 1) + 2)) { @@ -401,7 +462,7 @@ unsigned int write_directories() c_byte = mangle(directory_table + directory_bytes + block_offset, directoryp, avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0); TRACE("Directory block @ %x, size %d\n", directory_bytes, c_byte); if(!swap) - memcpy((void *) (directory_table + directory_bytes), (void *) &c_byte, sizeof(unsigned short)); + memcpy(directory_table + directory_bytes, &c_byte, sizeof(unsigned short)); else SQUASHFS_SWAP_SHORTS((&c_byte), (directory_table + directory_bytes), 1); if(check_data) @@ -455,81 +516,132 @@ unsigned int get_guid(squashfs_uid uid, squashfs_uid guid) } -squashfs_inode create_inode(char *filename, int type, int byte_size, -squashfs_block start_block, unsigned int offset, unsigned int *block_list, struct fragment *fragment) +int create_inode(squashfs_inode *i_no, struct dir_ent *dir_ent, int type, long long byte_size, long long start_block, unsigned int offset, unsigned int *block_list, struct fragment *fragment, struct directory *dir_in) { - squashfs_inode i_no; - struct stat buf; + struct stat *buf = &dir_ent->inode->buf; squashfs_inode_header inode_header; squashfs_base_inode_header *inode, *base = &inode_header.base; + char *filename = dir_ent->pathname; + int nlink = dir_ent->inode->nlink; + int inode_number = (type == SQUASHFS_LDIR_TYPE || type == SQUASHFS_DIR_TYPE) ? dir_ent->inode->inode_number : dir_ent->inode->inode_number + dir_inode_no; - if(filename[0] == '\0') { - /* dummy top level directory, if multiple sources specified on command line */ - buf.st_mode = S_IRWXU | S_IRWXG | S_IRWXO; - buf.st_uid = getuid(); - buf.st_gid = getgid(); - buf.st_mtime = time(NULL); - } else if(lstat(filename, &buf) == -1) { - char buffer[8192]; - sprintf(buffer, "Cannot stat dir/file %s, ignoring", filename); - perror(buffer); - return SQUASHFS_INVALID; - } - - base->mode = SQUASHFS_MODE(buf.st_mode); - base->uid = get_uid((squashfs_uid) global_uid == -1 ? buf.st_uid : global_uid); + base->mode = SQUASHFS_MODE(buf->st_mode); + base->uid = get_uid((squashfs_uid) global_uid == -1 ? buf->st_uid : global_uid); base->inode_type = type; - base->guid = get_guid((squashfs_uid) global_uid == -1 ? buf.st_uid : global_uid, (squashfs_uid) global_gid == -1 ? buf.st_gid : global_gid); + base->guid = get_guid((squashfs_uid) global_uid == -1 ? buf->st_uid : global_uid, (squashfs_uid) global_gid == -1 ? buf->st_gid : global_gid); + base->mtime = buf->st_mtime; + base->inode_number = inode_number; if(type == SQUASHFS_FILE_TYPE) { int i; squashfs_reg_inode_header *reg = &inode_header.reg, *inodep; inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int)); - inodep = (squashfs_reg_inode_header *) inode ; - reg->mtime = buf.st_mtime; + inodep = (squashfs_reg_inode_header *) inode; reg->file_size = byte_size; reg->start_block = start_block; reg->fragment = fragment->index; reg->offset = fragment->offset; if(!swap) { - memcpy((void *) inodep, (void *) reg, sizeof(*reg)); - memcpy((void *) inodep->block_list, block_list, offset * sizeof(unsigned int)); + memcpy(inodep, reg, sizeof(*reg)); + memcpy(inodep->block_list, block_list, offset * sizeof(unsigned int)); } else { SQUASHFS_SWAP_REG_INODE_HEADER(reg, inodep); SQUASHFS_SWAP_INTS(block_list, inodep->block_list, offset); } - TRACE("File inode, file_size %d, start_block %x, blocks %d, fragment %d, offset %d, size %d\n", byte_size, + TRACE("File inode, file_size %d, start_block %llx, blocks %d, fragment %d, offset %d, size %d\n", (int) byte_size, start_block, offset, fragment->index, fragment->offset, fragment->size); for(i = 0; i < offset; i++) TRACE("Block %d, size %d\n", i, block_list[i]); } + else if(type == SQUASHFS_LREG_TYPE) { + int i; + squashfs_lreg_inode_header *reg = &inode_header.lreg, *inodep; + + inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int)); + inodep = (squashfs_lreg_inode_header *) inode; + reg->nlink = nlink; + reg->file_size = byte_size; + reg->start_block = start_block; + reg->fragment = fragment->index; + reg->offset = fragment->offset; + if(!swap) { + memcpy(inodep, reg, sizeof(*reg)); + memcpy(inodep->block_list, block_list, offset * sizeof(unsigned int)); + } else { + SQUASHFS_SWAP_LREG_INODE_HEADER(reg, inodep); + SQUASHFS_SWAP_INTS(block_list, inodep->block_list, offset); + } + TRACE("Long file inode, file_size %lld, start_block %llx, blocks %d, fragment %d, offset %d, size %d, nlink %d\n", byte_size, + start_block, offset, fragment->index, fragment->offset, fragment->size, nlink); + for(i = 0; i < offset; i++) + TRACE("Block %d, size %d\n", i, block_list[i]); + } + else if(type == SQUASHFS_LDIR_TYPE) { + int i; + unsigned char *p; + squashfs_ldir_inode_header *dir = &inode_header.ldir, *inodep; + struct cached_dir_index *index = dir_in->index; + unsigned int i_count = dir_in->i_count; + unsigned int i_size = dir_in->i_size; + + if(byte_size >= 1 << 27) + BAD_ERROR("directory greater than 2^27-1 bytes!\n"); + + inode = get_inode(sizeof(*dir) + i_size); + inodep = (squashfs_ldir_inode_header *) inode; + dir->inode_type = SQUASHFS_LDIR_TYPE; + dir->nlink = dir_ent->dir->directory_count + 2; + dir->file_size = byte_size; + dir->offset = offset; + dir->start_block = start_block; + dir->i_count = i_count; + dir->parent_inode = dir_ent->our_dir ? dir_ent->our_dir->dir_ent->inode->inode_number : dir_inode_no + inode_no; + + if(!swap) + memcpy(inode, dir, sizeof(*dir)); + else + SQUASHFS_SWAP_LDIR_INODE_HEADER(dir, inode); + p = (unsigned char *) inodep->index; + for(i = 0; i < i_count; i++) { + if(!swap) + memcpy(p, &index[i].index, sizeof(squashfs_dir_index)); + else + SQUASHFS_SWAP_DIR_INDEX(&index[i].index, p); + memcpy(((squashfs_dir_index *)p)->name, index[i].name, index[i].index.size + 1); + p += sizeof(squashfs_dir_index) + index[i].index.size + 1; + } + TRACE("Long directory inode, file_size %d, start_block %llx, offset %x, nlink %d\n", (int) byte_size, + start_block, offset, dir_ent->dir->directory_count + 2); + } else if(type == SQUASHFS_DIR_TYPE) { squashfs_dir_inode_header *dir = &inode_header.dir; inode = get_inode(sizeof(*dir)); - dir->mtime = buf.st_mtime; + dir->nlink = dir_ent->dir->directory_count + 2; dir->file_size = byte_size; dir->offset = offset; dir->start_block = start_block; + dir->parent_inode = dir_ent->our_dir ? dir_ent->our_dir->dir_ent->inode->inode_number : dir_inode_no + inode_no; if(!swap) - memcpy((void *) inode, (void *) dir, sizeof(*dir)); + memcpy(inode, dir, sizeof(*dir)); else SQUASHFS_SWAP_DIR_INODE_HEADER(dir, inode); - TRACE("Directory inode, file_size %d, start_block %x, offset %x\n", byte_size, - start_block, offset); + TRACE("Directory inode, file_size %d, start_block %llx, offset %x, nlink %d\n", (int) byte_size, + start_block, offset, dir_ent->dir->directory_count + 2); } else if(type == SQUASHFS_CHRDEV_TYPE || type == SQUASHFS_BLKDEV_TYPE) { squashfs_dev_inode_header *dev = &inode_header.dev; inode = get_inode(sizeof(*dev)); - dev->rdev = (unsigned short) ((major(buf.st_rdev) << 8) | - (minor(buf.st_rdev) & 0xff)); + dev->nlink = nlink; + dev->rdev = (unsigned short) ((major(buf->st_rdev) << 8) | + (minor(buf->st_rdev) & 0xff)); if(!swap) - memcpy((void *) inode, (void *) dev, sizeof(*dev)); + memcpy(inode, dev, sizeof(*dev)); else SQUASHFS_SWAP_DEV_INODE_HEADER(dev, inode); - TRACE("Device inode, rdev %x\n", dev->rdev); + TRACE("Device inode, rdev %x, nlink %d\n", dev->rdev, nlink); } else if(type == SQUASHFS_SYMLINK_TYPE) { squashfs_symlink_inode_header *symlink = &inode_header.symlink, *inodep; @@ -538,61 +650,65 @@ squashfs_block start_block, unsigned int offset, unsigned int *block_list, struc if((byte = readlink(filename, buff, 65536)) == -1) { perror("Error in reading symbolic link, skipping..."); - return SQUASHFS_INVALID; + return FALSE; } if(byte == 65536) { ERROR("Symlink is greater than 65536 bytes! skipping..."); - return SQUASHFS_INVALID; + return FALSE; } inode = get_inode(sizeof(*symlink) + byte); - inodep = (squashfs_symlink_inode_header *) inode ; + symlink->nlink = nlink; + inodep = (squashfs_symlink_inode_header *) inode; symlink->symlink_size = byte; if(!swap) - memcpy((void *) inode, symlink, sizeof(*symlink)); + memcpy(inode, symlink, sizeof(*symlink)); else SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode); strncpy(inodep->symlink, buff, byte); - TRACE("Symbolic link inode, symlink_size %d\n", byte); + TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte, nlink); } else if(type == SQUASHFS_FIFO_TYPE || type == SQUASHFS_SOCKET_TYPE) { squashfs_ipc_inode_header *ipc = &inode_header.ipc; inode = get_inode(sizeof(*ipc)); + ipc->nlink = nlink; if(!swap) - memcpy((void *) inode, (void *) ipc, sizeof(*ipc)); + memcpy(inode, ipc, sizeof(*ipc)); else SQUASHFS_SWAP_IPC_INODE_HEADER(ipc, inode); - TRACE("ipc inode, type %s %d\n", type == SQUASHFS_FIFO_TYPE ? "fifo" : "socket"); + TRACE("ipc inode, type %s, nlink %d\n", type == SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink); } else - return SQUASHFS_INVALID; + return FALSE; - i_no = MKINODE(inode); + *i_no = MKINODE(inode); inode_count ++; - TRACE("Created inode 0x%Lx, type %d, uid %d, guid %d\n", i_no, type, base->uid, base->guid); + TRACE("Created inode 0x%llx, type %d, uid %d, guid %d\n", *i_no, type, base->uid, base->guid); - return i_no; + return TRUE; } -void init_dir(struct directory *dir) +void scan2_init_dir(struct directory *dir) { - if((dir->buff = (char *)malloc(SQUASHFS_METADATA_SIZE)) == NULL) { + if((dir->buff = malloc(SQUASHFS_METADATA_SIZE)) == NULL) { BAD_ERROR("Out of memory allocating directory buffer\n"); } dir->size = SQUASHFS_METADATA_SIZE; - dir->p = dir->buff; + dir->p = dir->index_count_p = dir->buff; dir->entry_count = 256; dir->entry_count_p = NULL; + dir->index = NULL; + dir->i_count = dir->i_size = 0; } -void add_dir(squashfs_inode inode, char *name, int type, struct directory *dir) +void add_dir(squashfs_inode inode, unsigned int inode_number, char *name, int type, struct directory *dir) { - char *buff; + unsigned char *buff; squashfs_dir_entry idir, *idirp; unsigned int start_block = inode >> 16; unsigned int offset = inode & 0xffff; @@ -603,33 +719,48 @@ void add_dir(squashfs_inode inode, char *name, int type, struct directory *dir) ERROR("Filename is greater than %d characters, truncating! ...\n", SQUASHFS_NAME_LEN); } - if(dir->p + sizeof(squashfs_dir_entry) + size + 6 >= dir->buff + dir->size) { - if((buff = (char *) realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE)) == NULL) { + if(dir->p + sizeof(squashfs_dir_entry) + size + sizeof(squashfs_dir_header) >= dir->buff + dir->size) { + if((buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE)) == NULL) { BAD_ERROR("Out of memory reallocating directory buffer\n"); } dir->p = (dir->p - dir->buff) + buff; if(dir->entry_count_p) - dir->entry_count_p = (squashfs_dir_header *) (((unsigned char *) dir->entry_count_p) - - dir->buff + buff); + dir->entry_count_p = (dir->entry_count_p - dir->buff + buff); + dir->index_count_p = dir->index_count_p - dir->buff + buff; dir->buff = buff; } - if(dir->entry_count == 256 || start_block != dir->start_block) { + if(dir->entry_count == 256 || start_block != dir->start_block || ((dir->entry_count_p != NULL) && ((dir->p + sizeof(squashfs_dir_entry) + size - dir->index_count_p) > SQUASHFS_METADATA_SIZE)) || ((long long) inode_number - dir->inode_number) > 32767 || ((long long) inode_number - dir->inode_number) < - 32768) { if(dir->entry_count_p) { squashfs_dir_header dir_header; + if((dir->p + sizeof(squashfs_dir_entry) + size - dir->index_count_p) > SQUASHFS_METADATA_SIZE) { + if(dir->i_count % I_COUNT_SIZE == 0) + if((dir->index = realloc(dir->index, (dir->i_count + I_COUNT_SIZE) * sizeof(struct cached_dir_index))) == NULL) + BAD_ERROR("Out of memory in directory index table reallocation!\n"); + dir->index[dir->i_count].index.index = dir->p - dir->buff; + dir->index[dir->i_count].index.size = size - 1; + dir->index[dir->i_count++].name = name; + dir->i_size += sizeof(squashfs_dir_index) + size; + dir->index_count_p = dir->p; + } + dir_header.count = dir->entry_count - 1; dir_header.start_block = dir->start_block; + dir_header.inode_number = dir->inode_number; if(!swap) - memcpy((void *) dir->entry_count_p, (void *) &dir_header, sizeof(dir_header)); + memcpy(dir->entry_count_p, &dir_header, sizeof(dir_header)); else - SQUASHFS_SWAP_DIR_HEADER((&dir_header), dir->entry_count_p); + SQUASHFS_SWAP_DIR_HEADER((&dir_header), (squashfs_dir_header *) dir->entry_count_p); + } - dir->entry_count_p = (squashfs_dir_header *) dir->p; + + dir->entry_count_p = dir->p; dir->start_block = start_block; dir->entry_count = 0; + dir->inode_number = inode_number; dir->p += sizeof(squashfs_dir_header); } @@ -637,8 +768,9 @@ void add_dir(squashfs_inode inode, char *name, int type, struct directory *dir) idir.offset = offset; idir.type = type; idir.size = size - 1; + idir.inode_number = ((long long) inode_number - dir->inode_number); if(!swap) - memcpy((void *) idirp, (void *) &idir, sizeof(idir)); + memcpy(idirp, &idir, sizeof(idir)); else SQUASHFS_SWAP_DIR_ENTRY((&idir), idirp); strncpy(idirp->name, name, size); @@ -647,14 +779,48 @@ void add_dir(squashfs_inode inode, char *name, int type, struct directory *dir) } -squashfs_inode write_dir(char *filename, struct directory *dir) +int write_dir(squashfs_inode *inode, struct dir_info *dir_info, struct directory *dir) { - squashfs_inode inode; - unsigned int dir_size; - int data_space; + unsigned int dir_size = dir->p - dir->buff; + int data_space = (directory_cache_size - directory_cache_bytes); + unsigned int directory_block, directory_offset, i_count, index; unsigned short c_byte; - while(directory_cache_bytes >= SQUASHFS_METADATA_SIZE) { + if(data_space < dir_size) { + int realloc_size = directory_cache_size == 0 ? ((dir_size + SQUASHFS_METADATA_SIZE) & ~(SQUASHFS_METADATA_SIZE - 1)) : dir_size - data_space; + + if((directory_data_cache = (char *) realloc(directory_data_cache, directory_cache_size + realloc_size)) == NULL) { + goto failed; + } + directory_cache_size += realloc_size; + } + + if(dir_size) { + squashfs_dir_header dir_header; + + dir_header.count = dir->entry_count - 1; + dir_header.start_block = dir->start_block; + dir_header.inode_number = dir->inode_number; + if(!swap) + memcpy(dir->entry_count_p, &dir_header, sizeof(dir_header)); + else + SQUASHFS_SWAP_DIR_HEADER((&dir_header), (squashfs_dir_header *) dir->entry_count_p); + memcpy(directory_data_cache + directory_cache_bytes, dir->buff, dir_size); + } + directory_offset = directory_cache_bytes; + directory_block = directory_bytes; + directory_cache_bytes += dir_size; + i_count = 0; + index = SQUASHFS_METADATA_SIZE - directory_offset; + + while(1) { + while(i_count < dir->i_count && dir->index[i_count].index.index < index) + dir->index[i_count++].index.start_block = directory_bytes; + index += SQUASHFS_METADATA_SIZE; + + if(directory_cache_bytes < SQUASHFS_METADATA_SIZE) + break; + if((directory_size - directory_bytes) < ((SQUASHFS_METADATA_SIZE << 1) + 2)) { if((directory_table = (char *) realloc(directory_table, directory_size + (SQUASHFS_METADATA_SIZE << 1) + 2)) == NULL) { @@ -667,7 +833,7 @@ squashfs_inode write_dir(char *filename, struct directory *dir) SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE, noI, 0); TRACE("Directory block @ %x, size %d\n", directory_bytes, c_byte); if(!swap) - memcpy((void *) directory_table + directory_bytes, (void *) &c_byte, sizeof(unsigned short)); + memcpy(directory_table + directory_bytes, &c_byte, sizeof(unsigned short)); else SQUASHFS_SWAP_SHORTS((&c_byte), (directory_table + directory_bytes), 1); if(check_data) @@ -678,39 +844,20 @@ squashfs_inode write_dir(char *filename, struct directory *dir) directory_cache_bytes -= SQUASHFS_METADATA_SIZE; } - dir_size = dir->p - dir->buff; - data_space = (directory_cache_size - directory_cache_bytes); - if(data_space < dir_size) { - int realloc_size = directory_cache_size == 0 ? ((dir_size + SQUASHFS_METADATA_SIZE) & ~(SQUASHFS_METADATA_SIZE - 1)) : dir_size - data_space; - - if((directory_data_cache = (char *) realloc(directory_data_cache, directory_cache_size + realloc_size)) == NULL) { - goto failed; - } - directory_cache_size += realloc_size; - } - - if(dir_size) { - squashfs_dir_header dir_header; - - dir_header.count = dir->entry_count - 1; - dir_header.start_block = dir->start_block; - if(!swap) - memcpy((void *) dir->entry_count_p, (void *) &dir_header, sizeof(dir_header)); - else - SQUASHFS_SWAP_DIR_HEADER((&dir_header), dir->entry_count_p); - memcpy(directory_data_cache + directory_cache_bytes, dir->buff, dir_size); + if(dir_info->dir_is_ldir) { + if(create_inode(inode, dir_info->dir_ent, SQUASHFS_LDIR_TYPE, dir_size + 3, directory_block, directory_offset, NULL, NULL, dir) == FALSE) + return FALSE; + } else { + if(create_inode(inode, dir_info->dir_ent, SQUASHFS_DIR_TYPE, dir_size + 3, directory_block, directory_offset, NULL, NULL, NULL) == FALSE) + return FALSE; } - inode = create_inode(filename, SQUASHFS_DIR_TYPE, dir_size, directory_bytes, directory_cache_bytes, NULL, NULL); - - directory_cache_bytes += dir_size; - #ifdef SQUASHFS_TRACE if(!swap) { unsigned char *dirp; int count; - TRACE("Directory contents of inode 0x%Lx\n", inode); + TRACE("Directory contents of inode 0x%llx\n", *inode); dirp = dir->buff; while(dirp < dir->p) { char buffer[SQUASHFS_NAME_LEN + 1]; @@ -735,7 +882,7 @@ squashfs_inode write_dir(char *filename, struct directory *dir) #endif dir_count ++; - return inode; + return TRUE; failed: BAD_ERROR("Out of memory in directory table reallocation!\n"); @@ -744,37 +891,35 @@ failed: char *get_fragment(char *buffer, struct fragment *fragment) { - if(fragment->index == fragments || fragment->index == SQUASHFS_INVALID_BLK) - return fragment_data + fragment->offset; - else { - squashfs_fragment_entry *disk_fragment = &fragment_table[fragment->index]; - int size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size), res; - long bytes = block_size; - - if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) { - char cbuffer[block_size]; - - read_bytes(fd, disk_fragment->start_block, size, cbuffer); - - if((res = uncompress(buffer, &bytes, (const char *) cbuffer, size)) != Z_OK) { - if(res == Z_MEM_ERROR) - BAD_ERROR("zlib::uncompress failed, not enough memory\n"); - else if(res == Z_BUF_ERROR) - BAD_ERROR("zlib::uncompress failed, not enough room in output buffer\n"); - else - BAD_ERROR("zlib::uncompress failed, unknown error %d\n", res); - } - } else - read_bytes(fd, disk_fragment->start_block, size, buffer); - return buffer + fragment->offset; - } + squashfs_fragment_entry *disk_fragment = &fragment_table[fragment->index]; + int size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size); + + if(SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) { + int res; + unsigned long bytes = block_size; + char cbuffer[block_size]; + + read_bytes(fd, disk_fragment->start_block, size, cbuffer); + + if((res = uncompress((unsigned char *) buffer, &bytes, (const unsigned char *) cbuffer, size)) != Z_OK) { + if(res == Z_MEM_ERROR) + BAD_ERROR("zlib::uncompress failed, not enough memory\n"); + else if(res == Z_BUF_ERROR) + BAD_ERROR("zlib::uncompress failed, not enough room in output buffer\n"); + else + BAD_ERROR("zlib::uncompress failed, unknown error %d\n", res); + } + } else + read_bytes(fd, disk_fragment->start_block, size, buffer); + + return buffer + fragment->offset; } void write_fragment() { int compressed_size; - unsigned char buffer[block_size << 1]; + char buffer[block_size << 1]; if(fragment_size == 0) return; @@ -795,7 +940,7 @@ void write_fragment() } -static struct fragment empty_fragment = {SQUASHFS_INVALID_BLK, 0, 0}; +static struct fragment empty_fragment = {SQUASHFS_INVALID_FRAG, 0, 0}; struct fragment *get_and_fill_fragment(char *buff, int size) { struct fragment *ffrg; @@ -819,9 +964,10 @@ struct fragment *get_and_fill_fragment(char *buff, int size) } -unsigned int write_fragment_table() +long long write_fragment_table() { - unsigned int start_bytes, frag_bytes = SQUASHFS_FRAGMENT_BYTES(fragments), + long long start_bytes; + unsigned int frag_bytes = SQUASHFS_FRAGMENT_BYTES(fragments), meta_blocks = SQUASHFS_FRAGMENT_INDEXES(fragments); char cbuffer[(SQUASHFS_METADATA_SIZE << 2) + 2], buffer[frag_bytes]; squashfs_fragment_entry *p = (squashfs_fragment_entry *) buffer; @@ -831,9 +977,9 @@ unsigned int write_fragment_table() TRACE("write_fragment_table: fragments %d, frag_bytes %d, meta_blocks %d\n", fragments, frag_bytes, meta_blocks); for(i = 0; i < fragments; i++, p++) { - TRACE("write_fragment_table: fragment %d, start_block %x, size %d\n", i, fragment_table[i].start_block, fragment_table[i].size); + TRACE("write_fragment_table: fragment %d, start_block %llx, size %d\n", i, fragment_table[i].start_block, fragment_table[i].size); if(!swap) - memcpy((void *) p, &fragment_table[i], sizeof(squashfs_fragment_entry)); + memcpy(p, &fragment_table[i], sizeof(squashfs_fragment_entry)); else SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_table[i], p); } @@ -842,7 +988,7 @@ unsigned int write_fragment_table() int avail_bytes = i == meta_blocks - 1 ? frag_bytes % SQUASHFS_METADATA_SIZE : SQUASHFS_METADATA_SIZE; c_byte = mangle(cbuffer + block_offset, buffer + i * SQUASHFS_METADATA_SIZE , avail_bytes, SQUASHFS_METADATA_SIZE, noF, 0); if(!swap) - memcpy((void *) cbuffer, (void *) &c_byte, sizeof(unsigned short)); + memcpy(cbuffer, &c_byte, sizeof(unsigned short)); else SQUASHFS_SWAP_SHORTS((&c_byte), cbuffer, 1); if(check_data) @@ -868,16 +1014,16 @@ unsigned int write_fragment_table() } -unsigned char *read_from_buffer(struct duplicate_buffer_handle *handle, unsigned int avail_bytes) +char *read_from_buffer(struct duplicate_buffer_handle *handle, unsigned int avail_bytes) { - unsigned char *v = handle->ptr; + char *v = handle->ptr; handle->ptr += avail_bytes; return v; } char read_from_file_buffer[SQUASHFS_FILE_MAX_SIZE]; -unsigned char *read_from_file(struct duplicate_buffer_handle *handle, unsigned int avail_bytes) +char *read_from_file(struct duplicate_buffer_handle *handle, unsigned int avail_bytes) { read_bytes(fd, handle->start, avail_bytes, read_from_file_buffer); handle->start += avail_bytes; @@ -888,7 +1034,7 @@ unsigned char *read_from_file(struct duplicate_buffer_handle *handle, unsigned i /* * Compute 16 bit BSD checksum over the data */ -unsigned short get_checksum(unsigned char *(get_next_file_block)(struct duplicate_buffer_handle *, unsigned int), struct duplicate_buffer_handle *handle, int l) +unsigned short get_checksum(char *(get_next_file_block)(struct duplicate_buffer_handle *, unsigned int), struct duplicate_buffer_handle *handle, long long l) { unsigned short chksum = 0; unsigned int bytes = 0; @@ -898,7 +1044,7 @@ unsigned short get_checksum(unsigned char *(get_next_file_block)(struct duplicat while(l) { bytes = l > SQUASHFS_FILE_MAX_SIZE ? SQUASHFS_FILE_MAX_SIZE : l; l -= bytes; - b = get_next_file_block(&position, bytes); + b = (unsigned char *) get_next_file_block(&position, bytes); while(bytes--) { chksum = (chksum & 1) ? (chksum >> 1) | 0x8000 : chksum >> 1; chksum += *b++; @@ -909,14 +1055,15 @@ unsigned short get_checksum(unsigned char *(get_next_file_block)(struct duplicat } -static unsigned int cached_frag = -1; -void add_file(int start, int file_bytes, unsigned int *block_listp, int blocks, unsigned int fragment, int offset, int bytes) +int cached_frag = -1; +void add_file(long long start, long long file_bytes, unsigned int *block_listp, int blocks, unsigned int fragment, int offset, int bytes) { struct fragment *frg; struct file_info *dupl_ptr; char *datap; struct duplicate_buffer_handle handle; - + unsigned int *block_list = block_listp; + if(!duplicate_checking) return; @@ -926,18 +1073,23 @@ void add_file(int start, int file_bytes, unsigned int *block_listp, int blocks, frg->index = fragment; frg->offset = offset; frg->size = bytes; - if(cached_frag == fragment) + if(fragment == cached_frag || fragment == SQUASHFS_INVALID_FRAG) datap = fragment_data + offset; else datap = get_fragment(fragment_data, frg); handle.start = start; if((dupl_ptr = duplicate(read_from_file, &handle, file_bytes, &block_listp, &start, blocks, &frg, datap, bytes)) != NULL) dupl_ptr->fragment = frg; + else + free(block_list); cached_frag = fragment; } -struct file_info *duplicate(unsigned char *(get_next_file_block)(struct duplicate_buffer_handle *, unsigned int), struct duplicate_buffer_handle *file_start, int bytes, unsigned int **block_list, int *start, int blocks, struct fragment **fragment, char *frag_data, int frag_bytes) +char cached_fragment[SQUASHFS_FILE_SIZE]; +int cached_frag1 = -1; + +struct file_info *duplicate(char *(get_next_file_block)(struct duplicate_buffer_handle *, unsigned int), struct duplicate_buffer_handle *file_start, long long bytes, unsigned int **block_list, long long *start, int blocks, struct fragment **fragment, char *frag_data, int frag_bytes) { unsigned short checksum = get_checksum(get_next_file_block, file_start, bytes); struct duplicate_buffer_handle handle = { frag_data, 0 }; @@ -947,10 +1099,11 @@ struct file_info *duplicate(unsigned char *(get_next_file_block)(struct duplicat for(; dupl_ptr; dupl_ptr = dupl_ptr->next) if(bytes == dupl_ptr->bytes && frag_bytes == dupl_ptr->fragment->size && fragment_checksum == dupl_ptr->fragment_checksum) { - unsigned char buffer1[SQUASHFS_FILE_MAX_SIZE]; - unsigned int dup_bytes = dupl_ptr->bytes, dup_start = dupl_ptr->start; + char buffer1[SQUASHFS_FILE_MAX_SIZE]; + long long dup_bytes = dupl_ptr->bytes; + long long dup_start = dupl_ptr->start; struct duplicate_buffer_handle position = *file_start; - unsigned char *buffer; + char *buffer; while(dup_bytes) { int avail_bytes = dup_bytes > SQUASHFS_FILE_MAX_SIZE ? SQUASHFS_FILE_MAX_SIZE : dup_bytes; @@ -962,10 +1115,19 @@ struct file_info *duplicate(unsigned char *(get_next_file_block)(struct duplicat dup_start += avail_bytes; } if(dup_bytes == 0) { - char frag_buffer1[block_size]; - char *fragment_buffer1 = get_fragment(frag_buffer1, dupl_ptr->fragment); + char *fragment_buffer1; + + if(dupl_ptr->fragment->index == fragments || dupl_ptr->fragment->index == SQUASHFS_INVALID_FRAG) + fragment_buffer1 = fragment_data + dupl_ptr->fragment->offset; + else if(dupl_ptr->fragment->index == cached_frag1) + fragment_buffer1 = cached_fragment + dupl_ptr->fragment->offset; + else { + fragment_buffer1 = get_fragment(cached_fragment, dupl_ptr->fragment); + cached_frag1 = dupl_ptr->fragment->index; + } + if(frag_bytes == 0 || memcmp(frag_data, fragment_buffer1, frag_bytes) == 0) { - TRACE("Found duplicate file, start 0x%x, size %d, checksum 0x%x, fragment %d, size %d, offset %d, checksum 0x%x\n", dupl_ptr->start, + TRACE("Found duplicate file, start 0x%llx, size %lld, checksum 0x%x, fragment %d, size %d, offset %d, checksum 0x%x\n", dupl_ptr->start, dupl_ptr->bytes, dupl_ptr->checksum, dupl_ptr->fragment->index, frag_bytes, dupl_ptr->fragment->offset, fragment_checksum); *block_list = dupl_ptr->block_list; *start = dupl_ptr->start; @@ -984,11 +1146,8 @@ struct file_info *duplicate(unsigned char *(get_next_file_block)(struct duplicat dupl_ptr->checksum = checksum; dupl_ptr->start = *start; dupl_ptr->fragment_checksum = fragment_checksum; - if((dupl_ptr->block_list = (unsigned int *) malloc(blocks * sizeof(unsigned int))) == NULL) { - BAD_ERROR("Out of memory allocating block_list\n"); - } - - memcpy(dupl_ptr->block_list, *block_list, blocks * sizeof(unsigned int)); + dupl_ptr->block_list = *block_list; + dup_files ++; if(bytes) { dupl_ptr->next = dupl[checksum]; @@ -1003,18 +1162,22 @@ struct file_info *duplicate(unsigned char *(get_next_file_block)(struct duplicat #define MINALLOCBYTES (1024 * 1024) -squashfs_inode write_file(char *filename, long long size, int *duplicate_file) +int write_file(squashfs_inode *inode, struct dir_ent *dir_ent, long long size, int *duplicate_file) { - unsigned int frag_bytes, file, start, file_bytes = 0, block = 0; - unsigned int c_byte; - long long read_size = (size > SQUASHFS_MAX_FILE_SIZE) ? SQUASHFS_MAX_FILE_SIZE : size; - unsigned int blocks = (read_size + block_size - 1) >> block_log; - unsigned int block_list[blocks], *block_listp = block_list; - char buff[block_size], *c_buffer; - int allocated_blocks = blocks, i, bbytes, whole_file = 1; + int block = 0, i, file, whole_file = 1, status; + unsigned int c_byte, frag_bytes; + long long bbytes, file_bytes = 0, start; + char buff[block_size], *c_buffer = NULL, *filename = dir_ent->pathname; struct fragment *fragment; - struct file_info *dupl_ptr; + struct file_info *dupl_ptr = NULL; struct duplicate_buffer_handle handle; + long long read_size = (size > SQUASHFS_MAX_FILE_SIZE) ? SQUASHFS_MAX_FILE_SIZE : size; + int blocks = (read_size + block_size - 1) >> block_log, allocated_blocks = blocks; + unsigned int *block_list, *block_listp; + + if((block_list = malloc(blocks * sizeof(unsigned int))) == NULL) + BAD_ERROR("Out of memory allocating block_list\n"); + block_listp = block_list; if(!no_fragments && (read_size < block_size || always_use_fragments)) { allocated_blocks = blocks = read_size >> block_log; @@ -1023,20 +1186,19 @@ squashfs_inode write_file(char *filename, long long size, int *duplicate_file) frag_bytes = 0; if(size > read_size) - ERROR("file %s truncated to %Ld bytes\n", filename, SQUASHFS_MAX_FILE_SIZE); + ERROR("file %s truncated to %lld bytes\n", filename, SQUASHFS_MAX_FILE_SIZE); total_bytes += read_size; - if((file = open(filename, O_RDONLY)) == -1) { - perror("Error in opening file, skipping..."); - return SQUASHFS_INVALID; - } + if((file = open(filename, O_RDONLY)) == -1) + goto read_err; do { - if((c_buffer = (char *) malloc((allocated_blocks + 1) << block_log)) == NULL) { - TRACE("Out of memory allocating write_file buffer, allocated_blocks %d, blocks %d\n", allocated_blocks, blocks); + long long bytes = (((long long) allocated_blocks) + 1) << block_log; + if(bytes != ((size_t) bytes) || (c_buffer = (char *) malloc(bytes)) == NULL) { + TRACE("Out of memory allocating write_file buffer, allocated_blocks %ld, blocks %d\n", allocated_blocks, blocks); whole_file = 0; - if((allocated_blocks << (block_log - 1)) < MINALLOCBYTES) - BAD_ERROR("Out of memory allocating write_file buffer, could not allocate %d blocks (%d Kbytes)\n", allocated_blocks, allocated_blocks << (block_log - 10)); + if(bytes < MINALLOCBYTES) + BAD_ERROR("Out of memory allocating write_file buffer, could not allocate %ld blocks (%d Kbytes)\n", allocated_blocks, allocated_blocks << (block_log - 10)); allocated_blocks >>= 1; } } while(!c_buffer); @@ -1089,54 +1251,19 @@ squashfs_inode write_file(char *filename, long long size, int *duplicate_file) wr_inode: free(c_buffer); file_count ++; - return create_inode(filename, SQUASHFS_FILE_TYPE, read_size, start, blocks, block_listp, fragment); + if(dir_ent->inode->nlink == 1 && read_size < ((long long) (1<<30) - 1)) + status = create_inode(inode, dir_ent, SQUASHFS_FILE_TYPE, read_size, start, blocks, block_listp, fragment, NULL); + else + status = create_inode(inode, dir_ent, SQUASHFS_LREG_TYPE, read_size, start, blocks, block_listp, fragment, NULL); + if(duplicate_checking == FALSE || *duplicate_file == TRUE) + free(block_list); + return status; read_err: perror("Error in reading file, skipping..."); free(c_buffer); - return SQUASHFS_INVALID; -} - - -struct linuxdir { - DIR *linuxdir; - char pathname[8192]; -}; - - -void *linux_opendir(char *pathname, struct directory *dir) -{ - struct linuxdir *linuxdir; - if((linuxdir = malloc(sizeof(struct linuxdir))) == NULL) - return NULL; - if((linuxdir->linuxdir = opendir(pathname)) == NULL) { - free(linuxdir); - return NULL; - } - strcpy(linuxdir->pathname, pathname); - return (void *) linuxdir; -} - - -int linux_readdir(void *l, char *filename, char *dir_name) -{ - struct dirent *d_name; - struct linuxdir *linuxdir = (struct linuxdir *)l; - - do { - if((d_name = readdir(linuxdir->linuxdir)) == NULL) - return FALSE; - } while(strcmp(d_name->d_name, ".") == 0 || strcmp(d_name->d_name, "..") == 0); - strcat(strcat(strcpy(filename, linuxdir->pathname), "/"), d_name->d_name); - strcpy(dir_name, d_name->d_name); - return TRUE; -} - - -void linux_closedir(void *linuxdir) -{ - closedir(((struct linuxdir *)linuxdir)->linuxdir); - free(linuxdir); + free(block_list); + return FALSE; } @@ -1189,100 +1316,265 @@ char *basename_r() } -char encomp_pathname[8192]; -int encomp_entry = 0; +struct inode_info *lookup_inode(struct stat *buf) +{ + int inode_hash = INODE_HASH(buf->st_dev, buf->st_ino); + struct inode_info *inode = inode_info[inode_hash]; + + while(inode != NULL) { + if(memcmp(buf, &inode->buf, sizeof(struct stat)) == 0) { + inode->nlink ++; + return inode; + } + inode = inode->next; + } + + if((inode = malloc(sizeof(struct inode_info))) == NULL) + BAD_ERROR("Out of memory in inode hash table entry allocation\n"); + + memcpy(&inode->buf, buf, sizeof(struct stat)); + inode->inode = SQUASHFS_INVALID_BLK; + inode->nlink = 1; + if((buf->st_mode & S_IFMT) == S_IFDIR) + inode->inode_number = dir_inode_no ++; + else + inode->inode_number = inode_no ++; + + inode->next = inode_info[inode_hash]; + inode_info[inode_hash] = inode; + + return inode; +} + + +inline void add_dir_entry(char *name, char *pathname, struct dir_info *sub_dir, struct inode_info *inode_info, void *data, struct dir_info *dir) +{ + if((dir->count % DIR_ENTRIES) == 0) + if((dir->list = realloc(dir->list, (dir->count + DIR_ENTRIES) * sizeof(struct dir_ent *))) == NULL) + BAD_ERROR("Out of memory in add_dir_entry\n"); + + if((dir->list[dir->count] = malloc(sizeof(struct dir_ent))) == NULL) + BAD_ERROR("Out of memory in linux_opendir\n"); + + if(sub_dir) + sub_dir->dir_ent = dir->list[dir->count]; + dir->list[dir->count]->name = strdup(name); + dir->list[dir->count]->pathname = pathname != NULL ? strdup(pathname) : NULL; + dir->list[dir->count]->inode = inode_info; + dir->list[dir->count]->dir = sub_dir; + dir->list[dir->count]->our_dir = dir; + dir->list[dir->count++]->data = data; + dir->byte_count += strlen(name) + sizeof(squashfs_dir_entry); +} + -void *encomp_opendir(char *pathname, struct directory *dir) +int compare_name(const void *ent1_ptr, const void *ent2_ptr) { - int i; + struct dir_ent *ent1 = *((struct dir_ent **) ent1_ptr); + struct dir_ent *ent2 = *((struct dir_ent **) ent2_ptr); + + return strcmp(ent1->name, ent2->name); +} + + +void sort_directory(struct dir_info *dir) +{ + qsort(dir->list, dir->count, sizeof(struct dir_ent *), compare_name); + + if((dir->count < 257 && dir->byte_count < SQUASHFS_METADATA_SIZE)) + dir->dir_is_ldir = FALSE; +} + + +struct dir_info *scan1_opendir(char *pathname) +{ + DIR *linuxdir; + struct dirent *d_name; + struct dir_info *dir; - for(i = 0; i < old_root_entries; i++) - add_dir(old_root_entry[i].inode, old_root_entry[i].name, old_root_entry[i].type, dir); + if((dir = malloc(sizeof(struct dir_info))) == NULL) + return NULL; + + if(pathname[0] != '\0' && (dir->linuxdir = opendir(pathname)) == NULL) { + free(dir); + return NULL; + } + dir->pathname = strdup(pathname); + dir->count = dir->directory_count = dir->current_count = dir->byte_count = 0; + dir->dir_is_ldir = TRUE; + dir->list = NULL; - return (void *)source_path; + return dir; } -int encomp_readdir(void *l, char *filename, char *dir_name) +int scan1_encomp_readdir(char *pathname, char *dir_name, struct dir_info *dir) { + int i, n, pass; char *basename; - int n, pass = 1; + static int index = 0; + + if(dir->count < old_root_entries) + for(i = 0; i < old_root_entries; i++) { + if(old_root_entry[i].type == SQUASHFS_DIR_TYPE) + dir->directory_count ++; + add_dir_entry(old_root_entry[i].name, "", NULL, NULL, &old_root_entry[i], dir); + } - while(encomp_entry < source) { - if((basename = getbase(source_path[encomp_entry])) == NULL) { - ERROR("Bad source directory %s - skipping ...\n", source_path[encomp_entry]); - encomp_entry++; + while(index < source) { + if((basename = getbase(source_path[index])) == NULL) { + ERROR("Bad source directory %s - skipping ...\n", source_path[index]); + index ++; continue; } - strcpy(filename, source_path[encomp_entry]); strcpy(dir_name, basename); + pass = 1; for(;;) { - for(n = 0; n < old_root_entries && strcmp(old_root_entry[n].name, dir_name) != 0; n++); - if(n == old_root_entries) { - add_old_root_entry(dir_name, 0, 0); - encomp_entry++; - return TRUE; - } + for(n = 0; n < dir->count && strcmp(dir->list[n]->name, dir_name) != 0; n++); + if(n == dir->count) + break; ERROR("Source directory entry %s already used! - trying ", dir_name); sprintf(dir_name, "%s_%d", basename, pass++); ERROR("%s\n", dir_name); } + strcpy(pathname, source_path[index ++]); + return 1; } - return FALSE; + return 0; +} + + +int scan1_single_readdir(char *pathname, char *dir_name, struct dir_info *dir) +{ + struct dirent *d_name; + int i, pass; + + if(dir->count < old_root_entries) + for(i = 0; i < old_root_entries; i++) { + if(old_root_entry[i].type == SQUASHFS_DIR_TYPE) + dir->directory_count ++; + add_dir_entry(old_root_entry[i].name, "", NULL, NULL, &old_root_entry[i], dir); + } + + if((d_name = readdir(dir->linuxdir)) != NULL) { + strcpy(dir_name, d_name->d_name); + pass = 1; + for(;;) { + for(i = 0; i < dir->count && strcmp(dir->list[i]->name, dir_name) != 0; i++); + if(i == dir->count) + break; + ERROR("Source directory entry %s already used! - trying ", dir_name); + sprintf(dir_name, "%s_%d", d_name->d_name, pass++); + ERROR("%s\n", dir_name); + } + strcat(strcat(strcpy(pathname, dir->pathname), "/"), d_name->d_name); + return 1; + } + + return 0; } -void encomp_closedir(void *linuxdir) +int scan1_readdir(char *pathname, char *dir_name, struct dir_info *dir) { + struct dirent *d_name; + + if((d_name = readdir(dir->linuxdir)) != NULL) { + strcpy(dir_name, d_name->d_name); + strcat(strcat(strcpy(pathname, dir->pathname), "/"), d_name->d_name); + return 1; + } + + return 0; } -void *single_opendir(char *pathname, struct directory *dir) +struct dir_ent *scan2_readdir(struct directory *dir, struct dir_info *dir_info) { - encomp_opendir(pathname, dir); - return linux_opendir(pathname, dir); + int current_count; + + while((current_count = dir_info->current_count++) < dir_info->count) + if(dir_info->list[current_count]->data) + add_dir(dir_info->list[current_count]->data->inode, dir_info->list[current_count]->data->inode_number, + dir_info->list[current_count]->name, dir_info->list[current_count]->data->type, dir); + else + return dir_info->list[current_count]; + return FALSE; } -int single_readdir(void *l, char *filename, char *dir_name) +void scan1_freedir(struct dir_info *dir) { - int i, pass = 1; - char name[SQUASHFS_NAME_LEN + 1]; + if(dir->pathname[0] != '\0') + closedir(dir->linuxdir); +} - if(linux_readdir(l, filename, dir_name) == FALSE) - return FALSE; - strcpy(name, dir_name); - for(;;) { - for(i = 0; i < old_root_entries && strcmp(old_root_entry[i].name, dir_name) != 0; i++); - if(i == old_root_entries) { - add_old_root_entry(dir_name, 0, 0); - return TRUE; - } - ERROR("Source directory entry %s already used! - trying ", dir_name); - sprintf(dir_name, "%s_%d", name, pass++); - ERROR("%s\n", dir_name); +void scan2_freedir(struct directory *dir) +{ + if(dir->index) + free(dir->index); + free(dir->buff); +} + + +void dir_scan(squashfs_inode *inode, char *pathname, int (_readdir)(char *, char *, struct dir_info *)) +{ + struct dir_info *dir_info = dir_scan1(pathname, _readdir); + struct dir_ent *dir_ent; + struct inode_info *inode_info; + + if(dir_info == NULL) + return; + + if((dir_ent = malloc(sizeof(struct dir_ent))) == NULL) + BAD_ERROR("Out of memory in dir_scan\n"); + + if((inode_info = malloc(sizeof(struct inode_info))) == NULL) + BAD_ERROR("Out of memory in dir_scan\n"); + + dir_ent->name = dir_ent->pathname = strdup(pathname); + dir_ent->dir = dir_info; + dir_ent->inode = inode_info; + dir_ent->our_dir = NULL; + dir_ent->data = NULL; + inode_info->nlink = 1; + inode_info->inode_number = root_inode_number ? root_inode_number : dir_inode_no++; + dir_info->dir_ent = dir_ent; + + if(pathname[0] == '\0') { + /* dummy top level directory, if multiple sources specified on command line */ + inode_info->buf.st_mode = S_IRWXU | S_IRWXG | S_IRWXO; + inode_info->buf.st_uid = getuid(); + inode_info->buf.st_gid = getgid(); + inode_info->buf.st_mtime = time(NULL); + } else if(lstat(pathname, &inode_info->buf) == -1) { + char buffer[8192]; + sprintf(buffer, "Cannot stat dir/file %s, ignoring", pathname); + perror(buffer); + return; } + if(sorted) + sort_files_and_write(dir_info); + dir_scan2(inode, dir_info); } -squashfs_inode dir_scan(char *pathname, void* (_opendir)(char *, struct directory *), int (_readdir)(void *, char *, char *), - void (_closedir)(void *)) +struct dir_info *dir_scan1(char *pathname, int (_readdir)(char *, char *, struct dir_info *)) { - void *linuxdir; + struct dir_info *dir, *sub_dir; struct stat buf; char filename[8192], dir_name[8192]; - int squashfs_type; - squashfs_inode inode = SQUASHFS_INVALID; - struct directory dir; - - init_dir(&dir); - if((linuxdir = _opendir(pathname, &dir)) == NULL) { + + if((dir = scan1_opendir(pathname)) == NULL) { ERROR("Could not open %s, skipping...\n", pathname); goto error; } - - while(_readdir(linuxdir, filename, dir_name) != FALSE) { + + while(_readdir(filename, dir_name, dir) != FALSE) { + + if(strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0) + continue; if(lstat(filename, &buf) == -1) { char buffer[8192]; @@ -1293,75 +1585,135 @@ squashfs_inode dir_scan(char *pathname, void* (_opendir)(char *, struct director if(excluded(filename, &buf)) continue; - switch(buf.st_mode & S_IFMT) { - case S_IFREG: { - int duplicate_file; + if((buf.st_mode & S_IFMT) == S_IFDIR) { + if((sub_dir = dir_scan1(filename, scan1_readdir)) == NULL) + continue; + dir->directory_count ++; + } else + sub_dir = NULL; - squashfs_type = SQUASHFS_FILE_TYPE; - if(!sorted) { - inode = write_file(filename, buf.st_size, &duplicate_file); - INFO("file %s, uncompressed size %Ld bytes, %s\n", filename, buf.st_size, duplicate_file ? "DUPLICATE" : ""); - } else - inode = get_sorted_inode(&buf); - break; - } - case S_IFDIR: - squashfs_type = SQUASHFS_DIR_TYPE; - inode = dir_scan(filename, linux_opendir, linux_readdir, linux_closedir); - break; + add_dir_entry(dir_name, filename, sub_dir, lookup_inode(&buf), NULL, dir); + } - case S_IFLNK: - squashfs_type = SQUASHFS_SYMLINK_TYPE; - inode = create_inode(filename, squashfs_type, 0, 0, 0, NULL, NULL); - INFO("symbolic link %s inode 0x%Lx\n", dir_name, inode); - sym_count ++; - break; + scan1_freedir(dir); + sort_directory(dir); - case S_IFCHR: - squashfs_type = SQUASHFS_CHRDEV_TYPE; - inode = create_inode(filename, squashfs_type, 0, 0, 0, NULL, NULL); - INFO("character device %s inode 0x%Lx\n", dir_name, inode); - dev_count ++; - break; +error: + return dir; +} - case S_IFBLK: - squashfs_type = SQUASHFS_BLKDEV_TYPE; - inode = create_inode(filename, squashfs_type, 0, 0, 0, NULL, NULL); - INFO("block device %s inode 0x%Lx\n", dir_name, inode); - dev_count ++; - break; - case S_IFIFO: - squashfs_type = SQUASHFS_FIFO_TYPE; - inode = create_inode(filename, squashfs_type, 0, 0, 0, NULL, NULL); - INFO("fifo %s inode 0x%Lx\n", dir_name, inode); - fifo_count ++; - break; +int dir_scan2(squashfs_inode *inode, struct dir_info *dir_info) +{ + int squashfs_type; + int result = FALSE; + int duplicate_file; + char *pathname = dir_info->pathname; + struct directory dir; + struct dir_ent *dir_ent; + + scan2_init_dir(&dir); + + while((dir_ent = scan2_readdir(&dir, dir_info)) != NULL) { + struct inode_info *inode_info = dir_ent->inode; + struct stat *buf = &inode_info->buf; + char *filename = dir_ent->pathname; + char *dir_name = dir_ent->name; + unsigned int inode_number = ((buf->st_mode & S_IFMT) == S_IFDIR) ? dir_ent->inode->inode_number : dir_ent->inode->inode_number + dir_inode_no; + + if(dir_ent->inode->inode == SQUASHFS_INVALID_BLK) { + switch(buf->st_mode & S_IFMT) { + case S_IFREG: + squashfs_type = SQUASHFS_FILE_TYPE; + result = write_file(inode, dir_ent, buf->st_size, &duplicate_file); + INFO("file %s, uncompressed size %lld bytes %s\n", filename, buf->st_size, duplicate_file ? "DUPLICATE" : ""); + break; - case S_IFSOCK: - squashfs_type = SQUASHFS_SOCKET_TYPE; - inode = create_inode(filename, squashfs_type, 0, 0, 0, NULL, NULL); - INFO("unix domain socket %s inode 0x%Lx\n", dir_name, inode); - sock_count ++; - break; + case S_IFDIR: + squashfs_type = SQUASHFS_DIR_TYPE; + result = dir_scan2(inode, dir_ent->dir); + break; - default: - ERROR("%s unrecognised file type, mode is %x\n", filename, buf.st_mode); - continue; + case S_IFLNK: + squashfs_type = SQUASHFS_SYMLINK_TYPE; + result = create_inode(inode, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL); + INFO("symbolic link %s inode 0x%llx\n", dir_name, *inode); + sym_count ++; + break; + + case S_IFCHR: + squashfs_type = SQUASHFS_CHRDEV_TYPE; + result = create_inode(inode, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL); + INFO("character device %s inode 0x%llx\n", dir_name, *inode); + dev_count ++; + break; + + case S_IFBLK: + squashfs_type = SQUASHFS_BLKDEV_TYPE; + result = create_inode(inode, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL); + INFO("block device %s inode 0x%llx\n", dir_name, *inode); + dev_count ++; + break; + + case S_IFIFO: + squashfs_type = SQUASHFS_FIFO_TYPE; + result = create_inode(inode, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL); + INFO("fifo %s inode 0x%llx\n", dir_name, *inode); + fifo_count ++; + break; + + case S_IFSOCK: + squashfs_type = SQUASHFS_SOCKET_TYPE; + result = create_inode(inode, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL); + INFO("unix domain socket %s inode 0x%llx\n", dir_name, *inode); + sock_count ++; + break; + + default: + ERROR("%s unrecognised file type, mode is %x\n", filename, buf->st_mode); + result = FALSE; + } + if(result) + dir_ent->inode->inode = *inode; + dir_ent->inode->type = squashfs_type; + } else { + *inode = dir_ent->inode->inode; + squashfs_type = dir_ent->inode->type; + switch(squashfs_type) { + case SQUASHFS_FILE_TYPE: + if(!sorted) + INFO("file %s, uncompressed size %lld bytes LINK\n", filename, buf->st_size); + break; + case SQUASHFS_SYMLINK_TYPE: + INFO("symbolic link %s inode 0x%llx LINK\n", dir_name, *inode); + break; + case SQUASHFS_CHRDEV_TYPE: + INFO("character device %s inode 0x%llx LINK\n", dir_name, *inode); + break; + caseSQUASHFS_BLKDEV_TYPE: + INFO("block device %s inode 0x%llx LINK\n", dir_name, *inode); + break; + case SQUASHFS_FIFO_TYPE: + INFO("fifo %s inode 0x%llx LINK\n", dir_name, *inode); + break; + case SQUASHFS_SOCKET_TYPE: + INFO("unix domain socket %s inode 0x%llx LINK\n", dir_name, *inode); + break; } + result = TRUE; + } + - if(inode != SQUASHFS_INVALID) - add_dir(inode, dir_name, squashfs_type, &dir); + if(result) + add_dir(*inode, inode_number, dir_name, squashfs_type, &dir); } - _closedir(linuxdir); - inode = write_dir(pathname, &dir); - INFO("directory %s inode 0x%Lx\n", pathname, inode); + result = write_dir(inode, dir_info, &dir); + INFO("directory %s inode 0x%llx\n", pathname, *inode); -error: - free(dir.buff); + scan2_freedir(&dir); - return inode; + return result; } @@ -1369,7 +1721,7 @@ unsigned int slog(unsigned int block) { int i; - for(i = 9; i <= 16; i++) + for(i = 12; i <= 16; i++) if(block == (1 << i)) return i; return 0; @@ -1425,7 +1777,7 @@ int add_exclude(char *path) } -void add_old_root_entry(char *name, squashfs_inode inode, int type) +void add_old_root_entry(char *name, squashfs_inode inode, int inode_number, int type) { if((old_root_entry = (struct old_root_entry_info *) realloc(old_root_entry, sizeof(struct old_root_entry_info) * (old_root_entries + 1))) == NULL) @@ -1433,13 +1785,14 @@ void add_old_root_entry(char *name, squashfs_inode inode, int type) strcpy(old_root_entry[old_root_entries].name, name); old_root_entry[old_root_entries].inode = inode; + old_root_entry[old_root_entries].inode_number = inode_number; old_root_entry[old_root_entries++].type = type; } #define VERSION() \ - printf("mksquashfs version 2.0\n");\ - printf("copyright (C) 2004 Phillip Lougher (plougher@users.sourceforge.net)\n\n"); \ + printf("mksquashfs version 3.0 (2006/03/15)\n");\ + printf("copyright (C) 2006 Phillip Lougher <phillip@lougher.org.uk>\n\n"); \ printf("This program is free software; you can redistribute it and/or\n");\ printf("modify it under the terms of the GNU General Public License\n");\ printf("as published by the Free Software Foundation; either version 2,\n");\ @@ -1450,11 +1803,12 @@ void add_old_root_entry(char *name, squashfs_inode inode, int type) printf("GNU General Public License for more details.\n"); int main(int argc, char *argv[]) { - struct stat buf; + struct stat buf, source_buf; int i; squashfs_super_block sBlk; char *b, *root_name = NULL; - int be, nopad = FALSE, delete = FALSE, keep_as_directory = FALSE, orig_be; + int be, nopad = FALSE, keep_as_directory = FALSE, orig_be; + squashfs_inode inode; #if __BYTE_ORDER == __BIG_ENDIAN be = TRUE; @@ -1480,7 +1834,7 @@ int main(int argc, char *argv[]) } if((block_log = slog(block_size)) == 0) { - ERROR("%s: -b block size not power of two or not between 512 and 64K\n", argv[0]); + ERROR("%s: -b block size not power of two or not between 4096 and 64K\n", argv[0]); exit(1); } } else if(strcmp(argv[i], "-ef") == 0) { @@ -1591,40 +1945,51 @@ int main(int argc, char *argv[]) } else { ERROR("%s: invalid option\n\n", argv[0]); printOptions: - ERROR("SYNTAX:%s source1 source2 ... dest [options] [-e list of exclude dirs/files]\n", argv[0]); + ERROR("SYNTAX:%s source1 source2 ... dest [options] [-e list of exclude\ndirs/files]\n", argv[0]); ERROR("\nOptions are\n"); - ERROR("\t-info\t\t\t\tprint files written to filesystem\n"); - ERROR("\t-sort sort file\t\t\tsort files according to priorities in sort file. One file or dir\n"); - ERROR("\t\t\t\t\twith priority per line. Priority -32768 to 32767, default priority 0\n"); - ERROR("\t-b block size\t\t\tsize of blocks in "); - ERROR("filesystem, default %d\n", SQUASHFS_FILE_SIZE); - ERROR("\t-noappend\t\t\tDo not append to existing filesystem on dest, write a new filesystem\n"); - ERROR("\t\t\t\t\tThis is the default action if dest does not exist, or if no filesystem is on it\n"); - ERROR("\t-keep-as-directory\t\tIf one source directory is specified, create a root directory\n"); - ERROR("\t\t\t\t\tcontaining that directory, rather than the contents of the directory\n"); - ERROR("\t-root-becomes name\t\tWhen appending source files/directories, make the original\n"); - ERROR("\t\t\t\t\troot become a subdirectory in the new root called name, rather\n"); - ERROR("\t\t\t\t\tthan adding the new source items to the original root\n"); - ERROR("\t-noI -noInodeCompression\tdo not compress inode table\n"); - ERROR("\t-noD -noDataCompression\t\tdo not compress data blocks\n"); - ERROR("\t-noF -noFragmentCompression\tdo not compress fragment blocks\n"); - ERROR("\t-no-duplicates\t\t\tdo not perform duplicate checking\n"); - ERROR("\t-no-fragments\t\t\tdo not use fragments\n"); - ERROR("\t-always-use-fragments\t\tuse fragment blocks for files larger than block size\n"); - ERROR("\t-nopad\t\t\t\tdo not pad filesystem to a multiple of 4K\n"); - ERROR("\t-check_data\t\t\tadd checkdata for greater filesystem checks\n"); - ERROR("\t-le\t\t\t\tcreate a little endian filesystem\n"); - ERROR("\t-be\t\t\t\tcreate a big endian filesystem\n"); - ERROR("\t-ef exclude file\t\tfile is a list of exclude dirs/files - one per line\n"); - ERROR("\t-all-root\t\t\toverride file uid/gid and make all file uid/gids owned by root\n"); - ERROR("\t-root-owned\t\t\talternative name for -all-root\n"); - ERROR("\t-force-uid uid\t\t\tset all file uids to uid\n"); - ERROR("\t-force-gid gid\t\t\tset all file gids to gid\n"); - ERROR("\t-version\t\t\tprint version, licence and copyright message\n"); + ERROR("-version\t\tprint version, licence and copyright message\n"); + ERROR("-info\t\t\tprint files written to filesystem\n"); + ERROR("-b <block_size>\t\tset data block to <block_size>. Default %d bytes\n", SQUASHFS_FILE_SIZE); + ERROR("-noI\t\t\tdo not compress inode table\n"); + ERROR("-noD\t\t\tdo not compress data blocks\n"); + ERROR("-noF\t\t\tdo not compress fragment blocks\n"); + ERROR("-no-fragments\t\tdo not use fragments\n"); + ERROR("-always-use-fragments\tuse fragment blocks for files larger than block size\n"); + ERROR("-no-duplicates\t\tdo not perform duplicate checking\n"); + ERROR("-noappend\t\tdo not append to existing filesystem\n"); + ERROR("-keep-as-directory\tif one source directory is specified, create a root\n"); + ERROR("\t\t\tdirectory containing that directory, rather than the\n"); + ERROR("\t\t\tcontents of the directory\n"); + ERROR("-root-becomes <name>\twhen appending source files/directories, make the\n"); + ERROR("\t\t\toriginal root become a subdirectory in the new root\n"); + ERROR("\t\t\tcalled <name>, rather than adding the new source items\n"); + ERROR("\t\t\tto the original root\n"); + ERROR("-all-root\t\tmake all files owned by root\n"); + ERROR("-force-uid uid\t\tset all file uids to uid\n"); + ERROR("-force-gid gid\t\tset all file gids to gid\n"); + ERROR("-le\t\t\tcreate a little endian filesystem\n"); + ERROR("-be\t\t\tcreate a big endian filesystem\n"); + ERROR("-nopad\t\t\tdo not pad filesystem to a multiple of 4K\n"); + ERROR("-check_data\t\tadd checkdata for greater filesystem checks\n"); + ERROR("-root-owned\t\talternative name for -all-root\n"); + ERROR("-noInodeCompression\talternative name for -noI\n"); + ERROR("-noDataCompression\talternative name for -noD\n"); + ERROR("-noFragmentCompression\talternative name for -noF\n"); + ERROR("-sort <sort_file>\tsort files according to priorities in <sort_file>. One\n"); + ERROR("\t\t\tfile or dir with priority per line. Priority -32768 to\n"); + ERROR("\t\t\t32767, default priority 0\n"); + ERROR("-ef <exclude_file>\tlist of exclude dirs/files. One per line\n"); exit(1); } } + for(i = 0; i < source; i++) + if(stat(source_path[i], &source_buf) == -1) { + fprintf(stderr, "Cannot stat source directory \"%s\" because %s\n", source_path[i], strerror(errno)); + EXIT_MKSQUASHFS(); + } + + destination_file = argv[source + 1]; if(stat(argv[source + 1], &buf) == -1) { if(errno == ENOENT) { /* Does not exist */ if((fd = open(argv[source + 1], O_CREAT | O_TRUNC | O_RDWR, S_IRWXU)) == -1) { @@ -1656,19 +2021,16 @@ printOptions: exit(1); } - if(!delete) { - if(read_super(fd, &sBlk, &orig_be, argv[source + 1]) == 0) { - if(S_ISREG(buf.st_mode)) { /* reopen truncating file */ - close(fd); - if((fd = open(argv[source + 1], O_TRUNC | O_RDWR)) == -1) { - perror("Could not open regular file for writing as destination"); - exit(1); - } - } - delete = TRUE; - } + } + if(!delete) { + if(read_super(fd, &sBlk, &orig_be, argv[source + 1]) == 0) { + ERROR("Failed to read existing filesystem - will not overwrite - ABORTING!\n"); + EXIT_MKSQUASHFS(); } + } else { + signal(SIGTERM, sighandler2); + signal(SIGINT, sighandler2); } /* process the exclude files - must be done afer destination file has been possibly created */ @@ -1678,7 +2040,7 @@ printOptions: char filename[16385]; if((fd = fopen(argv[++i], "r")) == NULL) { perror("Could not open exclude file..."); - exit(1); + EXIT_MKSQUASHFS(); } while(fscanf(fd, "%16384[^\n]\n", filename) != EOF) add_exclude(filename); @@ -1691,7 +2053,7 @@ printOptions: if(i != argc) { if(++i == argc) { ERROR("%s: -e missing arguments\n", argv[0]); - exit(1); + EXIT_MKSQUASHFS(); } while(i < argc && add_exclude(argv[i++])); } @@ -1706,14 +2068,17 @@ printOptions: else if(strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "-root-becomes") == 0 || strcmp(argv[i], "-ef") == 0) i++; - if((fragment_data = (char *) malloc(block_size)) == NULL) - BAD_ERROR("Out of memory allocating fragment_data"); - if(delete) { - printf("Creating %s filesystem on %s, block size %d.\n", - be ? "big endian" : "little endian", argv[source + 1], block_size); + printf("Creating %s %d.%d filesystem on %s, block size %d.\n", + be ? "big endian" : "little endian", SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1], block_size); bytes = sizeof(squashfs_super_block); } else { + unsigned int last_directory_block, inode_dir_offset, inode_dir_file_size, root_inode_size, + inode_dir_start_block, uncompressed_data, compressed_data, inode_dir_inode_number, + inode_dir_parent_inode; + unsigned int root_inode_start = SQUASHFS_INODE_BLK(sBlk.root_inode), root_inode_offset = + SQUASHFS_INODE_OFFSET(sBlk.root_inode); + be = orig_be; block_log = slog(block_size = sBlk.block_size); noI = SQUASHFS_UNCOMPRESSED_INODES(sBlk.flags); @@ -1724,47 +2089,48 @@ printOptions: always_use_fragments = SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags); duplicate_checking = SQUASHFS_DUPLICATES(sBlk.flags); - fragments = SQUASHFS_INVALID_BLK; - if((bytes = read_filesystem(root_name, fd, &sBlk, &inode_table, &inode_bytes, &data_cache, - &cache_bytes, &cache_size, &directory_table, &directory_bytes, - &directory_data_cache, &directory_cache_bytes, &directory_cache_size, - &file_count, &sym_count, &dev_count, &dir_count, &fifo_count, &sock_count, (squashfs_uid *) uids, &uid_count, - (squashfs_uid *) guids, &guid_count, - &total_bytes, &total_inode_bytes, &total_directory_bytes, add_old_root_entry, &fragment_table)) == 0) { + if((bytes = read_filesystem(root_name, fd, &sBlk, &inode_table, &data_cache, + &directory_table, &directory_data_cache, &last_directory_block, &inode_dir_offset, + &inode_dir_file_size, &root_inode_size, &inode_dir_start_block, + &file_count, &sym_count, &dev_count, &dir_count, &fifo_count, &sock_count, + (squashfs_uid *) uids, &uid_count, (squashfs_uid *) guids, &guid_count, + &total_bytes, &total_inode_bytes, &total_directory_bytes, &inode_dir_inode_number, + &inode_dir_parent_inode, add_old_root_entry, &fragment_table)) == 0) { ERROR("Failed to read existing filesystem - will not overwrite - ABORTING!\n"); - exit(1); + EXIT_MKSQUASHFS(); } if((fragments = sBlk.fragments)) fragment_table = (squashfs_fragment_entry *) realloc((char *) fragment_table, ((fragments + FRAG_SIZE - 1) & ~(FRAG_SIZE - 1)) * sizeof(squashfs_fragment_entry)); - printf("Appending to existing %s squashfs filesystem on %s, block size %d\n", be ? "big endian" : - "little endian", argv[source + 1], block_size); - printf("All -be, -le, -b, -noI, noD, noF, -check_data, no-duplicates, no-fragments and always-use-fragments options ignored\n"); + printf("Appending to existing %s %d.%d filesystem on %s, block size %d\n", be ? "big endian" : + "little endian", SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1], block_size); + printf("All -be, -le, -b, -noI, -noD, -noF, -check_data, no-duplicates, no-fragments, -always-use-fragments and -2.0 options ignored\n"); printf("\nIf appending is not wanted, please re-run with -noappend specified!\n\n"); - inode_size = inode_bytes; - directory_size = directory_bytes; - + compressed_data = inode_dir_offset + inode_dir_file_size & ~(SQUASHFS_METADATA_SIZE - 1); + uncompressed_data = inode_dir_offset + inode_dir_file_size & (SQUASHFS_METADATA_SIZE - 1); + /* save original filesystem state for restoring ... */ sfragments = fragments; sbytes = bytes; sinode_count = sBlk.inodes; - inode_count = file_count + dir_count + sym_count + dev_count; - sdata_cache = (char *)malloc(scache_bytes = cache_size); - sdirectory_data_cache = (char *)malloc(sdirectory_cache_bytes = directory_cache_size); + sdata_cache = (char *)malloc(scache_bytes = root_inode_offset + root_inode_size); + sdirectory_data_cache = (char *)malloc(sdirectory_cache_bytes = uncompressed_data); memcpy(sdata_cache, data_cache, scache_bytes); - memcpy(sdirectory_data_cache, directory_data_cache, sdirectory_cache_bytes); - sinode_bytes = inode_bytes; - sdirectory_bytes = directory_bytes; + memcpy(sdirectory_data_cache, directory_data_cache + compressed_data, sdirectory_cache_bytes); + sinode_bytes = root_inode_start; + sdirectory_bytes = last_directory_block; suid_count = uid_count; sguid_count = guid_count; stotal_bytes = total_bytes; stotal_inode_bytes = total_inode_bytes; - stotal_directory_bytes = total_directory_bytes; + stotal_directory_bytes = total_directory_bytes + compressed_data; sfile_count = file_count; ssym_count = sym_count; sdev_count = dev_count; - sdir_count = dir_count; + sdir_count = dir_count + 1; + sfifo_count = fifo_count; + ssock_count = sock_count; sdup_files = dup_files; restore = TRUE; if(setjmp(env)) @@ -1772,6 +2138,34 @@ printOptions: signal(SIGTERM, sighandler); signal(SIGINT, sighandler); write_bytes(fd, SQUASHFS_START, 4, "\0\0\0\0"); + + /* set the filesystem state up to be able to append to the original filesystem. The filesystem state + * differs depending on whether we're appending to the original root directory, or if the original + * root directory becomes a sub-directory (root-becomes specified on command line, here root_name != NULL) + */ + inode_bytes = inode_size = root_inode_start; + directory_size = last_directory_block; + cache_size = root_inode_offset + root_inode_size; + directory_cache_size = inode_dir_offset + inode_dir_file_size; + if(root_name) { + root_inode_number = inode_dir_parent_inode; + dir_inode_no = sBlk.inodes + 2; + directory_bytes = last_directory_block; + directory_cache_bytes = uncompressed_data; + memmove(directory_data_cache, directory_data_cache + compressed_data, uncompressed_data); + cache_bytes = root_inode_offset + root_inode_size; + add_old_root_entry(root_name, sBlk.root_inode, inode_dir_inode_number, SQUASHFS_DIR_TYPE); + total_directory_bytes += compressed_data; + dir_count ++; + } else { + root_inode_number = inode_dir_inode_number; + dir_inode_no = sBlk.inodes + 1; + directory_bytes = inode_dir_start_block; + directory_cache_bytes = inode_dir_offset; + cache_bytes = root_inode_offset; + } + + inode_count = file_count + dir_count + sym_count + dev_count + fifo_count + sock_count; } #if __BYTE_ORDER == __BIG_ENDIAN @@ -1782,20 +2176,13 @@ printOptions: block_offset = check_data ? 3 : 2; - if(stat(source_path[0], &buf) == -1) { - perror("Cannot stat source directory"); - EXIT_MKSQUASHFS(); - } - - if(sorted) - sort_files_and_write(source, source_path); - - if(delete && !keep_as_directory && source == 1 && S_ISDIR(buf.st_mode)) - sBlk.root_inode = dir_scan(source_path[0], linux_opendir, linux_readdir, linux_closedir); - else if(!keep_as_directory && source == 1 && S_ISDIR(buf.st_mode)) - sBlk.root_inode = dir_scan(source_path[0], single_opendir, single_readdir, linux_closedir); + if(delete && !keep_as_directory && source == 1 && S_ISDIR(source_buf.st_mode)) + dir_scan(&inode, source_path[0], scan1_readdir); + else if(!keep_as_directory && source == 1 && S_ISDIR(source_buf.st_mode)) + dir_scan(&inode, source_path[0], scan1_single_readdir); else - sBlk.root_inode = dir_scan("", encomp_opendir, encomp_readdir, encomp_closedir); + dir_scan(&inode, "", scan1_encomp_readdir); + sBlk.root_inode = inode; sBlk.inodes = inode_count; sBlk.s_magic = SQUASHFS_MAGIC; sBlk.s_major = SQUASHFS_MAJOR; @@ -1846,6 +2233,8 @@ restore_filesystem: sBlk.bytes_used = bytes; + sBlk.unused = SQUASHFS_INVALID_BLK; + if(!swap) write_bytes(fd, SQUASHFS_START, sizeof(squashfs_super_block), (char *) &sBlk); else { @@ -1856,7 +2245,7 @@ restore_filesystem: } if(!nopad && (i = bytes & (4096 - 1))) { - unsigned char temp[4096] = {0}; + char temp[4096] = {0}; write_bytes(fd, bytes, 4096 - i, temp); } @@ -1865,7 +2254,7 @@ restore_filesystem: sizeof(squashfs_super_block); printf("\n%s filesystem, data block size %d, %s data, %s metadata, %s fragments\n", be ? - "Big endian" : "Little endian", block_size, noI ? "uncompressed" : "compressed", noD ? + "Big endian" : "Little endian", block_size, noD ? "uncompressed" : "compressed", noI ? "uncompressed" : "compressed", no_fragments ? "no" : noF ? "uncompressed" : "compressed"); printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n", bytes / 1024.0, bytes / (1024.0 * 1024.0)); printf("\t%.2f%% of uncompressed filesystem size (%.2f Kbytes)\n", diff --git a/release/src/linux/linux/scripts/squashfs/mksquashfs.h b/release/src/linux/linux/scripts/squashfs/mksquashfs.h index b3d2e441..680bb388 100644 --- a/release/src/linux/linux/scripts/squashfs/mksquashfs.h +++ b/release/src/linux/linux/scripts/squashfs/mksquashfs.h @@ -3,7 +3,8 @@ * endian and vice versa. These are needed when creating a filesystem on a * machine with different byte ordering to the target architecture. * - * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.net> + * Copyright (c) 2002, 2003, 2004, 2005, 2006 + * Phillip Lougher <phillip@lougher.demon.co.uK> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/release/src/linux/linux/scripts/squashfs/read_fs.c b/release/src/linux/linux/scripts/squashfs/read_fs.c index cdb62a75..46f4a4e4 100644 --- a/release/src/linux/linux/scripts/squashfs/read_fs.c +++ b/release/src/linux/linux/scripts/squashfs/read_fs.c @@ -1,7 +1,8 @@ /* * Read a squashfs filesystem. This is a highly compressed read only filesystem. * - * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.net> + * Copyright (c) 2002, 2003, 2004, 2005, 2006 + * Phillip Lougher <phillip@lougher.org.uk> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,8 +21,8 @@ * read_fs.c */ -extern void read_bytes(int, unsigned int, int, char *); -extern int add_file(int, int, unsigned int *, int, unsigned int, int, int); +extern void read_bytes(int, long long, int, char *); +extern int add_file(long long, long long, unsigned int *, int, unsigned int, int, int); #define TRUE 1 #define FALSE 0 @@ -34,29 +35,41 @@ extern int add_file(int, int, unsigned int *, int, unsigned int, int, int); #include <zlib.h> #include <sys/mman.h> +#ifndef linux +#define __BYTE_ORDER BYTE_ORDER +#define __BIG_ENDIAN BIG_ENDIAN +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#else #include <endian.h> -#include "read_fs.h" +#endif + #include <squashfs_fs.h> +#include "read_fs.h" +#include "global.h" #include <stdlib.h> #ifdef SQUASHFS_TRACE -#define TRACE(s, args...) printf("mksquashfs: "s, ## args) +#define TRACE(s, args...) do { \ + printf("mksquashfs: "s, ## args); \ + } while(0) #else #define TRACE(s, args...) #endif -#define ERROR(s, args...) fprintf(stderr, s, ## args) +#define ERROR(s, args...) do { \ + fprintf(stderr, s, ## args); \ + } while(0) int swap; -int read_block(int fd, int start, int *next, unsigned char *block, squashfs_super_block *sBlk) +int read_block(int fd, long long start, long long *next, unsigned char *block, squashfs_super_block *sBlk) { unsigned short c_byte; int offset = 2; if(swap) { - read_bytes(fd, start, 2, block); + read_bytes(fd, start, 2, (char *) block); ((unsigned char *) &c_byte)[1] = block[0]; ((unsigned char *) &c_byte)[0] = block[1]; } else @@ -65,14 +78,14 @@ int read_block(int fd, int start, int *next, unsigned char *block, squashfs_supe if(SQUASHFS_CHECK_DATA(sBlk->flags)) offset = 3; if(SQUASHFS_COMPRESSED(c_byte)) { - unsigned char buffer[SQUASHFS_METADATA_SIZE]; + char buffer[SQUASHFS_METADATA_SIZE]; int res; - long bytes = SQUASHFS_METADATA_SIZE; + unsigned long bytes = SQUASHFS_METADATA_SIZE; c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); read_bytes(fd, start + offset, c_byte, buffer); - if((res = uncompress(block, &bytes, (const char *) buffer, c_byte)) != Z_OK) { + if((res = uncompress(block, &bytes, (const unsigned char *) buffer, c_byte)) != Z_OK) { if(res == Z_MEM_ERROR) ERROR("zlib::uncompress failed, not enough memory\n"); else if(res == Z_BUF_ERROR) @@ -86,7 +99,7 @@ int read_block(int fd, int start, int *next, unsigned char *block, squashfs_supe return bytes; } else { c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); - read_bytes(fd, start + offset, c_byte, block); + read_bytes(fd, start + offset, c_byte, (char *) block); if(next) *next = start + offset + c_byte; return c_byte; @@ -94,30 +107,32 @@ int read_block(int fd, int start, int *next, unsigned char *block, squashfs_supe } -int scan_inode_table(int fd, int start, int end, int root_inode_start, squashfs_super_block *sBlk, - squashfs_dir_inode_header *dir_inode, unsigned char **inode_table, unsigned int *root_inode_block, - unsigned int *uncompressed_file, unsigned int *uncompressed_directory, int *file_count, int *sym_count, - int *dev_count, int *dir_count, int *fifo_count, int *sock_count) +int scan_inode_table(int fd, long long start, long long end, long long root_inode_start, int root_inode_offset, + squashfs_super_block *sBlk, + squashfs_inode_header *dir_inode, unsigned char **inode_table, unsigned int *root_inode_block, + unsigned int *root_inode_size, long long *uncompressed_file, unsigned int *uncompressed_directory, + int *file_count, int *sym_count, int *dev_count, int *dir_count, int *fifo_count, int *sock_count) { unsigned char *cur_ptr; - int bytes = 0, size = 0, files = 0; + int byte, bytes = 0, size = 0, files = 0; squashfs_reg_inode_header inode; unsigned int directory_start_block; - TRACE("scan_inode_table: start 0x%x, end 0x%x, root_inode_start 0x%x\n", start, end, root_inode_start); + TRACE("scan_inode_table: start 0x%llx, end 0x%llx, root_inode_start 0x%llx\n", start, end, root_inode_start); while(start < end) { if(start == root_inode_start) { - TRACE("scan_inode_table: read compressed block 0x%x containing root inode\n", start); + TRACE("scan_inode_table: read compressed block 0x%llx containing root inode\n", start); *root_inode_block = bytes; } if((size - bytes < SQUASHFS_METADATA_SIZE) && ((*inode_table = realloc(*inode_table, size += SQUASHFS_METADATA_SIZE)) == NULL)) return FALSE; - TRACE("scan_inode_table: reading block 0x%x\n", start); - if((bytes += read_block(fd, start, &start, *inode_table + bytes, sBlk)) == 0) { + TRACE("scan_inode_table: reading block 0x%llx\n", start); + if((byte = read_block(fd, start, &start, *inode_table + bytes, sBlk)) == 0) { free(*inode_table); return FALSE; } + bytes += byte; } /* @@ -128,43 +143,112 @@ int scan_inode_table(int fd, int start, int end, int root_inode_start, squashfs_ * The root inode is ignored in the inode scan. This ensures there is * always enough bytes left to read a regular file inode entry */ - bytes -= sizeof(squashfs_dir_inode_header); + *root_inode_size = bytes - (*root_inode_block + root_inode_offset); + bytes = *root_inode_block + root_inode_offset; if(swap) { - squashfs_dir_inode_header sinode; - memcpy((void *)&sinode, (void *)(*inode_table + bytes), sizeof(*dir_inode)); - SQUASHFS_SWAP_DIR_INODE_HEADER(dir_inode, &sinode); + squashfs_base_inode_header sinode; + memcpy(&sinode, *inode_table + bytes, sizeof(dir_inode->base)); + SQUASHFS_SWAP_BASE_INODE_HEADER(&dir_inode->base, &sinode, sizeof(squashfs_base_inode_header)); } else - memcpy((void *)dir_inode, (void *)(*inode_table + bytes), sizeof(*dir_inode)); - directory_start_block = dir_inode->start_block; + memcpy(&dir_inode->base, *inode_table + bytes, sizeof(dir_inode->base)); + if(dir_inode->base.inode_type == SQUASHFS_DIR_TYPE) { + if(swap) { + squashfs_dir_inode_header sinode; + memcpy(&sinode, *inode_table + bytes, sizeof(dir_inode->dir)); + SQUASHFS_SWAP_DIR_INODE_HEADER(&dir_inode->dir, &sinode); + } else + memcpy(&dir_inode->dir, *inode_table + bytes, sizeof(dir_inode->dir)); + directory_start_block = dir_inode->dir.start_block; + } else { + if(swap) { + squashfs_ldir_inode_header sinode; + memcpy(&sinode, *inode_table + bytes, sizeof(dir_inode->ldir)); + SQUASHFS_SWAP_LDIR_INODE_HEADER(&dir_inode->ldir, &sinode); + } else + memcpy(&dir_inode->ldir, *inode_table + bytes, sizeof(dir_inode->ldir)); + directory_start_block = dir_inode->ldir.start_block; + } for(cur_ptr = *inode_table; cur_ptr < *inode_table + bytes; files ++) { if(swap) { squashfs_reg_inode_header sinode; - memcpy((void *)&sinode, (void *)cur_ptr, sizeof(inode)); + memcpy(&sinode, cur_ptr, sizeof(inode)); SQUASHFS_SWAP_REG_INODE_HEADER(&inode, &sinode); } else - memcpy((void *)&inode, (void *)cur_ptr, sizeof(inode)); + memcpy(&inode, cur_ptr, sizeof(inode)); TRACE("scan_inode_table: processing inode @ byte position 0x%x, type 0x%x\n", cur_ptr - *inode_table, inode.inode_type); switch(inode.inode_type) { case SQUASHFS_FILE_TYPE: { - int frag_bytes = inode.fragment == SQUASHFS_INVALID_BLK ? 0 : inode.file_size % sBlk->block_size; - int blocks = inode.fragment == SQUASHFS_INVALID_BLK ? (inode.file_size + int frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ? 0 : inode.file_size % sBlk->block_size; + int blocks = inode.fragment == SQUASHFS_INVALID_FRAG ? (inode.file_size + sBlk->block_size - 1) >> sBlk->block_log : inode.file_size >> sBlk->block_log; - int file_bytes = 0, i, start = inode.start_block; - unsigned int block_list[blocks]; + long long file_bytes = 0; + int i, start = inode.start_block; + unsigned int *block_list; + + TRACE("scan_inode_table: regular file, file_size %lld, blocks %d\n", inode.file_size, blocks); + + if((block_list = malloc(blocks * sizeof(unsigned int))) == NULL) { + ERROR("Out of memory in block list malloc\n"); + goto failed; + } + + cur_ptr += sizeof(inode); + if(swap) { + unsigned int sblock_list[blocks]; + memcpy(sblock_list, cur_ptr, blocks * sizeof(unsigned int)); + SQUASHFS_SWAP_INTS(block_list, sblock_list, blocks); + } else + memcpy(block_list, cur_ptr, blocks * sizeof(unsigned int)); + + *uncompressed_file += inode.file_size; + (*file_count) ++; + + for(i = 0; i < blocks; i++) + file_bytes += SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]); + + add_file(start, file_bytes, block_list, blocks, inode.fragment, inode.offset, frag_bytes); + cur_ptr += blocks * sizeof(unsigned int); + break; + } + case SQUASHFS_LREG_TYPE: { + squashfs_lreg_inode_header inode; + int frag_bytes; + int blocks; + long long file_bytes = 0; + int i, start; + unsigned int *block_list; - TRACE("scan_inode_table: regular file, file_size %d, blocks %d\n", inode.file_size, blocks); + if(swap) { + squashfs_lreg_inode_header sinodep; + memcpy(&sinodep, cur_ptr, sizeof(sinodep)); + SQUASHFS_SWAP_LREG_INODE_HEADER(&inode, &sinodep); + } else + memcpy(&inode, cur_ptr, sizeof(inode)); + + TRACE("scan_inode_table: extended regular file, file_size %lld, blocks %d\n", inode.file_size, blocks); cur_ptr += sizeof(inode); + frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ? 0 : inode.file_size % sBlk->block_size; + blocks = inode.fragment == SQUASHFS_INVALID_FRAG ? (inode.file_size + + sBlk->block_size - 1) >> sBlk->block_log : inode.file_size >> + sBlk->block_log; + start = inode.start_block; + + if((block_list = malloc(blocks * sizeof(unsigned int))) == NULL) { + ERROR("Out of memory in block list malloc\n"); + goto failed; + } + if(swap) { unsigned int sblock_list[blocks]; - memcpy((void *)sblock_list, (void *)cur_ptr, blocks * sizeof(unsigned int)); + memcpy(sblock_list, cur_ptr, blocks * sizeof(unsigned int)); SQUASHFS_SWAP_INTS(block_list, sblock_list, blocks); } else - memcpy((void *)block_list, (void *)cur_ptr, blocks * sizeof(unsigned int)); + memcpy(block_list, cur_ptr, blocks * sizeof(unsigned int)); *uncompressed_file += inode.file_size; (*file_count) ++; @@ -181,10 +265,10 @@ int scan_inode_table(int fd, int start, int end, int root_inode_start, squashfs_ if(swap) { squashfs_symlink_inode_header sinodep; - memcpy((void *)&sinodep, (void *)cur_ptr, sizeof(sinodep)); + memcpy(&sinodep, cur_ptr, sizeof(sinodep)); SQUASHFS_SWAP_SYMLINK_INODE_HEADER(&inodep, &sinodep); } else - memcpy((void *)&inodep, (void *)cur_ptr, sizeof(inodep)); + memcpy(&inodep, cur_ptr, sizeof(inodep)); (*sym_count) ++; cur_ptr += sizeof(inodep) + inodep.symlink_size; break; @@ -194,16 +278,42 @@ int scan_inode_table(int fd, int start, int end, int root_inode_start, squashfs_ if(swap) { squashfs_dir_inode_header sinode; - memcpy((void *)&sinode, (void *)cur_ptr, sizeof(dir_inode)); + memcpy(&sinode, cur_ptr, sizeof(dir_inode)); SQUASHFS_SWAP_DIR_INODE_HEADER(&dir_inode, &sinode); } else - memcpy((void *)&dir_inode, (void *)cur_ptr, sizeof(dir_inode)); + memcpy(&dir_inode, cur_ptr, sizeof(dir_inode)); if(dir_inode.start_block < directory_start_block) *uncompressed_directory += dir_inode.file_size; (*dir_count) ++; cur_ptr += sizeof(squashfs_dir_inode_header); break; } + case SQUASHFS_LDIR_TYPE: { + squashfs_ldir_inode_header dir_inode; + int i; + + if(swap) { + squashfs_ldir_inode_header sinode; + memcpy(&sinode, cur_ptr, sizeof(dir_inode)); + SQUASHFS_SWAP_LDIR_INODE_HEADER(&dir_inode, &sinode); + } else + memcpy(&dir_inode, cur_ptr, sizeof(dir_inode)); + if(dir_inode.start_block < directory_start_block) + *uncompressed_directory += dir_inode.file_size; + (*dir_count) ++; + cur_ptr += sizeof(squashfs_ldir_inode_header); + for(i = 0; i < dir_inode.i_count; i++) { + squashfs_dir_index index; + if(swap) { + squashfs_dir_index sindex; + memcpy(&sindex, cur_ptr, sizeof(squashfs_dir_index)); + SQUASHFS_SWAP_DIR_INDEX(&index, &sindex); + } else + memcpy(&index, cur_ptr, sizeof(squashfs_dir_index)); + cur_ptr += sizeof(squashfs_dir_index) + index.size + 1; + } + break; + } case SQUASHFS_BLKDEV_TYPE: case SQUASHFS_CHRDEV_TYPE: (*dev_count) ++; @@ -220,12 +330,16 @@ int scan_inode_table(int fd, int start, int end, int root_inode_start, squashfs_ break; default: ERROR("Unknown inode type %d in scan_inode_table!\n", inode.inode_type); - free(*inode_table); - return FALSE; + goto failed; } } return files; + + +failed: + free(*inode_table); + return FALSE; } @@ -250,11 +364,11 @@ int read_super(int fd, squashfs_super_block *sBlk, int *be, char *source) /* Check the MAJOR & MINOR versions */ if(sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) { - if(sBlk->s_major == 1) - ERROR("Filesystem on %s is a SQUASHFS 1.x filesystem. Appending\nto SQUASHFS 1.x filesystems is not supported. Please convert it to a SQUASHFS 2.0 filesystem...n", source); + if(sBlk->s_major < 3) + ERROR("Filesystem on %s is a SQUASHFS %d.%d filesystem. Appending\nto SQUASHFS %d.%d filesystems is not supported. Please convert it to a SQUASHFS 3.0 filesystem\n", source, sBlk->s_major, sBlk->s_minor, sBlk->s_major, sBlk->s_minor); else - ERROR("Major/Minor mismatch, filesystem on %s is (%d:%d), I support (%d: <= %d)\n", - source, sBlk->s_major, sBlk->s_minor, SQUASHFS_MAJOR, SQUASHFS_MINOR); + ERROR("Major/Minor mismatch, filesystem on %s is %d.%d, I support 3.0\n", + source, sBlk->s_major, sBlk->s_minor); goto failed_mount; } @@ -272,16 +386,16 @@ int read_super(int fd, squashfs_super_block *sBlk, int *be, char *source) printf("\tFragments are %s present in the filesystem\n", SQUASHFS_NO_FRAGMENTS(sBlk->flags) ? "not" : ""); printf("\tAlways_use_fragments option is %s specified\n", SQUASHFS_ALWAYS_FRAGMENTS(sBlk->flags) ? "" : "not"); printf("\tDuplicates are %s removed\n", SQUASHFS_DUPLICATES(sBlk->flags) ? "" : "not"); - printf("\tFilesystem size %d bytes\n", sBlk->bytes_used); + printf("\tFilesystem size %.2f Kbytes (%.2f Mbytes)\n", sBlk->bytes_used / 1024.0, sBlk->bytes_used / (1024.0 * 1024.0)); printf("\tBlock size %d\n", sBlk->block_size); printf("\tNumber of fragments %d\n", sBlk->fragments); printf("\tNumber of inodes %d\n", sBlk->inodes); printf("\tNumber of uids %d\n", sBlk->no_uids); printf("\tNumber of gids %d\n", sBlk->no_guids); - TRACE("sBlk->inode_table_start %x\n", sBlk->inode_table_start); - TRACE("sBlk->directory_table_start %x\n", sBlk->directory_table_start); - TRACE("sBlk->uid_start %x\n", sBlk->uid_start); - TRACE("sBlk->fragment_table_start %x\n", sBlk->fragment_table_start); + TRACE("sBlk->inode_table_start %llx\n", sBlk->inode_table_start); + TRACE("sBlk->directory_table_start %llx\n", sBlk->directory_table_start); + TRACE("sBlk->uid_start %llx\n", sBlk->uid_start); + TRACE("sBlk->fragment_table_start %llx\n", sBlk->fragment_table_start); printf("\n"); return TRUE; @@ -291,24 +405,27 @@ failed_mount: } -unsigned char *squashfs_readdir(int fd, int root_entries, int start, int offset, int size, squashfs_super_block *sBlk, - void (push_directory_entry)(char *, squashfs_inode, int)) +unsigned char *squashfs_readdir(int fd, int root_entries, unsigned int directory_start_block, int offset, int size, + unsigned int *last_directory_block, squashfs_super_block *sBlk, void (push_directory_entry)(char *, squashfs_inode, int, int)) { squashfs_dir_header dirh; char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1]; squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer; unsigned char *directory_table = NULL; - int bytes = 0, dir_count; + int byte, bytes = 0, dir_count; + long long start = sBlk->directory_table_start + directory_start_block, last_start_block; size += offset; if((directory_table = malloc((size + SQUASHFS_METADATA_SIZE * 2 - 1) & ~(SQUASHFS_METADATA_SIZE - 1))) == NULL) return NULL; while(bytes < size) { - TRACE("squashfs_readdir: reading block 0x%x, bytes read so far %d\n", start, bytes); - if((bytes += read_block(fd, start, &start, directory_table + bytes, sBlk)) == 0) { + TRACE("squashfs_readdir: reading block 0x%llx, bytes read so far %d\n", start, bytes); + last_start_block = start; + if((byte = read_block(fd, start, &start, directory_table + bytes, sBlk)) == 0) { free(directory_table); return NULL; } + bytes += byte; } if(!root_entries) @@ -318,10 +435,10 @@ unsigned char *squashfs_readdir(int fd, int root_entries, int start, int offset, while(bytes < size) { if(swap) { squashfs_dir_header sdirh; - memcpy((void *)&sdirh, directory_table + bytes, sizeof(sdirh)); + memcpy(&sdirh, directory_table + bytes, sizeof(sdirh)); SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); } else - memcpy((void *)&dirh, directory_table + bytes, sizeof(dirh)); + memcpy(&dirh, directory_table + bytes, sizeof(dirh)); dir_count = dirh.count + 1; TRACE("squashfs_readdir: Read directory header @ byte position 0x%x, 0x%x directory entries\n", bytes, dir_count); @@ -330,21 +447,22 @@ unsigned char *squashfs_readdir(int fd, int root_entries, int start, int offset, while(dir_count--) { if(swap) { squashfs_dir_entry sdire; - memcpy((void *)&sdire, directory_table + bytes, sizeof(sdire)); + memcpy(&sdire, directory_table + bytes, sizeof(sdire)); SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); } else - memcpy((void *)dire, directory_table + bytes, sizeof(dire)); + memcpy(dire, directory_table + bytes, sizeof(dire)); bytes += sizeof(*dire); - memcpy((void *)dire->name, directory_table + bytes, dire->size + 1); + memcpy(dire->name, directory_table + bytes, dire->size + 1); dire->name[dire->size + 1] = '\0'; TRACE("squashfs_readdir: pushing directory entry %s, inode %x:%x, type 0x%x\n", dire->name, dirh.start_block, dire->offset, dire->type); - push_directory_entry(dire->name, SQUASHFS_MKINODE(dirh.start_block, dire->offset), dire->type); + push_directory_entry(dire->name, SQUASHFS_MKINODE(dirh.start_block, dire->offset), dire->inode_number, dire->type); bytes += dire->size + 1; } } all_done: + *last_directory_block = (unsigned int) last_start_block - sBlk->directory_table_start; return directory_table; } @@ -354,7 +472,7 @@ int read_fragment_table(int fd, squashfs_super_block *sBlk, squashfs_fragment_en int i, indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk->fragments); squashfs_fragment_index fragment_table_index[indexes]; - TRACE("read_fragment_table: %d fragments, reading %d fragment indexes from 0x%x\n", sBlk->fragments, indexes, sBlk->fragment_table_start); + TRACE("read_fragment_table: %d fragments, reading %d fragment indexes from 0x%llx\n", sBlk->fragments, indexes, sBlk->fragment_table_start); if(sBlk->fragments == 0) return 1; @@ -372,11 +490,10 @@ int read_fragment_table(int fd, squashfs_super_block *sBlk, squashfs_fragment_en read_bytes(fd, sBlk->fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), (char *) fragment_table_index); for(i = 0; i < indexes; i++) { - int length = read_block(fd, fragment_table_index[i], NULL, ((char *) *fragment_table) + (i * SQUASHFS_METADATA_SIZE), sBlk); - TRACE("Read fragment table block %d, from 0x%x, length %d\n", i, fragment_table_index[i], length); + int length = read_block(fd, fragment_table_index[i], NULL, ((unsigned char *) *fragment_table) + (i * SQUASHFS_METADATA_SIZE), sBlk); + TRACE("Read fragment table block %d, from 0x%llx, length %d\n", i, fragment_table_index[i], length); } - if(swap) { squashfs_fragment_entry sfragment; for(i = 0; i < sBlk->fragments; i++) { @@ -389,29 +506,30 @@ int read_fragment_table(int fd, squashfs_super_block *sBlk, squashfs_fragment_en } -int read_filesystem(char *root_name, int fd, squashfs_super_block *sBlk, char **cinode_table, int *inode_bytes, - char **data_cache, int *cache_bytes, int *cache_size, - char **cdirectory_table, int *directory_bytes, - char **directory_data_cache, int *directory_cache_bytes, int *directory_cache_size, - int *file_count, int *sym_count, int *dev_count, int *dir_count, int *fifo_count, int *sock_count, - squashfs_uid *uids, unsigned short *uid_count, squashfs_uid *guids, unsigned short *guid_count, - unsigned int *uncompressed_file, unsigned int *uncompressed_inode, unsigned int *uncompressed_directory, - void (push_directory_entry)(char *, squashfs_inode, int), squashfs_fragment_entry **fragment_table) +long long read_filesystem(char *root_name, int fd, squashfs_super_block *sBlk, char **cinode_table, + char **data_cache, char **cdirectory_table, char **directory_data_cache, + unsigned int *last_directory_block, unsigned int *inode_dir_offset, unsigned int *inode_dir_file_size, + unsigned int *root_inode_size, unsigned int *inode_dir_start_block, int *file_count, int *sym_count, + int *dev_count, int *dir_count, int *fifo_count, int *sock_count, squashfs_uid *uids, + unsigned short *uid_count, squashfs_uid *guids, unsigned short *guid_count, + long long *uncompressed_file, unsigned int *uncompressed_inode, unsigned int *uncompressed_directory, + unsigned int *inode_dir_inode_number, unsigned int *inode_dir_parent_inode, + void (push_directory_entry)(char *, squashfs_inode, int, int), squashfs_fragment_entry **fragment_table) { unsigned char *inode_table = NULL, *directory_table; - unsigned int start = sBlk->inode_table_start, end = sBlk->directory_table_start, - root_inode_start = start + SQUASHFS_INODE_BLK(sBlk->root_inode), - root_inode_offset = SQUASHFS_INODE_OFFSET(sBlk->root_inode), root_directory_offset; - squashfs_dir_inode_header inode; - unsigned int files, root_inode_block; + long long start = sBlk->inode_table_start, end = sBlk->directory_table_start, root_inode_start = start + + SQUASHFS_INODE_BLK(sBlk->root_inode); + unsigned int root_inode_offset = SQUASHFS_INODE_OFFSET(sBlk->root_inode), root_inode_block, files; + squashfs_inode_header inode; printf("Scanning existing filesystem...\n"); - if(read_fragment_table(fd, sBlk, fragment_table) == 0) + if(read_fragment_table(fd, sBlk, fragment_table) == 0) goto error; - if((files = scan_inode_table(fd, start, end, root_inode_start, sBlk, &inode, &inode_table, &root_inode_block, - uncompressed_file, uncompressed_directory, file_count, sym_count, dev_count, dir_count, fifo_count, sock_count)) == 0) { + if((files = scan_inode_table(fd, start, end, root_inode_start, root_inode_offset, sBlk, &inode, &inode_table, + &root_inode_block, root_inode_size, uncompressed_file, uncompressed_directory, file_count, sym_count, + dev_count, dir_count, fifo_count, sock_count)) == 0) { ERROR("read_filesystem: inode table read failed\n"); goto error; } @@ -420,53 +538,51 @@ int read_filesystem(char *root_name, int fd, squashfs_super_block *sBlk, char ** printf("Read existing filesystem, %d inodes scanned\n", files); - if(inode.inode_type == SQUASHFS_DIR_TYPE) { - if((directory_table = squashfs_readdir(fd, !root_name, sBlk->directory_table_start + inode.start_block, - inode.offset, inode.file_size, sBlk, push_directory_entry)) == NULL) { + if(inode.base.inode_type == SQUASHFS_DIR_TYPE || inode.base.inode_type == SQUASHFS_LDIR_TYPE) { + if(inode.base.inode_type == SQUASHFS_DIR_TYPE) { + *inode_dir_start_block = inode.dir.start_block; + *inode_dir_offset = inode.dir.offset; + *inode_dir_file_size = inode.dir.file_size - 3; + *inode_dir_inode_number = inode.dir.inode_number; + *inode_dir_parent_inode = inode.dir.parent_inode; + } else { + *inode_dir_start_block = inode.ldir.start_block; + *inode_dir_offset = inode.ldir.offset; + *inode_dir_file_size = inode.ldir.file_size - 3; + *inode_dir_inode_number = inode.ldir.inode_number; + *inode_dir_parent_inode = inode.ldir.parent_inode; + } + + if((directory_table = squashfs_readdir(fd, !root_name, *inode_dir_start_block, *inode_dir_offset, + *inode_dir_file_size, last_directory_block, sBlk, push_directory_entry)) == NULL) { ERROR("read_filesystem: Could not read root directory\n"); goto error; } - if((*cinode_table = (char *) malloc(root_inode_start - start)) == NULL) { + root_inode_start -= start; + if((*cinode_table = (char *) malloc(root_inode_start)) == NULL) { ERROR("read_filesystem: failed to alloc space for existing filesystem inode table\n"); goto error; } + read_bytes(fd, start, root_inode_start, *cinode_table); - read_bytes(fd, start, root_inode_start - start, *cinode_table); - - if((*cdirectory_table = (char *) malloc(inode.start_block)) == NULL) { - ERROR("read_filesystem: failed to alloc space for existing filesystem inode table\n"); + if((*cdirectory_table = (char *) malloc(*last_directory_block)) == NULL) { + ERROR("read_filesystem: failed to alloc space for existing filesystem directory table\n"); goto error; } + read_bytes(fd, sBlk->directory_table_start, *last_directory_block, *cdirectory_table); - read_bytes(fd, sBlk->directory_table_start, inode.start_block, *cdirectory_table); - - *inode_bytes = root_inode_start - start; - *directory_bytes = inode.start_block; - - root_inode_offset += sizeof(inode); - root_directory_offset = inode.offset + inode.file_size; - (*dir_count) ++; - - if(((*data_cache = (char *) malloc(root_inode_offset)) == NULL) || - ((*directory_data_cache = (char *) malloc(root_directory_offset)) == NULL)) { - ERROR("read_filesystem: failed to alloc inode/directory caches\n"); + if((*data_cache = (char *) malloc(root_inode_offset + *root_inode_size)) == NULL) { + ERROR("read_filesystem: failed to alloc inode cache\n"); goto error; } + memcpy(*data_cache, inode_table + root_inode_block, root_inode_offset + *root_inode_size); - memcpy(*data_cache, inode_table + root_inode_block, root_inode_offset); - memcpy(*directory_data_cache, directory_table, root_directory_offset); - *cache_size = root_inode_offset; - *directory_cache_size = root_directory_offset; - - if(root_name) { - push_directory_entry(root_name, sBlk->root_inode, SQUASHFS_DIR_TYPE); - *cache_bytes = root_inode_offset; - *directory_cache_bytes = root_directory_offset; - } else { - *cache_bytes = root_inode_offset - sizeof(inode); - *directory_cache_bytes = inode.offset; + if((*directory_data_cache = (char *) malloc(*inode_dir_offset + *inode_dir_file_size)) == NULL) { + ERROR("read_filesystem: failed to alloc directory cache\n"); + goto error; } + memcpy(*directory_data_cache, directory_table, *inode_dir_offset + *inode_dir_file_size); if(!swap) read_bytes(fd, sBlk->uid_start, sBlk->no_uids * sizeof(squashfs_uid), (char *) uids); diff --git a/release/src/linux/linux/scripts/squashfs/read_fs.h b/release/src/linux/linux/scripts/squashfs/read_fs.h index fcc39c35..1b35aed2 100644 --- a/release/src/linux/linux/scripts/squashfs/read_fs.h +++ b/release/src/linux/linux/scripts/squashfs/read_fs.h @@ -3,7 +3,8 @@ * endian and vice versa. These are needed when creating a filesystem on a * machine with different byte ordering to the target architecture. * - * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.net> + * Copyright (c) 2002, 2003, 2004, 2005, 2006 + * Phillip Lougher <phillip@lougher.org.uk> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/release/src/linux/linux/scripts/squashfs/sort.c b/release/src/linux/linux/scripts/squashfs/sort.c index b5371280..c30093fa 100644 --- a/release/src/linux/linux/scripts/squashfs/sort.c +++ b/release/src/linux/linux/scripts/squashfs/sort.c @@ -1,7 +1,8 @@ /* * Create a squashfs filesystem. This is a highly compressed read only filesystem. * - * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.net> + * Copyright (c) 2002, 2003, 2004, 2005 + * Phillip Lougher <phillip@lougher.org.uk> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -34,20 +35,32 @@ #include <stdlib.h> #include <squashfs_fs.h> +#include "global.h" +#include "sort.h" #ifdef SQUASHFS_TRACE -#define TRACE(s, args...) printf("mksquashfs: "s, ## args) +#define TRACE(s, args...) do { \ + printf("mksquashfs: "s, ## args); \ + } while(0) #else #define TRACE(s, args...) #endif -#define INFO(s, args...) if(!silent) printf("mksquashfs: "s, ## args) -#define ERROR(s, args...) fprintf(stderr, s, ## args) -#define EXIT_MKSQUASHFS() exit(1) -#define BAD_ERROR(s, args...) {\ - fprintf(stderr, "FATAL ERROR:" s, ##args);\ - EXIT_MKSQUASHFS();\ - } +#define INFO(s, args...) do { \ + if(!silent) printf("mksquashfs: "s, ## args); \ + } while(0) +#define ERROR(s, args...) do { \ + fprintf(stderr, s, ## args); \ + } while(0) +#define EXIT_MKSQUASHFS() do { \ + exit(1); \ + } while(0) +#define BAD_ERROR(s, args...) do {\ + fprintf(stderr, "FATAL ERROR:" s, ##args);\ + EXIT_MKSQUASHFS();\ + } while(0); + +int mkisofs_style = -1; struct sort_info { dev_t st_dev; @@ -59,66 +72,17 @@ struct sort_info { struct sort_info *sort_info_list[65536]; struct priority_entry { - char *filename; - long long size; - ino_t st_ino; - dev_t st_dev; + struct dir_ent *dir; struct priority_entry *next; }; struct priority_entry *priority_list[65536]; -struct sorted_inode_entry { - squashfs_inode inode; - ino_t st_ino; - dev_t st_dev; - struct sorted_inode_entry *next; -}; - -struct sorted_inode_entry *sorted_inode_list[65536]; - extern int silent; -extern int excluded(char *filename, struct stat *buf); -extern squashfs_inode write_file(char *filename, long long size, int *c_size); - - -int add_to_sorted_inode_list(squashfs_inode inode, dev_t st_dev, ino_t st_ino) -{ - int hash = st_ino & 0xffff; - struct sorted_inode_entry *new_sorted_inode_entry; - - if((new_sorted_inode_entry = malloc(sizeof(struct sorted_inode_entry))) == NULL) { - ERROR("Out of memory allocating sorted inode entry\n"); - return FALSE; - } - - new_sorted_inode_entry->inode = inode; - new_sorted_inode_entry->st_ino = st_ino; - new_sorted_inode_entry->st_dev = st_dev; - new_sorted_inode_entry->next = sorted_inode_list[hash]; - sorted_inode_list[hash] = new_sorted_inode_entry; - - return TRUE; -} - - -squashfs_inode get_sorted_inode(struct stat *buf) -{ - int hash = buf->st_ino & 0xffff; - struct sorted_inode_entry *sorted_inode_entry; - - for(sorted_inode_entry = sorted_inode_list[hash]; sorted_inode_entry; sorted_inode_entry = sorted_inode_entry->next) - if(buf->st_ino == sorted_inode_entry->st_ino && buf->st_dev == sorted_inode_entry->st_dev) - break; - - if(sorted_inode_entry) - return sorted_inode_entry->inode; - else - return (squashfs_inode) 0; -} +extern squashfs_inode write_file(squashfs_inode *inode, struct dir_ent *dir_ent, long long size, int *c_size); -int add_priority_list(char *filename, struct stat *buf, int priority) +int add_priority_list(struct dir_ent *dir, int priority) { struct priority_entry *new_priority_entry; @@ -128,10 +92,7 @@ int add_priority_list(char *filename, struct stat *buf, int priority) return FALSE; } - new_priority_entry->filename = strdup(filename); - new_priority_entry->size = buf->st_size; - new_priority_entry->st_dev = buf->st_dev; - new_priority_entry->st_ino = buf->st_ino; + new_priority_entry->dir = dir;; new_priority_entry->next = priority_list[priority]; priority_list[priority] = new_priority_entry; return TRUE; @@ -168,8 +129,8 @@ int get_priority(char *filename, struct stat *buf, int priority) } int add_sort_list(char *path, int priority, int source, char *source_path[]) { - int i; - char buffer[4096], filename[4096]; + int i, n; + char filename[4096]; struct stat buf; TRACE("add_sort_list: filename %s, priority %d\n", path, priority); @@ -177,71 +138,73 @@ int add_sort_list(char *path, int priority, int source, char *source_path[]) path[strlen(path) - 2] = '\0'; TRACE("add_sort_list: filename %s, priority %d\n", path, priority); - if(path[0] == '/' || strncmp(path, "./", 2) == 0 || strncmp(path, "../", 3) == 0) { - if(lstat(path, &buf) == -1) { - sprintf(buffer, "Cannot stat sort_list dir/file %s, ignoring", path); - perror(buffer); - return TRUE; - } - TRACE("adding filename %s, priority %d, st_dev %Lx, st_ino %Lx\n", path, priority, buf.st_dev, buf.st_ino); +re_read: + if(path[0] == '/' || strncmp(path, "./", 2) == 0 || strncmp(path, "../", 3) == 0 || mkisofs_style == 1) { + if(lstat(path, &buf) == -1) + goto error; + TRACE("adding filename %s, priority %d, st_dev %llx, st_ino %llx\n", path, priority, buf.st_dev, buf.st_ino); ADD_ENTRY(buf, priority); return TRUE; } - for(i = 0; i < source; i++) { + for(i = 0, n = 0; i < source; i++) { strcat(strcat(strcpy(filename, source_path[i]), "/"), path); if(lstat(filename, &buf) == -1) { - if(!(errno == ENOENT || errno == ENOTDIR)) { - sprintf(buffer, "Cannot stat sort_list dir/file %s, ignoring", filename); - perror(buffer); - } + if(!(errno == ENOENT || errno == ENOTDIR)) + goto error; continue; } ADD_ENTRY(buf, priority); + n ++; } - return TRUE; + + if(n == 0 && mkisofs_style == -1 && lstat(path, &buf) != -1) { + ERROR("WARNING: Mkisofs style sortlist detected! This is supported but please\n"); + ERROR("convert to mksquashfs style sortlist! A sortlist entry "); + ERROR("should be\neither absolute (starting with "); + ERROR("'/') start with './' or '../' (taken to be\nrelative to $PWD), otherwise it "); + ERROR("is assumed the entry is relative to one\nof the source directories, i.e. with "); + ERROR("\"mksquashfs test test.sqsh\",\nthe sortlist "); + ERROR("entry \"file\" is assumed to be inside the directory test.\n\n"); + mkisofs_style = 1; + goto re_read; + } + + mkisofs_style = 0; + + if(n == 1) + return TRUE; + if(n > 1) + BAD_ERROR(" Ambiguous sortlist entry \"%s\"\n\nIt maps to more than one source entry! Please use an absolute path.\n", path); + +error: + fprintf(stderr, "Cannot stat sortlist entry \"%s\"\n", path); + fprintf(stderr, "This is probably because you're using the wrong file\n"); + fprintf(stderr, "path relative to the source directories\n"); + return FALSE; } -void generate_file_priorities(char *pathname, int priority, struct stat *buf) +void generate_file_priorities(struct dir_info *dir, int priority, struct stat *buf) { - char filename[8192]; - DIR *linuxdir; - struct dirent *d_name; - - priority = get_priority(pathname, buf, priority); - - if((linuxdir = opendir(pathname)) == NULL) { - ERROR("Could not open %s, skipping...\n", pathname); - return; - } - - while((d_name = readdir(linuxdir)) != NULL) { - if(strcmp(d_name->d_name, ".") == 0 || strcmp(d_name->d_name, "..") == 0) - continue; - strcat(strcat(strcpy(filename, pathname), "/"), d_name->d_name); + priority = get_priority(dir->pathname, buf, priority); - if(lstat(filename, buf) == -1) { - char buffer[8192]; - sprintf(buffer, "Cannot stat dir/file %s, ignoring", filename); - perror(buffer); - continue; - } - - if(excluded(filename, buf)) + while(dir->current_count < dir->count) { + struct dir_ent *dir_ent = dir->list[dir->current_count++]; + struct stat *buf = &dir_ent->inode->buf; + if(dir_ent->data) continue; switch(buf->st_mode & S_IFMT) { case S_IFREG: - add_priority_list(filename, buf, get_priority(filename, buf, priority)); + add_priority_list(dir_ent, get_priority(dir_ent->pathname, buf, priority)); break; case S_IFDIR: - generate_file_priorities(filename, priority, buf); + generate_file_priorities(dir_ent->dir, priority, buf); break; } } - - closedir(linuxdir); + dir->current_count = 0; } @@ -265,40 +228,30 @@ int read_sort_file(char *filename, int source, char *source_path[]) } -void sort_files_and_write(int source, char *source_path[]) +void sort_files_and_write(struct dir_info *dir) { - struct stat buf; - int i, c_size; + int i; struct priority_entry *entry; squashfs_inode inode; + int duplicate_file; - for(i = 0; i < source; i++) { - if(lstat(source_path[i], &buf) == -1) { - char buffer[8192]; - sprintf(buffer, "Cannot stat dir/file %s, ignoring", source_path[i]); - perror(buffer); - continue; - } - - if(excluded(source_path[i], &buf)) - continue; - - switch(buf.st_mode & S_IFMT) { - case S_IFREG: - add_priority_list(source_path[i], &buf, get_priority(source_path[i], &buf, 0)); - break; - case S_IFDIR: - generate_file_priorities(source_path[i], 0, &buf); - break; - } - } + generate_file_priorities(dir, 0, &dir->dir_ent->inode->buf); - for(i = 0; i < 65536; i++) + for(i = 65535; i >= 0; i--) for(entry = priority_list[i]; entry; entry = entry->next) { - TRACE("%d: %s\n", i - 32768, entry->filename); - inode = write_file(entry->filename, entry->size, &c_size); - INFO("file %s, size %d bytes, inode 0x%Lx\n", entry->filename, c_size, inode); - INFO("\t%.2f%% of uncompressed file size (%Ld bytes)\n", ((float) c_size / entry->size) * 100.0, entry->size); - add_to_sorted_inode_list(inode, entry->st_dev, entry->st_ino); + TRACE("%d: %s\n", i - 32768, entry->dir->pathname); + if(entry->dir->inode->inode == SQUASHFS_INVALID_BLK) { + if(write_file(&inode, entry->dir, entry->dir->inode->buf.st_size, + &duplicate_file)) { + INFO("file %s, uncompressed size %lld bytes %s\n", + entry->dir->pathname, + entry->dir->inode->buf.st_size, + duplicate_file ? "DUPLICATE" : ""); + entry->dir->inode->inode = inode; + entry->dir->inode->type = SQUASHFS_FILE_TYPE; + } + } else + INFO("file %s, uncompressed size %lld bytes LINK\n", + entry->dir->pathname, entry->dir->inode->buf.st_size); } } diff --git a/release/src/linux/linux/scripts/squashfs/sort.h b/release/src/linux/linux/scripts/squashfs/sort.h new file mode 100644 index 00000000..561c320b --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/sort.h @@ -0,0 +1,56 @@ +#ifndef SORT_H +#define SORT_H + +/* + * Squashfs + * + * Copyright (c) 2002, 2003, 2004, 2005, 2006 + * Phillip Lougher <phillip@lougher.org.uk> + * + * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * sort.h + */ + +struct dir_info { + char *pathname; + unsigned int count; + unsigned int directory_count; + unsigned int current_count; + unsigned int byte_count; + char dir_is_ldir; + struct dir_ent *dir_ent; + struct dir_ent **list; + DIR *linuxdir; +}; + +struct dir_ent { + char *name; + char *pathname; + struct inode_info *inode; + struct dir_info *dir; + struct dir_info *our_dir; + struct old_root_entry_info *data; +}; + +struct inode_info { + unsigned int nlink; + struct stat buf; + squashfs_inode inode; + unsigned int type; + unsigned int inode_number; + struct inode_info *next; +}; +#endif diff --git a/release/src/linux/linux/scripts/squashfs/squashfs_fs.h b/release/src/linux/linux/scripts/squashfs/squashfs_fs.h index d810c596..fbbb53c1 100644 --- a/release/src/linux/linux/scripts/squashfs/squashfs_fs.h +++ b/release/src/linux/linux/scripts/squashfs/squashfs_fs.h @@ -1,9 +1,11 @@ #ifndef SQUASHFS_FS #define SQUASHFS_FS + /* * Squashfs * - * Copyright (c) 2002, 2003, 2004 Phillip Lougher <plougher@users.sourceforge.net> + * Copyright (c) 2002, 2003, 2004, 2005, 2006 + * Phillip Lougher <phillip@lougher.org.uk> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -22,7 +24,7 @@ * squashfs_fs.h */ -#define SQUASHFS_MAJOR 2 +#define SQUASHFS_MAJOR 3 #define SQUASHFS_MINOR 0 #define SQUASHFS_MAGIC 0x73717368 #define SQUASHFS_MAGIC_SWAP 0x68737173 @@ -46,8 +48,9 @@ #define SQUASHFS_NAME_LEN 256 #define SQUASHFS_INVALID ((long long) 0xffffffffffff) -#define SQUASHFS_INVALID_BLK ((long long) 0xffffffff) -#define SQUASHFS_USED_BLK ((long long) 0xfffffffe) +#define SQUASHFS_INVALID_FRAG ((unsigned int) 0xffffffff) +#define SQUASHFS_INVALID_BLK ((long long) -1) +#define SQUASHFS_USED_BLK ((long long) -2) /* Filesystem flags */ #define SQUASHFS_NOI 0 @@ -57,15 +60,34 @@ #define SQUASHFS_NO_FRAG 4 #define SQUASHFS_ALWAYS_FRAG 5 #define SQUASHFS_DUPLICATE 6 + #define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1) -#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, SQUASHFS_NOI) -#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, SQUASHFS_NOD) -#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, SQUASHFS_NOF) -#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, SQUASHFS_NO_FRAG) -#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, SQUASHFS_ALWAYS_FRAG) -#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, SQUASHFS_DUPLICATE) -#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, SQUASHFS_CHECK) -#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, duplicate_checking) (noi | (nod << 1) | (check_data << 2) | (nof << 3) | (no_frag << 4) | (always_frag << 5) | (duplicate_checking << 6)) + +#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_NOI) + +#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_NOD) + +#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_NOF) + +#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_NO_FRAG) + +#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_ALWAYS_FRAG) + +#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_DUPLICATE) + +#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, \ + SQUASHFS_CHECK) + +#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \ + duplicate_checking) (noi | (nod << 1) | (check_data << 2) \ + | (nof << 3) | (no_frag << 4) | (always_frag << 5) | \ + (duplicate_checking << 6)) /* Max number of types and file types */ #define SQUASHFS_DIR_TYPE 1 @@ -75,53 +97,74 @@ #define SQUASHFS_CHRDEV_TYPE 5 #define SQUASHFS_FIFO_TYPE 6 #define SQUASHFS_SOCKET_TYPE 7 +#define SQUASHFS_LDIR_TYPE 8 +#define SQUASHFS_LREG_TYPE 9 /* 1.0 filesystem type definitions */ #define SQUASHFS_TYPES 5 #define SQUASHFS_IPC_TYPE 0 -/* Flag whether block is compressed or uncompressed, bit is set if block is uncompressed */ +/* Flag whether block is compressed or uncompressed, bit is set if block is + * uncompressed */ #define SQUASHFS_COMPRESSED_BIT (1 << 15) + #define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \ - (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT) + (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT) #define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT)) #define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24) -#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) (((B) & ~SQUASHFS_COMPRESSED_BIT_BLOCK) ? \ - (B) & ~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK) -#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK)) +#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) (((B) & \ + ~SQUASHFS_COMPRESSED_BIT_BLOCK) ? (B) & \ + ~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK) + +#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK)) /* - * Inode number ops. Inodes consist of a compressed block number, and an uncompressed - * offset within that block + * Inode number ops. Inodes consist of a compressed block number, and an + * uncompressed offset within that block */ #define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16)) + #define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff)) -#define SQUASHFS_MKINODE(A, B) ((squashfs_inode)(((squashfs_inode) (A) << 16)\ - + (B))) + +#define SQUASHFS_MKINODE(A, B) ((squashfs_inode_t)(((squashfs_inode_t) (A)\ + << 16) + (B))) /* Compute 32 bit VFS inode number from squashfs inode number */ -#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + ((b) >> 2) + 1)) +#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + \ + ((b) >> 2) + 1)) +/* XXX */ /* Translate between VFS mode and squashfs mode */ #define SQUASHFS_MODE(a) ((a) & 0xfff) /* fragment and fragment table defines */ -typedef unsigned int squashfs_fragment_index; -#define SQUASHFS_FRAGMENT_BYTES(A) (A * sizeof(squashfs_fragment_entry)) -#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / SQUASHFS_METADATA_SIZE) -#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % SQUASHFS_METADATA_SIZE) -#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + SQUASHFS_METADATA_SIZE - 1) / SQUASHFS_METADATA_SIZE) -#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) * sizeof(squashfs_fragment_index)) +#define SQUASHFS_FRAGMENT_BYTES(A) (A * sizeof(struct squashfs_fragment_entry)) + +#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \ + SQUASHFS_METADATA_SIZE - 1) / \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\ + sizeof(long long)) + #define SQUASHFS_CACHED_FRAGMENTS 3 /* cached data constants for filesystem */ #define SQUASHFS_CACHED_BLKS 8 -#define SQUASHFS_MAX_FILE_SIZE_LOG 32 -#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << (SQUASHFS_MAX_FILE_SIZE_LOG - 1)) +#define SQUASHFS_MAX_FILE_SIZE_LOG 64 + +#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << \ + (SQUASHFS_MAX_FILE_SIZE_LOG - 2)) #define SQUASHFS_MARKER_BYTE 0xff @@ -129,19 +172,17 @@ typedef unsigned int squashfs_fragment_index; * definitions for structures on disk */ -typedef unsigned int squashfs_block; -typedef long long squashfs_inode; - -typedef unsigned int squashfs_uid; +typedef long long squashfs_block_t; +typedef long long squashfs_inode_t; -typedef struct squashfs_super_block { +struct squashfs_super_block { unsigned int s_magic; unsigned int inodes; - unsigned int bytes_used; - unsigned int uid_start; - unsigned int guid_start; - unsigned int inode_table_start; - unsigned int directory_table_start; + unsigned int bytes_used_2; + unsigned int uid_start_2; + unsigned int guid_start_2; + unsigned int inode_table_start_2; + unsigned int directory_table_start_2; unsigned int s_major:16; unsigned int s_minor:16; unsigned int block_size_1:16; @@ -150,88 +191,125 @@ typedef struct squashfs_super_block { unsigned int no_uids:8; unsigned int no_guids:8; unsigned int mkfs_time /* time of filesystem creation */; - squashfs_inode root_inode; + squashfs_inode_t root_inode; unsigned int block_size; unsigned int fragments; - unsigned int fragment_table_start; -} __attribute__ ((packed)) squashfs_super_block; - -typedef struct { - unsigned int inode_type:4; - unsigned int mode:12; /* protection */ - unsigned int uid:8; /* index into uid table */ - unsigned int guid:8; /* index into guid table */ -} __attribute__ ((packed)) squashfs_base_inode_header; - -typedef squashfs_base_inode_header squashfs_ipc_inode_header; - -typedef struct { - unsigned int inode_type:4; - unsigned int mode:12; /* protection */ - unsigned int uid:8; /* index into uid table */ - unsigned int guid:8; /* index into guid table */ + unsigned int fragment_table_start_2; + long long bytes_used; + long long uid_start; + long long guid_start; + long long inode_table_start; + long long directory_table_start; + long long fragment_table_start; + long long unused; +} __attribute__ ((packed)); + +struct squashfs_dir_index { + unsigned int index; + unsigned int start_block; + unsigned char size; + unsigned char name[0]; +} __attribute__ ((packed)); + +#define SQUASHFS_BASE_INODE_HEADER \ + unsigned int inode_type:4; \ + unsigned int mode:12; \ + unsigned int uid:8; \ + unsigned int guid:8; \ + unsigned int mtime; \ + unsigned int inode_number; + +struct squashfs_base_inode_header { + SQUASHFS_BASE_INODE_HEADER; +} __attribute__ ((packed)); + +struct squashfs_ipc_inode_header { + SQUASHFS_BASE_INODE_HEADER; + unsigned int nlink; +} __attribute__ ((packed)); + +struct squashfs_dev_inode_header { + SQUASHFS_BASE_INODE_HEADER; + unsigned int nlink; unsigned short rdev; -} __attribute__ ((packed)) squashfs_dev_inode_header; +} __attribute__ ((packed)); -typedef struct { - unsigned int inode_type:4; - unsigned int mode:12; /* protection */ - unsigned int uid:8; /* index into uid table */ - unsigned int guid:8; /* index into guid table */ +struct squashfs_symlink_inode_header { + SQUASHFS_BASE_INODE_HEADER; + unsigned int nlink; unsigned short symlink_size; char symlink[0]; -} __attribute__ ((packed)) squashfs_symlink_inode_header; +} __attribute__ ((packed)); -typedef struct { - unsigned int inode_type:4; - unsigned int mode:12; /* protection */ - unsigned int uid:8; /* index into uid table */ - unsigned int guid:8; /* index into guid table */ - unsigned int mtime; - squashfs_block start_block; +struct squashfs_reg_inode_header { + SQUASHFS_BASE_INODE_HEADER; + squashfs_block_t start_block; unsigned int fragment; unsigned int offset; - unsigned int file_size:SQUASHFS_MAX_FILE_SIZE_LOG; + unsigned int file_size; unsigned short block_list[0]; -} __attribute__ ((packed)) squashfs_reg_inode_header; +} __attribute__ ((packed)); -typedef struct { - unsigned int inode_type:4; - unsigned int mode:12; /* protection */ - unsigned int uid:8; /* index into uid table */ - unsigned int guid:8; /* index into guid table */ +struct squashfs_lreg_inode_header { + SQUASHFS_BASE_INODE_HEADER; + unsigned int nlink; + squashfs_block_t start_block; + unsigned int fragment; + unsigned int offset; + long long file_size; + unsigned short block_list[0]; +} __attribute__ ((packed)); + +struct squashfs_dir_inode_header { + SQUASHFS_BASE_INODE_HEADER; + unsigned int nlink; unsigned int file_size:19; unsigned int offset:13; - unsigned int mtime; - unsigned int start_block:24; -} __attribute__ ((packed)) squashfs_dir_inode_header; - -typedef union { - squashfs_base_inode_header base; - squashfs_dev_inode_header dev; - squashfs_symlink_inode_header symlink; - squashfs_reg_inode_header reg; - squashfs_dir_inode_header dir; - squashfs_ipc_inode_header ipc; -} squashfs_inode_header; + unsigned int start_block; + unsigned int parent_inode; +} __attribute__ ((packed)); + +struct squashfs_ldir_inode_header { + SQUASHFS_BASE_INODE_HEADER; + unsigned int nlink; + unsigned int file_size:27; + unsigned int offset:13; + unsigned int start_block; + unsigned int i_count:16; + unsigned int parent_inode; + struct squashfs_dir_index index[0]; +} __attribute__ ((packed)); + +union squashfs_inode_header { + struct squashfs_base_inode_header base; + struct squashfs_dev_inode_header dev; + struct squashfs_symlink_inode_header symlink; + struct squashfs_reg_inode_header reg; + struct squashfs_lreg_inode_header lreg; + struct squashfs_dir_inode_header dir; + struct squashfs_ldir_inode_header ldir; + struct squashfs_ipc_inode_header ipc; +}; -typedef struct { +struct squashfs_dir_entry { unsigned int offset:13; unsigned int type:3; unsigned int size:8; + int inode_number:16; char name[0]; -} __attribute__ ((packed)) squashfs_dir_entry; +} __attribute__ ((packed)); -typedef struct { +struct squashfs_dir_header { unsigned int count:8; - unsigned int start_block:24; -} __attribute__ ((packed)) squashfs_dir_header; - - -typedef struct { unsigned int start_block; + unsigned int inode_number; +} __attribute__ ((packed)); + +struct squashfs_fragment_entry { + long long start_block; unsigned int size; -} __attribute__ ((packed)) squashfs_fragment_entry; + unsigned int unused; +} __attribute__ ((packed)); extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen); extern int squashfs_uncompress_init(void); @@ -239,20 +317,28 @@ extern int squashfs_uncompress_exit(void); /* * macros to convert each packed bitfield structure from little endian to big - * endian and vice versa. These are needed when creating or using a filesystem on a - * machine with different byte ordering to the target architecture. + * endian and vice versa. These are needed when creating or using a filesystem + * on a machine with different byte ordering to the target architecture. * */ +#define SQUASHFS_SWAP_START \ + int bits;\ + int b_pos;\ + unsigned long long val;\ + unsigned char *s;\ + unsigned char *d; + #define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\ - SQUASHFS_MEMSET(s, d, sizeof(squashfs_super_block));\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\ SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\ SQUASHFS_SWAP((s)->inodes, d, 32, 32);\ - SQUASHFS_SWAP((s)->bytes_used, d, 64, 32);\ - SQUASHFS_SWAP((s)->uid_start, d, 96, 32);\ - SQUASHFS_SWAP((s)->guid_start, d, 128, 32);\ - SQUASHFS_SWAP((s)->inode_table_start, d, 160, 32);\ - SQUASHFS_SWAP((s)->directory_table_start, d, 192, 32);\ + SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\ + SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\ + SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\ + SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\ + SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\ SQUASHFS_SWAP((s)->s_major, d, 224, 16);\ SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\ SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\ @@ -264,137 +350,218 @@ extern int squashfs_uncompress_exit(void); SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\ SQUASHFS_SWAP((s)->block_size, d, 408, 32);\ SQUASHFS_SWAP((s)->fragments, d, 440, 32);\ - SQUASHFS_SWAP((s)->fragment_table_start, d, 472, 32);\ + SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\ + SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\ + SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\ + SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\ + SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\ + SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\ + SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\ + SQUASHFS_SWAP((s)->unused, d, 888, 64);\ } -#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\ +#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\ SQUASHFS_MEMSET(s, d, n);\ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ SQUASHFS_SWAP((s)->uid, d, 16, 8);\ SQUASHFS_SWAP((s)->guid, d, 24, 8);\ + SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ + SQUASHFS_SWAP((s)->inode_number, d, 64, 32); + +#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\ } -#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_ipc_inode_header)) +#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ + sizeof(struct squashfs_ipc_inode_header))\ + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ +} #define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\ - SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dev_inode_header));\ - SQUASHFS_SWAP((s)->rdev, d, 32, 16);\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ + sizeof(struct squashfs_dev_inode_header)); \ + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ + SQUASHFS_SWAP((s)->rdev, d, 128, 16);\ } #define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\ - SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_symlink_inode_header));\ - SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ + sizeof(struct squashfs_symlink_inode_header));\ + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ + SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\ } #define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\ - SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_reg_inode_header));\ - SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ - SQUASHFS_SWAP((s)->start_block, d, 64, 32);\ - SQUASHFS_SWAP((s)->fragment, d, 96, 32);\ - SQUASHFS_SWAP((s)->offset, d, 128, 32);\ - SQUASHFS_SWAP((s)->file_size, d, 160, SQUASHFS_MAX_FILE_SIZE_LOG);\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ + sizeof(struct squashfs_reg_inode_header));\ + SQUASHFS_SWAP((s)->start_block, d, 96, 64);\ + SQUASHFS_SWAP((s)->fragment, d, 160, 32);\ + SQUASHFS_SWAP((s)->offset, d, 192, 32);\ + SQUASHFS_SWAP((s)->file_size, d, 224, 32);\ +} + +#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ + sizeof(struct squashfs_lreg_inode_header));\ + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 128, 64);\ + SQUASHFS_SWAP((s)->fragment, d, 192, 32);\ + SQUASHFS_SWAP((s)->offset, d, 224, 32);\ + SQUASHFS_SWAP((s)->file_size, d, 256, 64);\ } #define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\ - SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dir_inode_header));\ - SQUASHFS_SWAP((s)->file_size, d, 32, 19);\ - SQUASHFS_SWAP((s)->offset, d, 51, 13);\ - SQUASHFS_SWAP((s)->mtime, d, 64, 32);\ - SQUASHFS_SWAP((s)->start_block, d, 96, 24);\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ + sizeof(struct squashfs_dir_inode_header));\ + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ + SQUASHFS_SWAP((s)->file_size, d, 128, 19);\ + SQUASHFS_SWAP((s)->offset, d, 147, 13);\ + SQUASHFS_SWAP((s)->start_block, d, 160, 32);\ + SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\ +} + +#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \ + sizeof(struct squashfs_ldir_inode_header));\ + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ + SQUASHFS_SWAP((s)->file_size, d, 128, 27);\ + SQUASHFS_SWAP((s)->offset, d, 155, 13);\ + SQUASHFS_SWAP((s)->start_block, d, 168, 32);\ + SQUASHFS_SWAP((s)->i_count, d, 200, 16);\ + SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\ +} + +#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\ + SQUASHFS_SWAP((s)->index, d, 0, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 32, 32);\ + SQUASHFS_SWAP((s)->size, d, 64, 8);\ } #define SQUASHFS_SWAP_DIR_HEADER(s, d) {\ - SQUASHFS_MEMSET(s, d, sizeof(squashfs_dir_header));\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\ SQUASHFS_SWAP((s)->count, d, 0, 8);\ - SQUASHFS_SWAP((s)->start_block, d, 8, 24);\ + SQUASHFS_SWAP((s)->start_block, d, 8, 32);\ + SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\ } #define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\ - SQUASHFS_MEMSET(s, d, sizeof(squashfs_dir_entry));\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\ SQUASHFS_SWAP((s)->offset, d, 0, 13);\ SQUASHFS_SWAP((s)->type, d, 13, 3);\ SQUASHFS_SWAP((s)->size, d, 16, 8);\ + SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\ } #define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\ - SQUASHFS_MEMSET(s, d, sizeof(squashfs_fragment_entry));\ - SQUASHFS_SWAP((s)->start_block, d, 0, 32);\ - SQUASHFS_SWAP((s)->size, d, 32, 32);\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\ + SQUASHFS_SWAP((s)->start_block, d, 0, 64);\ + SQUASHFS_SWAP((s)->size, d, 64, 32);\ } #define SQUASHFS_SWAP_SHORTS(s, d, n) {\ int entry;\ int bit_position;\ + SQUASHFS_SWAP_START\ SQUASHFS_MEMSET(s, d, n * 2);\ - for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += 16)\ + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ + 16)\ SQUASHFS_SWAP(s[entry], d, bit_position, 16);\ } #define SQUASHFS_SWAP_INTS(s, d, n) {\ int entry;\ int bit_position;\ + SQUASHFS_SWAP_START\ SQUASHFS_MEMSET(s, d, n * 4);\ - for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += 32)\ + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ + 32)\ SQUASHFS_SWAP(s[entry], d, bit_position, 32);\ } +#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\ + int entry;\ + int bit_position;\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, n * 8);\ + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ + 64)\ + SQUASHFS_SWAP(s[entry], d, bit_position, 64);\ +} + #define SQUASHFS_SWAP_DATA(s, d, n, bits) {\ int entry;\ int bit_position;\ + SQUASHFS_SWAP_START\ SQUASHFS_MEMSET(s, d, n * bits / 8);\ - for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += bits)\ + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ + bits)\ SQUASHFS_SWAP(s[entry], d, bit_position, bits);\ } -#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_INTS(s, d, n) +#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n) + +#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY -#ifdef SQUASHFS_1_0_COMPATIBILITY -typedef struct { +struct squashfs_base_inode_header_1 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:4; /* index into uid table */ unsigned int guid:4; /* index into guid table */ -} __attribute__ ((packed)) squashfs_base_inode_header_1; +} __attribute__ ((packed)); -typedef struct { +struct squashfs_ipc_inode_header_1 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:4; /* index into uid table */ unsigned int guid:4; /* index into guid table */ unsigned int type:4; unsigned int offset:4; -} __attribute__ ((packed)) squashfs_ipc_inode_header_1; +} __attribute__ ((packed)); -typedef struct { +struct squashfs_dev_inode_header_1 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:4; /* index into uid table */ unsigned int guid:4; /* index into guid table */ unsigned short rdev; -} __attribute__ ((packed)) squashfs_dev_inode_header_1; +} __attribute__ ((packed)); -typedef struct { +struct squashfs_symlink_inode_header_1 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:4; /* index into uid table */ unsigned int guid:4; /* index into guid table */ unsigned short symlink_size; char symlink[0]; -} __attribute__ ((packed)) squashfs_symlink_inode_header_1; +} __attribute__ ((packed)); -typedef struct { +struct squashfs_reg_inode_header_1 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:4; /* index into uid table */ unsigned int guid:4; /* index into guid table */ unsigned int mtime; - squashfs_block start_block; - unsigned int file_size:SQUASHFS_MAX_FILE_SIZE_LOG; + unsigned int start_block; + unsigned int file_size:32; unsigned short block_list[0]; -} __attribute__ ((packed)) squashfs_reg_inode_header_1; +} __attribute__ ((packed)); -typedef struct { +struct squashfs_dir_inode_header_1 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:4; /* index into uid table */ @@ -403,72 +570,308 @@ typedef struct { unsigned int offset:13; unsigned int mtime; unsigned int start_block:24; -} __attribute__ ((packed)) squashfs_dir_inode_header_1; +} __attribute__ ((packed)); -#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\ +#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \ SQUASHFS_MEMSET(s, d, n);\ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ SQUASHFS_SWAP((s)->uid, d, 16, 4);\ - SQUASHFS_SWAP((s)->guid, d, 20, 4);\ + SQUASHFS_SWAP((s)->guid, d, 20, 4); + +#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\ } #define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\ - SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, sizeof(squashfs_ipc_inode_header_1));\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ + sizeof(struct squashfs_ipc_inode_header_1));\ SQUASHFS_SWAP((s)->type, d, 24, 4);\ SQUASHFS_SWAP((s)->offset, d, 28, 4);\ } #define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\ - SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, sizeof(squashfs_dev_inode_header_1));\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ + sizeof(struct squashfs_dev_inode_header_1));\ SQUASHFS_SWAP((s)->rdev, d, 24, 16);\ } #define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\ - SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_symlink_inode_header_1));\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ + sizeof(struct squashfs_symlink_inode_header_1));\ SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\ } #define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\ - SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_reg_inode_header_1));\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ + sizeof(struct squashfs_reg_inode_header_1));\ SQUASHFS_SWAP((s)->mtime, d, 24, 32);\ SQUASHFS_SWAP((s)->start_block, d, 56, 32);\ SQUASHFS_SWAP((s)->file_size, d, 88, SQUASHFS_MAX_FILE_SIZE_LOG);\ } #define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\ - SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, sizeof(squashfs_dir_inode_header_1));\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ + sizeof(struct squashfs_dir_inode_header_1));\ SQUASHFS_SWAP((s)->file_size, d, 24, 19);\ SQUASHFS_SWAP((s)->offset, d, 43, 13);\ SQUASHFS_SWAP((s)->mtime, d, 56, 32);\ SQUASHFS_SWAP((s)->start_block, d, 88, 24);\ } + +#endif + +#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY + +struct squashfs_dir_index_2 { + unsigned int index:27; + unsigned int start_block:29; + unsigned char size; + unsigned char name[0]; +} __attribute__ ((packed)); + +struct squashfs_base_inode_header_2 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ +} __attribute__ ((packed)); + +struct squashfs_ipc_inode_header_2 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ +} __attribute__ ((packed)); + +struct squashfs_dev_inode_header_2 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ + unsigned short rdev; +} __attribute__ ((packed)); + +struct squashfs_symlink_inode_header_2 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ + unsigned short symlink_size; + char symlink[0]; +} __attribute__ ((packed)); + +struct squashfs_reg_inode_header_2 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ + unsigned int mtime; + unsigned int start_block; + unsigned int fragment; + unsigned int offset; + unsigned int file_size:32; + unsigned short block_list[0]; +} __attribute__ ((packed)); + +struct squashfs_dir_inode_header_2 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ + unsigned int file_size:19; + unsigned int offset:13; + unsigned int mtime; + unsigned int start_block:24; +} __attribute__ ((packed)); + +struct squashfs_ldir_inode_header_2 { + unsigned int inode_type:4; + unsigned int mode:12; /* protection */ + unsigned int uid:8; /* index into uid table */ + unsigned int guid:8; /* index into guid table */ + unsigned int file_size:27; + unsigned int offset:13; + unsigned int mtime; + unsigned int start_block:24; + unsigned int i_count:16; + struct squashfs_dir_index_2 index[0]; +} __attribute__ ((packed)); + +union squashfs_inode_header_2 { + struct squashfs_base_inode_header_2 base; + struct squashfs_dev_inode_header_2 dev; + struct squashfs_symlink_inode_header_2 symlink; + struct squashfs_reg_inode_header_2 reg; + struct squashfs_dir_inode_header_2 dir; + struct squashfs_ldir_inode_header_2 ldir; + struct squashfs_ipc_inode_header_2 ipc; +}; + +struct squashfs_dir_header_2 { + unsigned int count:8; + unsigned int start_block:24; +} __attribute__ ((packed)); + +struct squashfs_dir_entry_2 { + unsigned int offset:13; + unsigned int type:3; + unsigned int size:8; + char name[0]; +} __attribute__ ((packed)); + +struct squashfs_fragment_entry_2 { + unsigned int start_block; + unsigned int size; +} __attribute__ ((packed)); + +#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\ + SQUASHFS_MEMSET(s, d, n);\ + SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ + SQUASHFS_SWAP((s)->mode, d, 4, 12);\ + SQUASHFS_SWAP((s)->uid, d, 16, 8);\ + SQUASHFS_SWAP((s)->guid, d, 24, 8);\ + +#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\ +} + +#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \ + SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2)) + +#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ + sizeof(struct squashfs_dev_inode_header_2)); \ + SQUASHFS_SWAP((s)->rdev, d, 32, 16);\ +} + +#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ + sizeof(struct squashfs_symlink_inode_header_2));\ + SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\ +} + +#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ + sizeof(struct squashfs_reg_inode_header_2));\ + SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 64, 32);\ + SQUASHFS_SWAP((s)->fragment, d, 96, 32);\ + SQUASHFS_SWAP((s)->offset, d, 128, 32);\ + SQUASHFS_SWAP((s)->file_size, d, 160, SQUASHFS_MAX_FILE_SIZE_LOG);\ +} + +#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ + sizeof(struct squashfs_dir_inode_header_2));\ + SQUASHFS_SWAP((s)->file_size, d, 32, 19);\ + SQUASHFS_SWAP((s)->offset, d, 51, 13);\ + SQUASHFS_SWAP((s)->mtime, d, 64, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 96, 24);\ +} + +#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ + sizeof(struct squashfs_ldir_inode_header_2));\ + SQUASHFS_SWAP((s)->file_size, d, 32, 27);\ + SQUASHFS_SWAP((s)->offset, d, 59, 13);\ + SQUASHFS_SWAP((s)->mtime, d, 72, 32);\ + SQUASHFS_SWAP((s)->start_block, d, 104, 24);\ + SQUASHFS_SWAP((s)->i_count, d, 128, 16);\ +} + +#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\ + SQUASHFS_SWAP((s)->index, d, 0, 27);\ + SQUASHFS_SWAP((s)->start_block, d, 27, 29);\ + SQUASHFS_SWAP((s)->size, d, 56, 8);\ +} +#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\ + SQUASHFS_SWAP((s)->count, d, 0, 8);\ + SQUASHFS_SWAP((s)->start_block, d, 8, 24);\ +} + +#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\ + SQUASHFS_SWAP((s)->offset, d, 0, 13);\ + SQUASHFS_SWAP((s)->type, d, 13, 3);\ + SQUASHFS_SWAP((s)->size, d, 16, 8);\ +} + +#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\ + SQUASHFS_SWAP_START\ + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\ + SQUASHFS_SWAP((s)->start_block, d, 0, 32);\ + SQUASHFS_SWAP((s)->size, d, 32, 32);\ +} + +#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n) + +/* fragment and fragment table defines */ +#define SQUASHFS_FRAGMENT_BYTES_2(A) (A * sizeof(struct squashfs_fragment_entry_2)) + +#define SQUASHFS_FRAGMENT_INDEX_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) / \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) % \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_FRAGMENT_INDEXES_2(A) ((SQUASHFS_FRAGMENT_BYTES_2(A) + \ + SQUASHFS_METADATA_SIZE - 1) / \ + SQUASHFS_METADATA_SIZE) + +#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A) (SQUASHFS_FRAGMENT_INDEXES_2(A) *\ + sizeof(int)) + #endif #ifdef __KERNEL__ + /* * macros used to swap each structure entry, taking into account - * bitfields and different bitfield placing conventions on differing architectures + * bitfields and different bitfield placing conventions on differing + * architectures */ + #include <asm/byteorder.h> + #ifdef __BIG_ENDIAN /* convert from little endian to big endian */ -#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, b_pos) +#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \ + tbits, b_pos) #else /* convert from big endian to little endian */ -#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, 64 - tbits - b_pos) +#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \ + tbits, 64 - tbits - b_pos) #endif #define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\ - int bits;\ - int b_pos = pos % 8;\ - unsigned long long val = 0;\ - unsigned char *s = (unsigned char *)p + (pos / 8);\ - unsigned char *d = ((unsigned char *) &val) + 7;\ + b_pos = pos % 8;\ + val = 0;\ + s = (unsigned char *)p + (pos / 8);\ + d = ((unsigned char *) &val) + 7;\ for(bits = 0; bits < (tbits + b_pos); bits += 8) \ *d-- = *s++;\ value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\ } + #define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n); + #endif #endif diff --git a/release/src/linux/linux/scripts/squashfs/unsquashfs.c b/release/src/linux/linux/scripts/squashfs/unsquashfs.c new file mode 100644 index 00000000..dae8fd62 --- /dev/null +++ b/release/src/linux/linux/scripts/squashfs/unsquashfs.c @@ -0,0 +1,946 @@ +/* + * Unsquash a squashfs filesystem. This is a highly compressed read only filesystem. + * + * Copyright (c) 2002, 2003, 2004, 2005, 2006 + * Phillip Lougher <phillip@lougher.org.uk> + * + * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * unsquash.c + */ + +#define TRUE 1 +#define FALSE 0 +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <zlib.h> +#include <sys/mman.h> +#include <utime.h> + +#ifndef linux +#define __BYTE_ORDER BYTE_ORDER +#define __BIG_ENDIAN BIG_ENDIAN +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#else +#include <endian.h> +#endif + +#include <squashfs_fs.h> +#include "read_fs.h" +#include "global.h" + +#include <stdlib.h> + +#ifdef SQUASHFS_TRACE +#define TRACE(s, args...) do { \ + printf("mksquashfs: "s, ## args); \ + } while(0) +#else +#define TRACE(s, args...) +#endif + +#define ERROR(s, args...) do { \ + fprintf(stderr, s, ## args); \ + } while(0) + +#define EXIT_UNSQUASH(s, args...) do { \ + fprintf(stderr, "FATAL ERROR aborting: "s, ## args); \ + } while(0) + +struct hash_table_entry { + int start; + int bytes; + struct hash_table_entry *next; +}; + +int bytes = 0, swap, file_count = 0, dir_count = 0, sym_count = 0, dev_count = 0, fifo_count = 0; +char *inode_table = NULL, *directory_table = NULL; +struct hash_table_entry *inode_table_hash[65536], *directory_table_hash[65536]; +int fd; +squashfs_fragment_entry *fragment_table; +unsigned int *uid_table, *guid_table; +unsigned int cached_frag = SQUASHFS_INVALID_FRAG; +char *fragment_data; +char *file_data; +char *data; +unsigned int block_size; +int lsonly = FALSE, info = FALSE; +char **created_inode; + +#define CALCULATE_HASH(start) (start & 0xffff) + +int add_entry(struct hash_table_entry *hash_table[], int start, int bytes) +{ + int hash = CALCULATE_HASH(start); + struct hash_table_entry *hash_table_entry; + + if((hash_table_entry = malloc(sizeof(struct hash_table_entry))) == NULL) { + ERROR("add_hash: out of memory in malloc\n"); + return FALSE; + } + + hash_table_entry->start = start; + hash_table_entry->bytes = bytes; + hash_table_entry->next = hash_table[hash]; + hash_table[hash] = hash_table_entry; + + return TRUE; +} + + +int lookup_entry(struct hash_table_entry *hash_table[], int start) +{ + int hash = CALCULATE_HASH(start); + struct hash_table_entry *hash_table_entry; + + for(hash_table_entry = hash_table[hash]; hash_table_entry; hash_table_entry = hash_table_entry->next) + if(hash_table_entry->start == start) + return hash_table_entry->bytes; + + return -1; +} + + +int read_bytes(long long byte, int bytes, char *buff) +{ + off_t off = byte; + + TRACE("read_bytes: reading from position 0x%llx, bytes %d\n", byte, bytes); + + if(lseek(fd, off, SEEK_SET) == -1) { + ERROR("Lseek failed because %s\b", strerror(errno)); + return FALSE; + } + + if(read(fd, buff, bytes) == -1) { + ERROR("Read on destination failed because %s\n", strerror(errno)); + return FALSE; + } + + return TRUE; +} + + +int read_block(long long start, long long *next, char *block, squashfs_super_block *sBlk) +{ + unsigned short c_byte; + int offset = 2; + + if(swap) { + if(read_bytes(start, 2, block) == FALSE) + goto failed; + ((unsigned char *) &c_byte)[1] = block[0]; + ((unsigned char *) &c_byte)[0] = block[1]; + } else + if(read_bytes(start, 2, (char *)&c_byte) == FALSE) + goto failed; + + TRACE("read_block: block @0x%llx, %d %s bytes\n", start, SQUASHFS_COMPRESSED_SIZE(c_byte), SQUASHFS_COMPRESSED(c_byte) ? "compressed" : "uncompressed"); + + if(SQUASHFS_CHECK_DATA(sBlk->flags)) + offset = 3; + if(SQUASHFS_COMPRESSED(c_byte)) { + char buffer[SQUASHFS_METADATA_SIZE]; + int res; + unsigned long bytes = SQUASHFS_METADATA_SIZE; + + c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); + if(read_bytes(start + offset, c_byte, buffer) == FALSE) + goto failed; + + if((res = uncompress((unsigned char *) block, &bytes, (const unsigned char *) buffer, c_byte)) != Z_OK) { + if(res == Z_MEM_ERROR) + ERROR("zlib::uncompress failed, not enough memory\n"); + else if(res == Z_BUF_ERROR) + ERROR("zlib::uncompress failed, not enough room in output buffer\n"); + else + ERROR("zlib::uncompress failed, unknown error %d\n", res); + goto failed; + } + if(next) + *next = start + offset + c_byte; + return bytes; + } else { + c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); + if(read_bytes(start + offset, c_byte, block) == FALSE) + goto failed; + if(next) + *next = start + offset + c_byte; + return c_byte; + } + +failed: + return FALSE; +} + + +int read_data_block(long long start, unsigned int size, char *block) +{ + int res; + unsigned long bytes = block_size; + int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(size); + + TRACE("read_data_block: block @0x%llx, %d %s bytes\n", start, SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte), SQUASHFS_COMPRESSED_BLOCK(c_byte) ? "compressed" : "uncompressed"); + + if(SQUASHFS_COMPRESSED_BLOCK(size)) { + if(read_bytes(start, c_byte, data) == FALSE) + return 0; + + if((res = uncompress((unsigned char *) block, &bytes, (const unsigned char *) data, c_byte)) != Z_OK) { + if(res == Z_MEM_ERROR) + ERROR("zlib::uncompress failed, not enough memory\n"); + else if(res == Z_BUF_ERROR) + ERROR("zlib::uncompress failed, not enough room in output buffer\n"); + else + ERROR("zlib::uncompress failed, unknown error %d\n", res); + return 0; + } + + return bytes; + } else { + if(read_bytes(start, c_byte, block) == FALSE) + return 0; + + return c_byte; + } +} + + +void uncompress_inode_table(long long start, long long end, squashfs_super_block *sBlk) +{ + int size = 0, bytes = 0, res; + + while(start < end) { + if((size - bytes < SQUASHFS_METADATA_SIZE) && + ((inode_table = realloc(inode_table, size += SQUASHFS_METADATA_SIZE)) == NULL)) + EXIT_UNSQUASH("uncompress_inode_table: out of memory in realloc\n"); + TRACE("uncompress_inode_table: reading block 0x%llx\n", start); + add_entry(inode_table_hash, start, bytes); + if((res = read_block(start, &start, inode_table + bytes, sBlk)) == 0) { + free(inode_table); + EXIT_UNSQUASH("uncompress_inode_table: failed to read block\n"); + } + bytes += res; + } +} + + +int set_attributes(char *pathname, unsigned int mode, unsigned int uid, unsigned int guid, +unsigned int mtime, unsigned int set_mode) +{ + struct utimbuf times = { (time_t) mtime, (time_t) mtime }; + + if(utime(pathname, ×) == -1) { + ERROR("set_attributes: failed to set time on %s, because %s\n", pathname, strerror(errno)); + return FALSE; + } + + if(set_mode && chmod(pathname, (mode_t) mode) == -1) { + ERROR("set_attributes: failed to change mode %s, because %s\n", pathname, strerror(errno)); + return FALSE; + } + + if(geteuid() == 0) { + uid_t uid_value = (uid_t) uid_table[uid]; + uid_t guid_value = guid == SQUASHFS_GUIDS ? uid_value : (uid_t) guid_table[guid]; + + if(chown(pathname, uid_value, guid_value) == -1) { + ERROR("set_attributes: failed to change uid and gids on %s, because %s\n", pathname, strerror(errno)); + return FALSE; + } + } + + return TRUE; +} + + +void read_uids_guids(squashfs_super_block *sBlk) +{ + if((uid_table = malloc((sBlk->no_uids + sBlk->no_guids) * sizeof(unsigned int))) == NULL) + EXIT_UNSQUASH("read_uids_guids: failed to allocate uid/gid table\n"); + + guid_table = uid_table + sBlk->no_uids; + + if(read_bytes(sBlk->uid_start, (sBlk->no_uids + sBlk->no_guids) * sizeof(unsigned int), (char *) uid_table) == + FALSE) + EXIT_UNSQUASH("read_uids_guids: failed to read uid/gid table\n"); +} + + +void read_fragment_table(squashfs_super_block *sBlk) +{ + int i, indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk->fragments); + squashfs_fragment_index fragment_table_index[indexes]; + + TRACE("read_fragment_table: %d fragments, reading %d fragment indexes from 0x%llx\n", sBlk->fragments, indexes, sBlk->fragment_table_start); + if(sBlk->fragments == 0) + return; + + if((fragment_table = (squashfs_fragment_entry *) malloc(sBlk->fragments * sizeof(squashfs_fragment_entry))) == NULL) + EXIT_UNSQUASH("read_fragment_table: failed to allocate fragment table\n"); + + if(swap) { + squashfs_fragment_index sfragment_table_index[indexes]; + + read_bytes(sBlk->fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), (char *) sfragment_table_index); + SQUASHFS_SWAP_FRAGMENT_INDEXES(fragment_table_index, sfragment_table_index, indexes); + } else + read_bytes(sBlk->fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), (char *) fragment_table_index); + + for(i = 0; i < indexes; i++) { + int length = read_block(fragment_table_index[i], NULL, ((char *) fragment_table) + (i * SQUASHFS_METADATA_SIZE), sBlk); + TRACE("Read fragment table block %d, from 0x%llx, length %d\n", i, fragment_table_index[i], length); + } + + if(swap) { + squashfs_fragment_entry sfragment; + for(i = 0; i < sBlk->fragments; i++) { + SQUASHFS_SWAP_FRAGMENT_ENTRY((&sfragment), (&fragment_table[i])); + memcpy((char *) &fragment_table[i], (char *) &sfragment, sizeof(squashfs_fragment_entry)); + } + } +} + + +char *read_fragment(unsigned int fragment) +{ + TRACE("read_fragment: reading fragment %d\n", fragment); + + if(cached_frag == SQUASHFS_INVALID_FRAG || fragment != cached_frag) { + squashfs_fragment_entry *fragment_entry = &fragment_table[fragment]; + if(read_data_block(fragment_entry->start_block, fragment_entry->size, fragment_data) == 0) { + ERROR("read_fragment: failed to read fragment %d\n", fragment); + cached_frag = SQUASHFS_INVALID_FRAG; + return NULL; + } + cached_frag = fragment; + } + + return fragment_data; +} + + +int write_file(char *pathname, unsigned int fragment, unsigned int frag_bytes, unsigned int offset, +unsigned int blocks, long long start, char *block_ptr, unsigned int mode) +{ + unsigned int file_fd, bytes, i; + unsigned int *block_list; + + TRACE("write_file: regular file, blocks %d\n", blocks); + + if((block_list = malloc(blocks * sizeof(unsigned int))) == NULL) { + ERROR("write_file: unable to malloc block list\n"); + return FALSE; + } + + if(swap) { + unsigned int sblock_list[blocks]; + memcpy(sblock_list, block_ptr, blocks * sizeof(unsigned int)); + SQUASHFS_SWAP_INTS(block_list, sblock_list, blocks); + } else + memcpy(block_list, block_ptr, blocks * sizeof(unsigned int)); + + if((file_fd = open(pathname, O_CREAT | O_WRONLY, (mode_t) mode)) == -1) { + ERROR("write_file: failed to create file %s, because %s\n", pathname, + strerror(errno)); + free(block_list); + return FALSE; + } + + for(i = 0; i < blocks; i++) { + if((bytes = read_data_block(start, block_list[i], file_data)) == 0) { + ERROR("write_file: failed to read data block 0x%llx\n", start); + goto failure; + } + + if(write(file_fd, file_data, bytes) < bytes) { + ERROR("write_file: failed to write data block 0x%llx\n", start); + goto failure; + } + + start += SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]); + } + + if(frag_bytes != 0) { + char *fragment_data = read_fragment(fragment); + + if(fragment_data == NULL) + goto failure; + + if(write(file_fd, fragment_data + offset, frag_bytes) < frag_bytes) { + ERROR("write_file: failed to write fragment %d\n", fragment); + goto failure; + } + } + + close(file_fd); + return TRUE; + +failure: + close(file_fd); + free(block_list); + return FALSE; +} + + +int create_inode(char *pathname, unsigned int start_block, unsigned int offset, squashfs_super_block *sBlk) +{ + long long start = sBlk->inode_table_start + start_block; + squashfs_inode_header header; + char *block_ptr; + int bytes = lookup_entry(inode_table_hash, start), file_fd; + + TRACE("create_inode: pathname %s, start 0x%llx, offset %d\n", pathname, start, offset); + + if(bytes == -1) { + ERROR("create_inode: inode block 0x%llx out of range!\n", start); + return FALSE; + } + block_ptr = inode_table + bytes + offset; + + if(swap) { + squashfs_base_inode_header sinode; + memcpy(&sinode, block_ptr, sizeof(header.base)); + SQUASHFS_SWAP_BASE_INODE_HEADER(&header.base, &sinode, sizeof(squashfs_base_inode_header)); + } else + memcpy(&header.base, block_ptr, sizeof(header.base)); + + if(created_inode[header.base.inode_number - 1]) { + TRACE("create_inode: hard link\n"); + if(link(created_inode[header.base.inode_number - 1], pathname) == -1) { + ERROR("create_inode: failed to create hardlink, because %s\n", strerror(errno)); + return FALSE; + } + + return TRUE; + } + + switch(header.base.inode_type) { + case SQUASHFS_FILE_TYPE: { + unsigned int frag_bytes; + unsigned int blocks; + unsigned int offset; + long long start; + squashfs_reg_inode_header *inode = &header.reg; + + if(swap) { + squashfs_reg_inode_header sinode; + memcpy(&sinode, block_ptr, sizeof(sinode)); + SQUASHFS_SWAP_REG_INODE_HEADER(inode, &sinode); + } else + memcpy(inode, block_ptr, sizeof(*inode)); + + frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ? 0 : inode->file_size % sBlk->block_size; + offset = inode->offset; + blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? (inode->file_size + + sBlk->block_size - 1) >> sBlk->block_log : inode->file_size >> + sBlk->block_log; + start = inode->start_block; + + TRACE("create_inode: regular file, file_size %lld, blocks %d\n", inode->file_size, blocks); + + if(write_file(pathname, inode->fragment, frag_bytes, offset, blocks, start, + block_ptr + sizeof(*inode), inode->mode)) { + set_attributes(pathname, inode->mode, inode->uid, inode->guid, inode->mtime, FALSE); + file_count ++; + } + break; + } + case SQUASHFS_LREG_TYPE: { + unsigned int frag_bytes; + unsigned int blocks; + unsigned int offset; + long long start; + squashfs_lreg_inode_header *inode = &header.lreg; + + if(swap) { + squashfs_lreg_inode_header sinode; + memcpy(&sinode, block_ptr, sizeof(sinode)); + SQUASHFS_SWAP_LREG_INODE_HEADER(inode, &sinode); + } else + memcpy(inode, block_ptr, sizeof(*inode)); + + frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ? 0 : inode->file_size % sBlk->block_size; + offset = inode->offset; + blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? (inode->file_size + + sBlk->block_size - 1) >> sBlk->block_log : inode->file_size >> + sBlk->block_log; + start = inode->start_block; + + TRACE("create_inode: regular file, file_size %lld, blocks %d\n", inode->file_size, blocks); + + if(write_file(pathname, inode->fragment, frag_bytes, offset, blocks, start, + block_ptr + sizeof(*inode), inode->mode)) { + set_attributes(pathname, inode->mode, inode->uid, inode->guid, inode->mtime, FALSE); + file_count ++; + } + break; + } + case SQUASHFS_SYMLINK_TYPE: { + squashfs_symlink_inode_header *inodep = &header.symlink; + char name[65536]; + + if(swap) { + squashfs_symlink_inode_header sinodep; + memcpy(&sinodep, block_ptr, sizeof(sinodep)); + SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, &sinodep); + } else + memcpy(inodep, block_ptr, sizeof(*inodep)); + + TRACE("create_inode: symlink, symlink_size %d\n", inodep->symlink_size); + + strncpy(name, block_ptr + sizeof(squashfs_symlink_inode_header), inodep->symlink_size); + name[inodep->symlink_size] = '\0'; + + if(symlink(name, pathname) == -1) { + ERROR("create_inode: failed to create symlink %s, because %s\n", pathname, + strerror(errno)); + break; + } + + if(geteuid() == 0) { + uid_t uid_value = (uid_t) uid_table[inodep->uid]; + uid_t guid_value = inodep->guid == SQUASHFS_GUIDS ? uid_value : (uid_t) guid_table[inodep->guid]; + + if(lchown(pathname, uid_value, guid_value) == -1) + ERROR("create_inode: failed to change uid and gids on %s, because %s\n", pathname, strerror(errno)); + } + + sym_count ++; + break; + } + case SQUASHFS_BLKDEV_TYPE: + case SQUASHFS_CHRDEV_TYPE: { + squashfs_dev_inode_header *inodep = &header.dev; + + if(swap) { + squashfs_dev_inode_header sinodep; + memcpy(&sinodep, block_ptr, sizeof(sinodep)); + SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, &sinodep); + } else + memcpy(inodep, block_ptr, sizeof(*inodep)); + + TRACE("create_inode: dev, rdev 0x%x\n", inodep->rdev); + + if(geteuid() == 0) { + if(mknod(pathname, inodep->inode_type == SQUASHFS_CHRDEV_TYPE ? S_IFCHR : S_IFBLK, + makedev((inodep->rdev >> 8) & 0xff, inodep->rdev & 0xff)) + == -1) { + ERROR("create_inode: failed to create %s device %s, because %s\n", + inodep->inode_type == SQUASHFS_CHRDEV_TYPE ? "character" : "block", + pathname, strerror(errno)); + break; + } + set_attributes(pathname, inodep->mode, inodep->uid, inodep->guid, inodep->mtime, TRUE); + dev_count ++; + } else + ERROR("create_inode: could not create %s device %s, because you're not superuser!\n", + inodep->inode_type == SQUASHFS_CHRDEV_TYPE ? "character" : "block", + pathname, strerror(errno)); + break; + } + case SQUASHFS_FIFO_TYPE: + TRACE("create_inode: fifo\n"); + + if(mknod(pathname, S_IFIFO, 0) == -1) { + ERROR("create_inode: failed to create fifo %s, because %s\n", + pathname, strerror(errno)); + break; + } + set_attributes(pathname, header.base.mode, header.base.uid, header.base.guid, + header.base.mtime, TRUE); + fifo_count ++; + break; + case SQUASHFS_SOCKET_TYPE: + TRACE("create_inode: socket\n"); + ERROR("create_inode: socket %s ignored\n", pathname); + break; + default: + ERROR("Unknown inode type %d in create_inode_table!\n", header.base.inode_type); + return FALSE; + } + + created_inode[header.base.inode_number - 1] = strdup(pathname); + + return TRUE; +} + + +void uncompress_directory_table(long long start, long long end, squashfs_super_block *sBlk) +{ + int bytes = 0, size = 0, res; + + while(start < end) { + if(size - bytes < SQUASHFS_METADATA_SIZE && (directory_table = realloc(directory_table, size += SQUASHFS_METADATA_SIZE)) == NULL) + EXIT_UNSQUASH("uncompress_directory_table: out of memory in realloc\n"); + TRACE("uncompress_directory_table: reading block 0x%llx\n", start); + add_entry(directory_table_hash, start, bytes); + if((res = read_block(start, &start, directory_table + bytes, sBlk)) == 0) + EXIT_UNSQUASH("uncompress_directory_table: failed to read block\n"); + bytes += res; + } +} + + +#define DIR_ENT_SIZE 16 + +struct dir_ent { + char name[SQUASHFS_NAME_LEN + 1]; + unsigned int start_block; + unsigned int offset; + unsigned int type; +}; + +struct dir { + int dir_count; + int cur_entry; + unsigned int mode; + unsigned int uid; + unsigned int guid; + unsigned int mtime; + struct dir_ent *dirs; +}; + + +struct dir *squashfs_openddir(unsigned int block_start, unsigned int offset, squashfs_super_block *sBlk) +{ + squashfs_dir_header dirh; + char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1]; + squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer; + long long start = sBlk->inode_table_start + block_start; + char *block_ptr; + int bytes = lookup_entry(inode_table_hash, start); + squashfs_inode_header header; + int dir_count, size; + struct dir_ent *new_dir; + struct dir *dir; + + TRACE("squashfs_opendir: inode start block %d, offset %d\n", block_start, offset); + + if(bytes == -1) { + ERROR("squashfs_opendir: inode block %d not found!\n", block_start); + return NULL; + } + block_ptr = inode_table + bytes + offset; + + if(swap) { + squashfs_dir_inode_header sinode; + memcpy(&sinode, block_ptr, sizeof(header.dir)); + SQUASHFS_SWAP_DIR_INODE_HEADER(&header.dir, &sinode); + } else + memcpy(&header.dir, block_ptr, sizeof(header.dir)); + + switch(header.dir.inode_type) { + case SQUASHFS_DIR_TYPE: + block_start = header.dir.start_block; + offset = header.dir.offset; + size = header.dir.file_size; + break; + case SQUASHFS_LDIR_TYPE: + if(swap) { + squashfs_ldir_inode_header sinode; + memcpy(&sinode, block_ptr, sizeof(header.ldir)); + SQUASHFS_SWAP_LDIR_INODE_HEADER(&header.ldir, &sinode); + } else + memcpy(&header.ldir, block_ptr, sizeof(header.ldir)); + block_start = header.ldir.start_block; + offset = header.ldir.offset; + size = header.ldir.file_size; + break; + default: + ERROR("squashfs_opendir: inode not a directory\n"); + return NULL; + } + + start = sBlk->directory_table_start + block_start; + bytes = lookup_entry(directory_table_hash, start); + + if(bytes == -1) { + ERROR("squashfs_opendir: directory block %d not found!\n", block_start); + return NULL; + } + bytes += offset; + size += bytes - 3; + + if((dir = malloc(sizeof(struct dir))) == NULL) { + ERROR("squashfs_opendir: malloc failed!\n"); + return NULL; + } + + dir->dir_count = 0; + dir->cur_entry = 0; + dir->mode = header.dir.mode; + dir->uid = header.dir.uid; + dir->guid = header.dir.guid; + dir->mtime = header.dir.mtime; + dir->dirs = NULL; + + while(bytes < size) { + if(swap) { + squashfs_dir_header sdirh; + memcpy(&sdirh, directory_table + bytes, sizeof(sdirh)); + SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); + } else + memcpy(&dirh, directory_table + bytes, sizeof(dirh)); + + dir_count = dirh.count + 1; + TRACE("squashfs_opendir: Read directory header @ byte position %d, %d directory entries\n", bytes, dir_count); + bytes += sizeof(dirh); + + while(dir_count--) { + if(swap) { + squashfs_dir_entry sdire; + memcpy(&sdire, directory_table + bytes, sizeof(sdire)); + SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); + } else + memcpy(dire, directory_table + bytes, sizeof(dire)); + bytes += sizeof(*dire); + + memcpy(dire->name, directory_table + bytes, dire->size + 1); + dire->name[dire->size + 1] = '\0'; + TRACE("squashfs_opendir: directory entry %s, inode %d:%d, type %d\n", dire->name, dirh.start_block, dire->offset, dire->type); + if((dir->dir_count % DIR_ENT_SIZE) == 0) { + if((new_dir = realloc(dir->dirs, (dir->dir_count + DIR_ENT_SIZE) * sizeof(struct dir_ent))) == NULL) { + ERROR("squashfs_opendir: realloc failed!\n"); + free(dir->dirs); + free(dir); + return NULL; + } + dir->dirs = new_dir; + } + strcpy(dir->dirs[dir->dir_count].name, dire->name); + dir->dirs[dir->dir_count].start_block = dirh.start_block; + dir->dirs[dir->dir_count].offset = dire->offset; + dir->dirs[dir->dir_count].type = dire->type; + dir->dir_count ++; + bytes += dire->size + 1; + } + } + + return dir; +} + + +int squashfs_readdir(struct dir *dir, char **name, unsigned int *start_block, unsigned int *offset, unsigned int *type) +{ + if(dir->cur_entry == dir->dir_count) + return FALSE; + + *name = dir->dirs[dir->cur_entry].name; + *start_block = dir->dirs[dir->cur_entry].start_block; + *offset = dir->dirs[dir->cur_entry].offset; + *type = dir->dirs[dir->cur_entry].type; + dir->cur_entry ++; + + return TRUE; +} + + +void squashfs_closedir(struct dir *dir) +{ + free(dir->dirs); + free(dir); +} + + +int dir_scan(char *parent_name, unsigned int start_block, unsigned int offset, squashfs_super_block *sBlk) +{ + struct dir *dir = squashfs_openddir(start_block, offset, sBlk); + unsigned int type; + char *name, pathname[1024]; + + if(dir == NULL) { + ERROR("dir_scan: Failed to read directory %s (%x:%x)\n", parent_name, start_block, offset); + return FALSE; + } + + if(!lsonly && mkdir(parent_name, (mode_t) dir->mode) == -1) { + ERROR("dir_scan: failed to open directory %s, because %s\n", parent_name, strerror(errno)); + return FALSE; + } + + while(squashfs_readdir(dir, &name, &start_block, &offset, &type)) { + TRACE("dir_scan: name %s, start_block %d, offset %d, type %d\n", name, start_block, offset, type); + + strcat(strcat(strcpy(pathname, parent_name), "/"), name); + + if(lsonly || info) + printf("%s\n", pathname); + + if(type == SQUASHFS_DIR_TYPE) + dir_scan(pathname, start_block, offset, sBlk); + else + if(!lsonly) + create_inode(pathname, start_block, offset, sBlk); + } + + !lsonly && set_attributes(parent_name, dir->mode, dir->uid, dir->guid, dir->mtime, TRUE); + + squashfs_closedir(dir); + dir_count ++; + + return TRUE; +} + + +int read_super(squashfs_super_block *sBlk, char *source) +{ + read_bytes(SQUASHFS_START, sizeof(squashfs_super_block), (char *) sBlk); + + /* Check it is a SQUASHFS superblock */ + swap = 0; + if(sBlk->s_magic != SQUASHFS_MAGIC) { + if(sBlk->s_magic == SQUASHFS_MAGIC_SWAP) { + squashfs_super_block sblk; + ERROR("Reading a different endian SQUASHFS filesystem on %s\n", source); + SQUASHFS_SWAP_SUPER_BLOCK(&sblk, sBlk); + memcpy(sBlk, &sblk, sizeof(squashfs_super_block)); + swap = 1; + } else { + ERROR("Can't find a SQUASHFS superblock on %s\n", source); + goto failed_mount; + } + } + + /* Check the MAJOR & MINOR versions */ + if(sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) { + ERROR("Major/Minor mismatch, filesystem on %s is (%d:%d)\n", + source, sBlk->s_major, sBlk->s_minor); + ERROR("I only support Squashfs 3.0 filesystems! Later releases will support older Squashfs filesystems\n"); + goto failed_mount; + } + +#if __BYTE_ORDER == __BIG_ENDIAN + TRACE("Found a valid %s endian SQUASHFS superblock on %s.\n", swap ? "little" : "big", source); +#else + TRACE("Found a valid %s endian SQUASHFS superblock on %s.\n", swap ? "big" : "little", source); +#endif + + TRACE("\tInodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sBlk->flags) ? "un" : ""); + TRACE("\tData is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sBlk->flags) ? "un" : ""); + TRACE("\tFragments are %scompressed\n", SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk->flags) ? "un" : ""); + TRACE("\tCheck data is %s present in the filesystem\n", SQUASHFS_CHECK_DATA(sBlk->flags) ? "" : "not"); + TRACE("\tFragments are %s present in the filesystem\n", SQUASHFS_NO_FRAGMENTS(sBlk->flags) ? "not" : ""); + TRACE("\tAlways_use_fragments option is %s specified\n", SQUASHFS_ALWAYS_FRAGMENTS(sBlk->flags) ? "" : "not"); + TRACE("\tDuplicates are %s removed\n", SQUASHFS_DUPLICATES(sBlk->flags) ? "" : "not"); + TRACE("\tFilesystem size %.2f Kbytes (%.2f Mbytes)\n", sBlk->bytes_used / 1024.0, sBlk->bytes_used / (1024.0 * 1024.0)); + TRACE("\tBlock size %d\n", sBlk->block_size); + TRACE("\tNumber of fragments %d\n", sBlk->fragments); + TRACE("\tNumber of inodes %d\n", sBlk->inodes); + TRACE("\tNumber of uids %d\n", sBlk->no_uids); + TRACE("\tNumber of gids %d\n", sBlk->no_guids); + TRACE("sBlk->inode_table_start 0x%llx\n", sBlk->inode_table_start); + TRACE("sBlk->directory_table_start 0x%llx\n", sBlk->directory_table_start); + TRACE("sBlk->uid_start 0x%llx\n", sBlk->uid_start); + TRACE("sBlk->fragment_table_start 0x%llx\n", sBlk->fragment_table_start); + TRACE("\n"); + + return TRUE; + +failed_mount: + return FALSE; +} + + +#define VERSION() \ + printf("unsquashfs version 1.0 (2006/03/15)\n");\ + printf("copyright (C) 2006 Phillip Lougher <phillip@lougher.org.uk>\n\n"); \ + printf("This program is free software; you can redistribute it and/or\n");\ + printf("modify it under the terms of the GNU General Public License\n");\ + printf("as published by the Free Software Foundation; either version 2,\n");\ + printf("or (at your option) any later version.\n\n");\ + printf("This program is distributed in the hope that it will be useful,\n");\ + printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");\ + printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");\ + printf("GNU General Public License for more details.\n"); +int main(int argc, char *argv[]) +{ + squashfs_super_block sBlk; + char *dest = "squashfs-root"; + int i, version = FALSE; + + for(i = 1; i < argc; i++) { + if(*argv[i] != '-') + break; + if(strcmp(argv[i], "-version") == 0) { + VERSION(); + version = TRUE; + } else if(strcmp(argv[i], "-info") == 0) + info = TRUE; + else if(strcmp(argv[i], "-ls") == 0) + lsonly = TRUE; + else if(strcmp(argv[i], "-dest") == 0) { + if(++i == argc) + goto options; + dest = argv[i]; + } + } + + if(i == argc) { + if(!version) { +options: + ERROR("SYNTAX: %s [-ls | -dest] filesystem\n", argv[0]); + ERROR("\t-version\t\tprint version, licence and copyright information\n"); + ERROR("\t-info\t\t\tprint files as they are unsquashed\n"); + ERROR("\t-ls\t\t\tlist filesystem only\n"); + ERROR("\t-dest <pathname>\tunsquash to <pathname>, default \"squashfs-root\"\n"); + } + exit(1); + } + + if((fd = open(argv[i], O_RDONLY)) == -1) { + ERROR("Could not open %s, because %s\n", argv[i], strerror(errno)); + exit(1); + } + + if(read_super(&sBlk, argv[i]) == FALSE) + exit(1); + + block_size = sBlk.block_size; + if((fragment_data = malloc(block_size)) == NULL) + EXIT_UNSQUASH("failed to allocate fragment_data\n"); + + if((file_data = malloc(block_size)) == NULL) + EXIT_UNSQUASH("failed to allocate file_data"); + + if((data = malloc(block_size)) == NULL) + EXIT_UNSQUASH("failed to allocate datan\n"); + + if((created_inode = malloc(sBlk.inodes * sizeof(char *))) == NULL) + EXIT_UNSQUASH("failed to allocate created_inode\n"); + + memset(created_inode, 0, sBlk.inodes * sizeof(char *)); + + read_uids_guids(&sBlk); + read_fragment_table(&sBlk); + uncompress_inode_table(sBlk.inode_table_start, sBlk.directory_table_start, &sBlk); + uncompress_directory_table(sBlk.directory_table_start, sBlk.fragment_table_start, &sBlk); + + dir_scan(dest, SQUASHFS_INODE_BLK(sBlk.root_inode), SQUASHFS_INODE_OFFSET(sBlk.root_inode), &sBlk); + + if(!lsonly) { + printf("\n"); + printf("created %d files\n", file_count); + printf("created %d directories\n", dir_count); + printf("created %d symlinks\n", sym_count); + printf("created %d devices\n", dev_count); + printf("created %d fifos\n", fifo_count); + } + +} |