From d195d59d94ea513c768ec6768f7aec1287eea13a Mon Sep 17 00:00:00 2001 From: freesource Date: Wed, 31 Oct 2001 07:01:08 +0000 Subject: [PATCH] The newest revision by Erick Andersen. --- genext2fs/Makefile | 19 + genext2fs/dev.txt | 6 + genext2fs/device_table.txt | 76 ++ genext2fs/genext2fs | Bin 0 -> 29868 bytes genext2fs/genext2fs.c | 1819 ++++++++++++++++++++++++++++++++++++ genext2fs/genext2fs.o | Bin 0 -> 27080 bytes genext2fs/gpl.txt | 342 +++++++ 7 files changed, 2262 insertions(+) create mode 100644 genext2fs/Makefile create mode 100644 genext2fs/dev.txt create mode 100644 genext2fs/device_table.txt create mode 100755 genext2fs/genext2fs create mode 100644 genext2fs/genext2fs.c create mode 100644 genext2fs/genext2fs.o create mode 100644 genext2fs/gpl.txt diff --git a/genext2fs/Makefile b/genext2fs/Makefile new file mode 100644 index 0000000..e2dc777 --- /dev/null +++ b/genext2fs/Makefile @@ -0,0 +1,19 @@ +CC=gcc +CFLAGS=-Wall -O2 + +SRC=genext2fs.c +OBJS=$(patsubst %.c,%.o, $(SRC)) + + +all: genext2fs + +genext2fs: $(OBJS) + $(CC) $(CFLAGS) -o $@ $(OBJS) -o $@ + +$(OBJS): %.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(OBJS): Makefile + +clean: + rm -f *.o *.a core genext2fs diff --git a/genext2fs/dev.txt b/genext2fs/dev.txt new file mode 100644 index 0000000..eeafbca --- /dev/null +++ b/genext2fs/dev.txt @@ -0,0 +1,6 @@ +drwx /dev +crw- 4,0 /dev/console +crw- 5,64 /dev/cua0 +crw- 5,65 /dev/cua1 +brw- 1,0 /dev/ram0 +brw- 1,1 /dev/ram1 diff --git a/genext2fs/device_table.txt b/genext2fs/device_table.txt new file mode 100644 index 0000000..90d90c6 --- /dev/null +++ b/genext2fs/device_table.txt @@ -0,0 +1,76 @@ +# device list table +# +/dev d 755 0 0 - - - - - +/dev/mem c 640 0 0 1 1 0 0 - +/dev/kmem c 640 0 0 1 2 0 0 - +/dev/null c 640 0 0 1 3 0 0 - +/dev/zero c 640 0 0 1 5 0 0 - +/dev/random c 640 0 0 1 8 0 0 - +/dev/urandom c 640 0 0 1 9 0 0 - +/dev/tty c 640 0 0 5 0 0 0 - +/dev/tty c 640 0 0 4 0 0 1 6 +/dev/console c 640 0 0 5 1 0 0 - +/dev/ram b 640 0 0 1 1 0 0 - +/dev/ram b 640 0 0 1 0 0 1 4 +/dev/loop b 640 0 0 7 0 0 1 2 +# +# +#/dev/ttyS c 640 0 0 4 64 0 1 4 +#/dev/psaux c 640 0 0 10 1 0 0 - +#/dev/rtc c 640 0 0 10 135 0 0 - +#/dev/fd b 640 0 0 2 0 0 0 1 +# +# IDE Devices +#/dev/hda b 640 0 0 3 0 0 0 - +#/dev/hda b 640 0 0 3 1 1 1 1 +#/dev/hdb b 640 0 0 3 64 0 0 - +#/dev/hdb b 640 0 0 3 65 1 1 1 +#/dev/hdc b 640 0 0 22 0 0 0 - +#/dev/hdc b 640 0 0 22 1 1 1 1 +#/dev/hdd b 640 0 0 22 64 0 0 - +#/dev/hdd b 640 0 0 22 65 1 1 1 +#/dev/hde b 640 0 0 33 0 0 0 - +#/dev/hde b 640 0 0 33 1 1 1 1 +#/dev/hdf b 640 0 0 33 64 0 0 - +#/dev/hdf b 640 0 0 33 65 1 1 1 +#/dev/hdg b 640 0 0 34 64 0 0 - +#/dev/hdg b 640 0 0 34 65 1 1 1 +#/dev/hdh b 640 0 0 34 64 0 0 - +#/dev/hdh b 640 0 0 34 65 1 1 1 +# SCSI Devices +#/dev/sda b 640 0 0 8 0 0 0 - +#/dev/sda b 640 0 0 8 1 1 1 1 +#/dev/sdb b 640 0 0 8 16 0 0 - +#/dev/sdb b 640 0 0 8 17 1 1 1 +#/dev/sdc b 640 0 0 8 32 0 0 - +#/dev/sdc b 640 0 0 8 33 1 1 1 +##/dev/sdd b 640 0 0 8 48 0 0 - +#/dev/sdd b 640 0 0 8 49 1 1 1 +#/dev/sde b 640 0 0 8 64 0 0 - +##/dev/sde b 640 0 0 8 65 1 1 1 +#/dev/sdf b 640 0 0 8 80 0 0 - +#/dev/sdf b 640 0 0 8 81 1 1 1 +#/dev/sdg b 640 0 0 8 96 0 0 - +#/dev/sdg b 640 0 0 8 97 1 1 1 +#/dev/sdh b 640 0 0 8 112 0 0 - +#/dev/sdh b 640 0 0 8 113 1 1 1 +#/dev/sg c 640 0 0 21 0 0 1 1 +#/dev/scd b 640 0 0 11 0 0 1 1 +#/dev/st b 640 0 0 9 0 1 1 4 +#/dev/st b 640 0 0 9 32 1 1 4 +#/dev/st b 640 0 0 9 64 1 1 4 +#/dev/st b 640 0 0 9 96 1 1 4 +# All the proprietary cdrom devices in the world +#/dev/aztcd b 640 0 0 29 0 0 0 - +#/dev/bpcd b 640 0 0 41 0 0 0 - +#/dev/capi20 c 640 0 0 68 0 0 1 2 +#/dev/cdu31a b 640 0 0 15 0 0 0 - +#/dev/cdu535 b 640 0 0 24 0 0 0 - +#/dev/cm206cd b 640 0 0 32 0 0 0 - +#/dev/sjcd b 640 0 0 18 0 0 0 - +#/dev/sonycd b 640 0 0 15 0 0 0 - +#/dev/gscd b 640 0 0 16 0 0 0 - +#/dev/sbpcd b 640 0 0 25 0 0 0 - +#/dev/sbpcd b 640 0 0 25 0 0 1 4 +#/dev/mcd b 640 0 0 23 0 0 0 - +#/dev/optcd b 640 0 0 17 0 0 0 - diff --git a/genext2fs/genext2fs b/genext2fs/genext2fs new file mode 100755 index 0000000000000000000000000000000000000000..ca3379d938921fd8c8b87904d3a52cc124aff484 GIT binary patch literal 29868 zcmc(I4}4U`x%LU!z!HMHYOK*xJt`@oYDf?i0%#yCe=6XTC4u`@UGitc29s>Me@JKr zLpM>5$K_J5_VV4L#j3sb*4xrsDu_xGunAhK0l76-t)kNQ#6>Sw3aRFEzvr1bXLADh z-Q4f@-TR&VW@nz6cV^ys=bd-v%sH8Jk7vn(jEoG$x<)CP3Q^G(hjSYI+i#aC(-c)1 ztrRF&U+K{Hem9A10I_6j0GF`+O zNQ2vk3=UMvdYL{7-i*J2>vuTmb^y~copsPTk;l2o;iOZ6>8!LV4fWMi8fvd^sBen3 z7DhsaQ)L>87Q8K7R)LVLhyE3C`Eax0R5)JOz!kwUo)?M`*DU;g$qd`Q=>RkA5eS#S zO@O<}jCaAm67H*T*TJ#g8{i7zcuj#ThMNh;wy+Owg!{j_oMxu+@W+{9_8TwCVGNw; z4@Th1k)HU?!|z3Km%?2LcNyGQ;Kss1?8?<}qOagjgv*Az1TGhDG8}b**R^o$OJ0{t zPr1PKuY&(Ixa;92!4<%L8SZ>n7?B0K!#M{&`SO8@8Nkn&_$$DRfbTZ(Vc=E3Yv7aq z+i*ePTg~)$5#I{TdfAqL0NxBtS(BbaV%Osq9ujJhH*rlx)8m(8u^dga1-zh(0^vue+GCF@a!_l z&j-l23b+eC`MU+_LEyP2z81I@Sn`Lm5x*IjdQbZAAblIKRsQ3Md&-7Ujj{*$aVR9| z{}ye`n$)NIwWX#_W%&z=;1f2S1$qPYJ572WcmVhZCZ?X8 zw9)?<>FqCB`r%SIZk(7O-0&&C@5AK*|I*BV68O=GCZABk3lqkg{v zb6i6+e52AFu5XIgDUoPxC>B*31C5QLbpa*PWXAjbHPQ9W0e>}0h(yEDP=g=zfpAk* zgHji%scNcIYU_a-1I$~~yk2Pzgu|h*5)M?=!rI@Z)CEFyN@G<+L#RdxHKYDDD5^FR z@&~J$Y8wKA5Je!ep%v^!!Adw>6AUZWRgr)wxJG8KOS4oP2nW{GN5F=^E{v+dQe8-? z39^{FNFZ<*E2?j*Wvl9&SYT64W3%+Zp=e2M3=y&cA{`aik!NL1Ad1{TD0o8UE#dlT02RoVgaa+)BG6hNMO>YXtYbNf zfAMYp<`@g8ZwNGnSSX~0tcVv}`(u#+8xW2(gWAsyGkdSGO16nI617X|olhj|ESaHc z0cGKm#q-MiQwxjJAr2#`y8SOhAo(lf?O{9R@Nnj^Qii8VL<*}c*2}OPJ{_+M>+3N! zW-3`2VA7$N5A9kRPJ`8X>eb~9p^f8G(K!1#)Y^9G0_96P&uov_(DQ~9_PIu79eN5ob)5nC~NgosWi}YbY57Pg#q8y?>K~Z|?W0F5g z9}AN{`dF;IMPG#+=wAgn(7zgTpnnbIKz}0SKtCUHppOO40DVlbgY-EOLOx@#IB?L1 zA$8Kn0wIU~b?5{7SPbOSFND3J4+B4eevzW6^szXaNFNKM0{YXjj-ro+R}p;}#tQ8Z z@e{c|gMIjoO$Qq80IN$Nf8#g&x!`8RzH|U-sp$>iES2AkU(%-XqX-2V>_3*mmETIt zwEkX!?;9Ti%7Wg6J zQsUJDZzEnr>=k%Bv6r}1U}{8g6>*Wk)QsS2VpU*jNRSQccMJS9aWk_G3*4|FYo{{Z!`LP1s){kl-S=XFf}@uN4!&DYIaa1-XSnGJXk=yRbXm* zu!y)#U}}7D263~%)cjy6@oIrN0)mT(y#jM21ii$i0&_$JR}mKp%#jgXO{@yc5fTg% zy9MS*2{sce0&~O!TZvB&rc#iDxQai#Q+qdl{G@k9dC>b3C{Et*a4xS5ZtHY7jr$h3^48VR`U|H&iI@qke(8|IeF1zix5h99oi)f=t`B-Hu}nsWi{dX11P9n4 zk?S5b$VQuZhD}TSioeL`)9-NV7i)*R`t!8jF2k9xp!H+By54hYy|7>@5q6I~tc}xs zjuDXE>d<}8knfY(#LtcVnZchD{>kDEUinLMqm^yx7~jD}k<%Bfe5WI!!* z=#?WGP|Hx>NCwoh9KCWR18SLDuN=vMT9%8(Xo%4P_AXQdS!4VbV0qcVI*`7dS&xS=$awa zbE|5spVDb4or9V;nwlr_3e_uqQ_p>L1U2V8TDIvk&Vn0X{l=Zv+>y(vBL3oF zYI^BMm|J#WK1@wNj%mhNdODR#cyf^D^_fv`AS(W%%9-fNA;O6w_SD)8m#-06DeNMgcoIdPrdpAj9e zoi2?JjJYSv_4xkqUlOkclJCm0td@1d4{M|8oIBULk ztm}hJr(>$t$Cf45$vLpXiRy0E{*6>z553memCRHf7fV|bKj8*TZ2Z7lB@yTLpx0Od zGOauQqPydC%*`pf6YVsPAUEP%yW=@dMbY+uy-xc(hUz*xC6)3rsGgQodOQbACcG)o zAOI3E*O!t+1BrGr5irQ6nBRx<;3f~fB(n3+#;nWIJY10GfuZ3%6j(gCEgl#c#zWRQ zJmk=XZE)%_bT(Sd+P3~Bm3oenMYCsq(sE~_ET!#-j9t&~}f?088kIws{AOkSj&7P``3 z3yqVjDt)CR{%I=qbu)j3GqHVC8}j!oglIt&DTr?vR9x-Ha4#I+kf+3QA;xm!e_~yS z25Mym{oP3EDJvj#|6Wpkn%z>8W+%~}!Qv8M&(LmjB%)idlf`}4EY8(&7eg&X4C;r@f(>W^S{KXd`r{a8jb4qhm)Jg)g$hnw;6&T6FLa;}v=w;;;0kT( zdT$hDk!UY|3Us<-RM)X=?Kc?*^o354C8p&`F2<#~_yg1d#r3~J|I-{-$6s0NO6R6e zKS!WtPGVk$w$Pbw6@=V}g3VGB(Z6%Z0{1dIq~z*&$Sjb1i}5j|(46ro$ZSr}Lbh#q zt2}5`k=ZJ*F%v7`vs)#a$W}dMw#seRFXY00S#D&Q`J7sAoRR>~jyT9*3fOw+$WZIK zjVhV_6PU63fW|8R>3CPi8{}|hjwykKq6c&A5_oG!0_l1veO0gt%4<4P9+D7@sSV;XRS{^j~&(CNyPfn zv>T3M*glD(ic?s^oxV4UU8;&yj%a|$^PXaO9b`^(maB2953z~l~{g{2isd1 zIv$mt?#atnunRCpDaB@;qb-p4VO!v`Pttnn+Wn9)IGf&6PC{Wk$LcnHs+2}$f9HCG z$JlT0U@GV6sK{+AQDPTD7s`X`AtZFm1kRdM^rgAWjeq@6P~sLfT|y}dA2CbVkh@bE ze3sVv&p$nLc(JzhIP*G|8%Igd>C`+1Dw@NYeWNI$BDXwP#S*?@RV5XHLS&CRq_RRv zTE$ykfw#u=e~eah1aEL=^k|eenu-j4afwfjzo zU;$~Py~a}1qE{G+`ED!)+%pfjzM~_vYxgpTwiKL!RY{jG*{#zSFv5}1jZBmG*J+gw zQ8b0+c}rMcF+0?y$}ZQJ9{cdmjop4%I z*BRD&f(xWn%x(N!R-}0bweGf?r^LSeD@>D$S>FQ0L_bZA>3B1GVwxT@KMeAu62ZhEsA7-;g_dT|R^vWKSZS*Vyt245*O} zvOLnGj$If8oV^A);MmT@f&#CxFL{1h-jS=v3M}^OvBK1P+ForlIb52D+O-FSE<;)q zQHxp*bM9U~#9E^;M=FX)^R+Z@xpDf>sg&1P)GvEMMZXB+28jpTXxug;9ks+aOi-d1 zVR)6V&45io zJByFV=^`VRrI)&ss=mm5`qvrJti2O4!?d-!l?|C~FF$y?t2CM!e|fQa&xY0)cea&; zV_ACy*|#!UVxw{%yuW-@+o!G3thP@hfQ!$%m&C;2Gwwkv*gVXEZ(wT3On5WOjc*}R zzrz@!M{+9WG^!;r)m3Dk2aHUkyRlcCSgTx6GYwEw)78_ z9Fu5F6CT4G{E1L*x0mZ7q^~}2I*VvQ5g0eguYrQY$@tM9Wy1%uV<-Cg+Q3$%1b4H` zbxgNXCaKs-<0TGR4t0VP=J+Ke#K#Ph4$9RJmAVB3fCEQ`eZW@mV5Kj3jAh=GF4JfH zL}YTio*A9+9_cs|bGV+V%;-4cYUd-2c;}JWc-J!vG8jP0f>9lvuJ(;cp|q;+Zkb)P zaT25yLg8RytzzV$X;8qm7>dWsO*7RBHj;~xE=Fa^$6$(9#~jV=Vl>}habmN#;Qk6@ zvv;yAX+LBlOY$7|Rzhbvq^ApeTLg+q<6|L3XbVi*F>mlOtAj3+!h|kd$~r0Eb$<{- zB=eaNnl-yv_k9gq7eU}OUB=f?tmb(F41&DlLfp}zhI4m1YDAG{o&^H1AF!cu84B2% zSTxS{OzAktRC`5Ab-9pg7i_*M)wz~b=L)I*BT^D~JcY`9m1{GNOxX&(Vh?xU#ma0o zR%SP~TslWl5hxTZHCOwa(3buc$U8@A!?e}Tmw@IdI~aUKLDEbXyAExDB%l({V;NzW z{_{fmNKJU2@*1PXZ4R2Qd-j->qORB&t+(xvn#`iNx=tIT^_hM5fb2WZ!Oe3Ebk9M( z;*jgZWe{i~xkt{~-ELG}z2hK17=j+f63eu1aIKs0aGG;rtBkeviTe;iDp83gero1I^?)Q0MQ11*UWy#ir$PZo5AO#qf4>p2a;?kH>(#vDz|bi5n1C{CNpsITGz-csGG*7s;iVk#RS1 zx-_FS+5~+Qx9^xuR~pOZdO11ET+b&a%)o*@@poc9-W!>y{SK}486TMw7#8exU7gN+ zKC{Kjz05iDWcY1Rr0;h`p}C?^v0#51%8!~+(@INuk9!Tju)A2(9>YDR$@_Qa%UdVh zOJTL@HU3c!WqE7mH99dWtSKdZpA8wHa*N~QI0wA&g<0kp3A$68i^Ox^%ri zCb9iWbL+}ybc;#{uyWom*kv{d@A&C5NUm;}ldhVS8&-d?%vd^$@J-JuAm%H(<-NLH_ zLiYo)4j{3U-g7VSU@}k^bpxvfg!t+VNDy)&#BC=IyzlXaDy?EbO5&bt68pFXW{yW1 z;+00WY%B(x5Y`9!qb!H}%fe7E9awJsNv;bll0WI<{K_msrSxQRQvgc}L}g7x zFo%J!B9OrV_W%kZA(13Vdyt95rH)gX_#HipVP|1scWJh=HY3Q=){d$)rpvJ&-zQ$i zb+yNZ%*-|Ap0~`EVDLlqX|M}w!8})SA?X24k=U^)?ld>PeqyqwI7B07J<2j8UomUr zJ#wY-YdJ#7WMcUJuE5|JeG3V@-p$r42DJyi#H|Rly99A;+r2j;kc(~CTqQcDZHw6T z<5L-V$8WoD<+vYQJ8G@6()jl`#Z1)Ec{kO5rQrt_ONZnQpgDI<=@Rs(f`_R1e}03R z&AIy55P>Kn2PB&g@X1zJG8*b z%9X}Df(7@?zUcY+^^0_q-+6X^FCo7ha+D}HKPrtsekueJ-?s!pRAS@mHtmxGO+Khm zUO{_*h*g96mXvQO0(|&sBe-tINsouC`v5(5B!^~ zQceIqP|5oOVaSeB5_~))NVkF1>PS(qtRtrwqfS&Iw+OnV0bUurhU`8ro14s&>q!(S zD>v>(!UFb;S+mT%U1YW@AJk65Ga#qXL8QZirLp!$6?aOewAiuYBU(?_pB$L>uq$~y;h4FP23M@l zXDHZ~pvi}UTekir?_lNXkXwDYIe&{)f7B;SuQ;BVP$Kd|dZ`oulJ zAuJF(u-$jROW(_NhZoW>WjQ`sPI@ge%X2(@zg@y-Hoa4qY5|97w%*RvVx36BCoRFYrZUq;0!p!E&5Gkq7* z#X{GzL+N^uYwft;eIW7~kAezYr%=PFqq{64tetG{+X4nxv z(~U)eh|dBIRtq9L8Z;2L2#)~`=TPQ#f`&TI@L14r$sx*&AdCzQk7gJd1Wi;sX?v{W zZ^@g(MM$)+Wi+-&u20s>y@c}QYO#9|Eo>P(M_CPmqU18Mi4etZLnrW<Kp=$*~r`#T1{}Po|BvY+PMj z?nGeQVjo(V@TcORWwjKgCO$I1*WuJo?|l#gPEOhT2)zQ}A2M*|-XGD+1O68VTze0} zi>I>JW$pbnLb7x`zt|-nUg4q0<=*m@!QUgvc<-pN1yBQ+${dI#^=@}5Nq-qrpvy7!)9(J!v{%>=ok&s^>I1N1+HAIe`or@O7c zJ&kvuo36SC{nv)Tq-2xmxY!zSEw_8G{wowdARvd)t5EP{rGVU6b1-#bI`uCD6b^DS zZRcl5yH-Fx_x&c}gf!{PAWh;<*d%@q@a*|P-2aRFq10}!%u~C$(n{^-;ySgPYxv-5 zisiP~SStqIU}`tl*s0xA>fkn}-5}Di+H>poaV5W(Nl@Y}JX3yeT)BQ97y4&K20NMa zuSZ}db{8NywVUhx)NU2OLFF*gevdTN2!=3{z>4_gs0x-cd7nr=6}*q&=aLpJl|18S z4(oTX@gY_x)RxCc^ni_s943B1rScgEK}5xd7P)7MX0?1Ru^|0^%;oY)c!YAqQsoU{ zecTHq<+|Tlx7g;`5%R>#x*Od3FDSj9IG3ZmI#OcAXXIvx%=$?5p za{k5KgT1mD&#@UX0cifPp}7ccLcwE!e8!it>bBUC^FIvkQfGIT`Vpk}+?Dv%ryoTb z+QBn_#7z`lB29?%I#G>VPmsX%Oh$SWp4-LI3EV2aSmt&;GcUv3hM$KG zR|dA$J=0KSQp5e&2FvKg&N6+nX_d5$t$h;23`B4(pCo5BN(#PVgo6i}Cw}=6NU)+tL3hkhveWLwm>m0>I*qmo{FR%vs#+xJ*GXSHEM2 zYu}1-smBbwQh0j4H$#oRkII&_A?>U$w!;WX2K9;^8NJ?e!;QMh{)Q)%=ry`$N85~R zqF)BRSM=nanC4`o$3Rd}R%#1NS&veBJUbA980wks*^Vp^VO!zO-^daNQm&4#L+ZL` zTjEJ}{m@=G?rGC^{zGE81R1S$`=%4yv1PL%wA*r}O_JH*l~99|e{1q*yk%A7k{)lQ6C58pn4u z(c$qIL}$C&w}U%f^aLh~c;{<;B0Dz&YoMq#T6LipUgJyP!`j|C|MRgY4hr`5hgo*H z(IKEJTd_)Tix-?LjrL<9)qjW_?R!wc7Uf||n1ev_B8*2g z7H@kVqoVv6>k#&Px8pWf#|jRs7lf^f)`~YGb)kN<_HdyaS*~?sGYHFW?ZBo3Vtu_Z zy@sA@zD>#nmweUdVU|-v(aXS*F6ko5!b3HT4 zG;Q-}+VK93WLZxzb-6LiWSlRpm7I4VzI1>UoYIBy^cw#ppvnFQR4(iRa`J^=v!{Rb zXOYEcdVw!f&rSb-dCrxXmyJsyZP0NPoPBZMmS+!q(Ul)5QN;l| zUqDb3iZ#?WO^T}GScK&?`%ak|A_YC%&-AeuL*}@&1!8RQWGwe zDtZ>@Wc!?8Vae^ z^=s6tr064R1I`0c>q23(CHb{#pf!pEJ0fax6;g1zNj0+JIF9;opeAbOy6W80aTl7GGiOIqU6{wD8&;+r43`f$6KZA4i4$L<*VbXM z)+$3%kfo~ija6#`_R`J`vwZYbtUg*rm4q;-+WAuRYZY@y*IVNxDKZ3DS z3%dj!z$Zx4)+1Xvzh=wUGNb4|(I)nDegwsty`L{Sedlh6b2nV4>3ZPz!m$L4QfA^5 zAsDe(oO~U$EliV$j+Gk4iqLnpQbmUHomai2en|bAgN!IHTxIGT@%dD8ST_#whj~mD zv!P&+#lTt*ixc9sMY3?wQ!xI~#;WEL*#NYbvh~H9`061r1Mu z!LqF0@bUiJLx&Dojm)1`6jAeQ)cl4JTI0D}!f0k^tLpWwCdpZL zq#^>of@q_#n`)Jq#dt;;4OVjqM~yMFeIl_HFc(v-$ebRQEFcn!g=+%LRwo2y%OHcy z#!(7A4-~E`G{qB{EZG+YQm!I1i>a167CEaR9}O%lv@{$fthdI`aLQ$|#%lC}wU~&I zG@P~=!)S*{tL9s;R~28YoTEDSUS!uC}thJ|c6S3{yX%*R>->bk0iSm5j;7Sv<1 zw3#QXy)E^qPUK+bZ=Ib@;-yu0nbWT-=z}55u%vG~KmGiW)aP%;uvXz{Z>*0*sAMXR zgHvHk1K~)as?J-FeyOX9HDIl>E)ZUic3=i$!T+a=**P_;G~*~`1yu`m2;&@)Qu%@^ z$@04Mm+j>ddF(K7L%kGQEfyOp&S#6&L}Ov0Z|C-nD9;xRwa9)51{#{Pvpuaq!QdLGyX{f2quC@}cLo6w-;U z`P5j|v|hzQeX&MN!x6>aUMhX8DQ$PoXF^~&Ff5t^&>pCLm6ST>O9ayc^?doPIHBbz zgf>j9vRK>@4@!Qdu)5(cr3DifPIpt3(k`4Ex&Oc4HCy$R z``})IdmHW}xX*Q!4~9)V>__T#RuBlf>U?|)_C|l z4-0!~O2H3FrnS#)`@&v_80n}RYg($Q&f79G!(FT%e$sk2NXc$6_OzC~cs(Uy7_ z%k$AiB7UrT`LL68lwTX@+CbOIf1NTf)%5v)f21QzrLeI)Q=W3OE~~u95n<8se83f; zv(iXwh51h@79DqjSAov56?VE^HoDcITm1!e&)MiW2k^AcUKV6tte376j(x#)a31B^ z_d5`#zVIRq`FIJA{L%G+?ilFo7vp)o3P*aD$AgDRS8FvAaVi|Iqi|LpV$!L$2rKw| zq?zwskqn!bQtu@gDuZ(w>$I*`(7kT~_*QxJ*|*kpd^Oq&-QqbNR2#BNof!*fFRvW~ zp}^K5R(T*h=c1iqr2N_eb0tH4lj%4F85i|RVp^b~D^tlE z0tjV_uLlf8Wv0IbAmcL6I`uyjTEKo?VYXjE``IE3j{;V0nCX*%t;?Z&EZ$ydv*n+P zL>@LunhcbN%X&2%q(D?jV21GeOufz{i3;9j$QrndtRKpt#)1}yRx z_^|W=q{&=Mt zcn0YCLK?L>0=x+LZWG^2df+wina-D*g21<$=}!UQ{!b3)8G*+uyMZlzzYzM~3A|@7 zPN_B14+6I$Kl|lsxPIWgf5E(DrvC+aGt#M7tdHk@+rJ;dGsQVxAs%R-OZgJ;>KzW} zW;4GEybbx^HS8;9Zb^t-#}zp8`Mski*FvVAi)A_!#={&nD*o z`djwwBCNQ2fM7ALl)`rw}*~_&yWQ1s(wZT<4LV=YjL2;cI}eh6@3^w?Uua zGra}=;6dCEn)LSo)84WF`2CFU0w1^G$AJy>=g&;~r-A1qKP@lI`vvd})MtJFq8s?B zA6Va07_Ynvya?&m_cq=KUIpAG@?*^m90ZnY~{9njC5g!aJ`{47Nv z_$>Al%>0$W-kn&#n)ps&u0KJps2Fecz<1;M2<-&h69YC-pVc4tF+cR1^cP`1PXG@f zoogTJ?+<{T*pINjU-EO{JYehlB`*RO0CS!qeIM|_@5}oj*7rW}45VB3@C@)GVA@gA zXJfIs3fLNNR{#fp>~MY}${Vi~0&{+XSfTH30`SV8{b_74-dD6GwpgzNl4x z2k;EgSDNVwVEgx3wgcb&AnG^U^Ca-1Us&_qcx4x`{rfH5z?OdUe}7&Bp7ulNr&<2* zfrowH1$Y(o|2i}M3@~5VwD=nf$sR@eBs2YDA!z_yD%{n;eB0KdSJu?jO!Z^)pc#*Y zY6}&9V#W4_7-b2bc4CjBCLE1KV|8_fHA-{g4fqVn{1vyA`Ct-v>An43>UYYV3# zr8eYW(-5kzYVeCK3x8Ft6|tU0{srZ8mwNp3JPQ{uLndx|_-kX0jq8HF#!%$L@6z zG_1O?czTh-_c|I1r_Q)Rky}CGK-4cDnEAz%X!)5OKepc$zAV9qx}~Mo_f(3|fIz@s z7f~WDRn309pMjwGJdB+NTTM+hRnfDe@DUe#3_q4*$5w&n(`oEbd4vTA09 ze*bws`(iJEuf_Py+}uNN3fWV!AJ6BAiodSeA8cXg)cU#oZhpkaPHKKh#vUb@Tf=AG z=(6e-C4vVXe8fR*82Y}C`DGh>M)_SFdyM$Z&aenONVJ1p$1b*0;sq6c70DhYJBDw4v9;&> z9+928rK;gBN{ChR*@gVtlAS_+K*%1`co*0CwQls${RXQ|SPXol!YF~%C3?bLoh_DRk5NkTFw zzM<4yg$IKi(|9^A2RkZ0>qATSqNKJ_AacN4EtTlJt_BdEIyz?e>%=$ExJ=y$(l|9P(($}y! ztLsd|(G-e^$F&MYPkjS7_$-w@3p?13!%h6ami%&;Jw8&;NyFa|4ON++-?FFr1Jcx+ zAIBP&v~bC7^X4w`-?m_Z&$Gh6V(z>p9!w`Nyu+x_dTE6t)#it~?8%Tc-f6POq`z-w zj}#x^vPU%HA-A6oj$z_y#?R_4igk#*SSlnQ$&2w$g+?ax+h;>$MSKrSj*GLt`9XfTZ|QZ0kAwnn$~z12LsiQ=IgA%3UgI`!&LLLX!as36Hp6v8uo=aJpNr* Gr2KDd>>Yss literal 0 HcmV?d00001 diff --git a/genext2fs/genext2fs.c b/genext2fs/genext2fs.c new file mode 100644 index 0000000..b328740 --- /dev/null +++ b/genext2fs/genext2fs.c @@ -0,0 +1,1819 @@ +// genext2fs.c +// +// ext2 filesystem generator for embedded systems +// Copyright (C) 2000 Xavier Bestel +// +// 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. +// +// Changes: +// 3 Jun 2000 Initial release +// 6 Jun 2000 Bugfix: fs size multiple of 8 +// Bugfix: fill blocks with inodes +// 14 Jun 2000 Bugfix: bad chdir() with -d option +// Bugfix: removed size=8n constraint +// Changed -d file to -f file +// Added -e option +// 22 Jun 2000 Changed types for 64bits archs +// 24 Jun 2000 Added endianness swap +// Bugfix: bad dir name lookup +// 03 Aug 2000 Bugfix: ind. blocks endian swap +// 09 Aug 2000 Bugfix: symlinks endian swap +// 19 Jun 2001 Erik Andersen added +// the -n (nosquash) option. +// 20 Aug 2001 Erik Andersen added +// device table support + + +// `genext2fs' is a mean to generate an ext2 filesystem +// as a normal (non-root) user. It doesn't require you to mount +// the image file to copy files on it. It doesn't even require +// you to be the superuser to make device nodes. +// +// Warning ! `genext2fs' has been designed for embedded +// systems. As such, it will generate a filesystem for single-user +// usage: all files/directories/etc... will belong to UID/GID 0 +// +// Example usage: +// +// # genext2fs -b 1440 -d srcdir /dev/fd0 +// +// All files in the srcdir directory will be written to /dev/fd0 as +// a new ext2 filesystem image. You can then mount the floppy as +// usual. +// +// # genext2fs -b 1024 -d builddir -f devices.txt flashdisk.img +// +// This one would build a filesystem from all the files in builddir, +// then would read a devices list and make apropriate nodes. The +// format for the device list is: +// +// drwx /dev +// crw- 10,190 /dev/lcd +// brw- 1,0 /dev/ram0 +// +// This device list builds the /dev directory, a character device +// node /dev/lcd (major 10, minor 190) and a block device node +// /dev/ram0 (major 1, minor 0) + + +#include +#include +#include +#include +#include +#include +#include +#include +#define __USE_GNU +#include +#include + + + + + +// block size + +#define BLOCKSIZE 1024 +#define BLOCKS_PER_GROUP 8192 +#define BYTES_PER_INODE (8*BLOCKSIZE) +#define RESERVED_INODES 5/100 + + +// inode block size (why is it != BLOCKSIZE ?!?) + +#define INODE_BLOCKSIZE 512 +#define INOBLK (BLOCKSIZE / INODE_BLOCKSIZE) + +// reserved inodes + +#define EXT2_BAD_INO 1 // Bad blocks inode +#define EXT2_ROOT_INO 2 // Root inode +#define EXT2_ACL_IDX_INO 3 // ACL inode +#define EXT2_ACL_DATA_INO 4 // ACL inode +#define EXT2_BOOT_LOADER_INO 5 // Boot loader inode +#define EXT2_UNDEL_DIR_INO 6 // Undelete directory inode +#define EXT2_FIRST_INO 11 // First non reserved inode + +// magic number for ext2 + +#define EXT2_MAGIC_NUMBER 0xEF53 + + +// direct/indirect block addresses + +#define EXT2_NDIR_BLOCKS 11 // direct blocks +#define EXT2_IND_BLOCK 12 // indirect block +#define EXT2_DIND_BLOCK 13 // double indirect block +#define EXT2_TIND_BLOCK 14 // triple indirect block +#define EXT2_INIT_BLOCK 0xFFFFFFFF // just initialized (not really a block address) + +// end of a block walk + +#define WALK_END 0xFFFFFFFE + + +// file modes + +#define FM_IFMT 0xF000 // format mask +#define FM_IFLNK 0xA000 // socket +#define FM_IFSOCK 0xC000 // symbolic link +#define FM_IFREG 0x8000 // regular file +#define FM_IFBLK 0x6000 // block device +#define FM_IFDIR 0x4000 // directory +#define FM_IFCHR 0x2000 // character device +#define FM_IFIFO 0x1000 // fifo + +#define FM_ISUID 0x0800 // SUID +#define FM_ISGID 0x0400 // SGID +#define FM_ISVTX 0x0200 // sticky bit + +#define FM_IRWXU 0x01C0 // user mask +#define FM_IRUSR 0x0100 // read +#define FM_IWUSR 0x0080 // write +#define FM_IXUSR 0x0040 // execute + +#define FM_IRWXG 0x0038 // group mask +#define FM_IRGRP 0x0020 // read +#define FM_IWGRP 0x0010 // write +#define FM_IXGRP 0x0008 // execute + +#define FM_IRWXO 0x0007 // other mask +#define FM_IROTH 0x0004 // read +#define FM_IWOTH 0x0002 // write +#define FM_IXOTH 0x0001 // execute + + +// options + +#define OP_HOLES 0x01 // make files with holes + + +// used types + +typedef signed char int8; +typedef unsigned char uint8; +typedef signed short int16; +typedef unsigned short uint16; +typedef signed int int32; +typedef unsigned int uint32; + + +// endianness swap + +inline uint16 swab16(uint16 val) +{ + return (val >> 8) | (val << 8); +} + +inline uint32 swab32(uint32 val) +{ + return ((val>>24) | ((val>>8)&0xFF00) | + ((val<<8)&0xFF0000) | (val<<24)); +} + + +// on-disk structures +// this trick makes me declare things only once +// (once for the structures, once for the endianness swap) + +#define superblock_decl \ + udecl32(s_inodes_count) /* Count of inodes in the filesystem */ \ + udecl32(s_blocks_count) /* Count of blocks in the filesystem */ \ + udecl32(s_r_blocks_count) /* Count of the number of reserved blocks */ \ + udecl32(s_free_blocks_count) /* Count of the number of free blocks */ \ + udecl32(s_free_inodes_count) /* Count of the number of free inodes */ \ + udecl32(s_first_data_block) /* The first block which contains data */ \ + udecl32(s_log_block_size) /* Indicator of the block size */ \ + decl32(s_log_frag_size) /* Indicator of the size of the fragments */ \ + udecl32(s_blocks_per_group) /* Count of the number of blocks in each block group */ \ + udecl32(s_frags_per_group) /* Count of the number of fragments in each block group */ \ + udecl32(s_inodes_per_group) /* Count of the number of inodes in each block group */ \ + udecl32(s_mtime) /* The time that the filesystem was last mounted */ \ + udecl32(s_wtime) /* The time that the filesystem was last written to */ \ + udecl16(s_mnt_count) /* The number of times the file system has been mounted */ \ + decl16(s_max_mnt_count) /* The number of times the file system can be mounted */ \ + udecl16(s_magic) /* Magic number indicating ex2fs */ \ + udecl16(s_state) /* Flags indicating the current state of the filesystem */ \ + udecl16(s_errors) /* Flags indicating the procedures for error reporting */ \ + udecl16(s_minor_rev_level) /* The minor revision level of the filesystem */ \ + udecl32(s_lastcheck) /* The time that the filesystem was last checked */ \ + udecl32(s_checkinterval) /* The maximum time permissable between checks */ \ + udecl32(s_creator_os) /* Indicator of which OS created the filesystem */ \ + udecl32(s_rev_level) /* The revision level of the filesystem */ \ + udecl16(s_def_resuid) /* The default uid for reserved blocks */ \ + udecl16(s_def_resgid) /* The default gid for reserved blocks */ + +#define groupdescriptor_decl \ + udecl32(bg_block_bitmap) /* Block number of the block bitmap */ \ + udecl32(bg_inode_bitmap) /* Block number of the inode bitmap */ \ + udecl32(bg_inode_table) /* Block number of the inode table */ \ + udecl16(bg_free_blocks_count) /* Free blocks in the group */ \ + udecl16(bg_free_inodes_count) /* Free inodes in the group */ \ + udecl16(bg_used_dirs_count) /* Number of directories in the group */ \ + udecl16(bg_pad) + +#define inode_decl \ + udecl16(i_mode) /* Entry type and file mode */ \ + udecl16(i_uid) /* User id */ \ + udecl32(i_size) /* File/dir size in bytes */ \ + udecl32(i_atime) /* Last access time */ \ + udecl32(i_ctime) /* Creation time */ \ + udecl32(i_mtime) /* Last modification time */ \ + udecl32(i_dtime) /* Deletion time */ \ + udecl16(i_gid) /* Group id */ \ + udecl16(i_links_count) /* Number of (hard) links to this inode */ \ + udecl32(i_blocks) /* Number of blocks used (1 block = 512 bytes) */ \ + udecl32(i_flags) /* ??? */ \ + udecl32(i_reserved1) \ + utdecl32(i_block,15) /* Blocks table */ \ + udecl32(i_version) /* ??? */ \ + udecl32(i_file_acl) /* File access control list */ \ + udecl32(i_dir_acl) /* Directory access control list */ \ + udecl32(i_faddr) /* Fragment address */ \ + udecl8(i_frag) /* Fragments count*/ \ + udecl8(i_fsize) /* Fragment size */ \ + udecl16(i_pad1) + +#define directory_decl \ + udecl32(d_inode) /* Inode entry */ \ + udecl16(d_rec_len) /* Total size on record */ \ + udecl16(d_name_len) /* Size of entry name */ + +#define decl8(x) int8 x; +#define udecl8(x) uint8 x; +#define decl16(x) int16 x; +#define udecl16(x) uint16 x; +#define decl32(x) int32 x; +#define udecl32(x) uint32 x; +#define utdecl32(x,n) uint32 x[n]; + +typedef struct +{ + superblock_decl + uint32 s_reserved[235]; // Reserved +} superblock; + +typedef struct +{ + groupdescriptor_decl + uint32 bg_reserved[3]; + uint32 bg_pad_to_bk[(BLOCKSIZE-32)/sizeof(uint32)]; +} groupdescriptor; + +typedef struct +{ + inode_decl + uint32 i_reserved2[2]; +} inode; + +typedef struct +{ + directory_decl + char d_name[0]; +} directory; + +typedef uint8 block[BLOCKSIZE]; + +typedef struct +{ + uint32 bnum; + uint32 bpdir; + uint32 bpind; + uint32 bpdind; + uint32 bptind; +} blockwalker; + +#if BLOCKSIZE == 1024 +typedef struct +{ + block zero; // The famous block 0 + superblock sb; // The superblock + groupdescriptor gd; // The group desciptor + block bbm; // The block bitmap + block ibm; // The inode bitmap + inode itab[0]; // The inode table +} filesystem; +#else +#error UNHANDLED BLOCKSIZE +#endif + +// now the endianness swap + +#undef decl8 +#undef udecl8 +#undef decl16 +#undef udecl16 +#undef decl32 +#undef udecl32 +#undef utdecl32 + +#define decl8(x) +#define udecl8(x) +#define decl16(x) this->x = swab16(this->x); +#define udecl16(x) this->x = swab16(this->x); +#define decl32(x) this->x = swab32(this->x); +#define udecl32(x) this->x = swab32(this->x); +#define utdecl32(x,n) { int i; for(i=0; ix[i] = swab32(this->x[i]); } + +void swap_sb(superblock *sb) +{ +#define this sb + superblock_decl +#undef this +} + +void swap_gd(groupdescriptor *gd) +{ +#define this gd + groupdescriptor_decl +#undef this +} + +void swap_nod(inode *nod) +{ +#define this nod + inode_decl +#undef this +} + +void swap_dir(directory *dir) +{ +#define this dir + directory_decl +#undef this +} + +void swap_block(block b) +{ + int i; + uint32 *blk = (uint32*)b; + for(i = 0; i < BLOCKSIZE/4; i++) + blk[i] = swab32(blk[i]); +} + +#undef decl8 +#undef udecl8 +#undef decl16 +#undef udecl16 +#undef decl32 +#undef udecl32 +#undef utdecl32 + +char * argv0; +int nosquash = 0; +extern ssize_t getline(char **lineptr, size_t *n, FILE *stream); + +// error (un)handling +inline void errexit(const char *fmt, ...) +{ + va_list ap; + fprintf(stderr, "%s: ", argv0); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + exit(1); +} + +inline void pexit(const char * fname) +{ + fprintf(stderr, "%s: ", argv0); + perror(fname); + exit(1); +} + +// printf helper macro +#define plural(a) (a), ((a) > 1) ? "s" : "" + +// temporary working block +inline uint8 * get_workblk(void) +{ + static block b; + return b; +} +inline void free_workblk(block b) +{ +} + +// rounds a quantity up to a blocksize +uint32 rndup(uint32 qty, uint32 siz) +{ + return (qty + (siz - 1)) & ~(siz - 1); +} + +// check if something is allocated in the bitmap +inline uint32 allocated(block b, uint32 item) +{ + return b[(item-1) / 8] & (1 << ((item-1) % 8)); +} + +// return a given block from a filesystem +inline uint8 * get_blk(filesystem *fs, uint32 blk) +{ + return (uint8*)fs + blk*BLOCKSIZE; +} + +// return a given inode from a filesystem +inline inode * get_nod(filesystem *fs, uint32 nod) +{ + return &fs->itab[nod-1]; +} + +// allocate a given block/inode in the bitmap +// allocate first free if item == 0 +uint32 allocate(block b, uint32 item) +{ + if(!item) + { + int i; + uint8 bits; + for(i = 0; i < BLOCKSIZE; i++) + if((bits = b[i]) != (uint8)-1) + { + int j; + for(j = 0; j < 8; j++) + if(!(bits & (1 << j))) + break; + item = i * 8 + j + 1; + break; + } + if(i == BLOCKSIZE) + return 0; + } + b[(item-1) / 8] |= (1 << ((item-1) % 8)); + return item; +} + +// deallocate a given block/inode +void deallocate(block b, uint32 item) +{ + b[(item-1) / 8] &= ~(1 << ((item-1) % 8)); +} + +// allocate a block +uint32 alloc_blk(filesystem *fs) +{ + uint32 bk; + if(!(bk = allocate(fs->bbm, 0))) + errexit("couldn't allocate a block (no free space)"); + if(!(fs->gd.bg_free_blocks_count--)) + errexit("group descr. free blocks count == 0 (corrupted fs?)"); + if(!(fs->sb.s_free_blocks_count--)) + errexit("superblock free blocks count == 0 (corrupted fs?)"); + return bk; +} + +// allocate an inode +uint32 alloc_nod(filesystem *fs) +{ + uint32 nod; + if(!(nod = allocate(fs->ibm, 0))) + errexit("couldn't allocate an inode (no free inode)"); + if(!(fs->gd.bg_free_inodes_count--)) + errexit("group descr. free blocks count == 0 (corrupted fs?)"); + if(!(fs->sb.s_free_inodes_count--)) + errexit("superblock free blocks count == 0 (corrupted fs?)"); + return nod; +} + +// print a bitmap allocation +void print_bm(block b, uint32 max) +{ + uint32 i; + printf("----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0\n"); + for(i=1; i <= max; i++) + { + putchar(allocated(b, i) ? '*' : '.'); + if(!(i % 100)) + printf("\n"); + } + if((i-1) % 100) + printf("\n"); +} + +// initalize a blockwalker (iterator for blocks list) +void init_bw(filesystem *fs, uint32 nod, blockwalker *bw) +{ + bw->bnum = 0; + bw->bpdir = EXT2_INIT_BLOCK; +} + +// return next block of inode (WALK_END for end) +// if create>0, append a newly allocated block at the end +// if hole!=0, create a hole in the file +uint32 walk_bw(filesystem *fs, uint32 nod, blockwalker *bw, uint32 *create, uint32 hole) +{ + uint32 *bkref = 0; + uint32 *b; + uint32 extend = 0; + if(bw->bnum >= get_nod(fs, nod)->i_blocks / INOBLK) + { + if(create && (*create)--) + extend = 1; + else + return WALK_END; + } + // first direct block + if(bw->bpdir == EXT2_INIT_BLOCK) + { + bkref = &get_nod(fs, nod)->i_block[bw->bpdir = 0]; + if(extend) // allocate first block + *bkref = hole ? 0 : alloc_blk(fs); + } + // direct block + else if(bw->bpdir < EXT2_NDIR_BLOCKS) + { + bkref = &get_nod(fs, nod)->i_block[++bw->bpdir]; + if(extend) // allocate block + *bkref = hole ? 0 : alloc_blk(fs); + } + // first block in indirect block + else if(bw->bpdir == EXT2_NDIR_BLOCKS) + { + bw->bnum++; + bw->bpdir = EXT2_IND_BLOCK; + bw->bpind = 0; + if(extend) // allocate indirect block + get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs); + b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]); + bkref = &b[bw->bpind]; + if(extend) // allocate first block + *bkref = hole ? 0 : alloc_blk(fs); + } + // block in indirect block + else if((bw->bpdir == EXT2_IND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1)) + { + bw->bpind++; + b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]); + bkref = &b[bw->bpind]; + if(extend) // allocate block + *bkref = hole ? 0 : alloc_blk(fs); + } + // first block in first indirect block in first double indirect block + else if(bw->bpdir == EXT2_IND_BLOCK) + { + bw->bnum += 2; + bw->bpdir = EXT2_DIND_BLOCK; + bw->bpind = 0; + bw->bpdind = 0; + if(extend) // allocate double indirect block + get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs); + b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]); + if(extend) // allocate first indirect block + b[bw->bpind] = alloc_blk(fs); + b = (uint32*)get_blk(fs, b[bw->bpind]); + bkref = &b[bw->bpdind]; + if(extend) // allocate first block + *bkref = hole ? 0 : alloc_blk(fs); + } + // block in indirect block in double indirect block + else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpdind < BLOCKSIZE/4 - 1)) + { + bw->bpdind++; + b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]); + b = (uint32*)get_blk(fs, b[bw->bpind]); + bkref = &b[bw->bpdind]; + if(extend) // allocate block + *bkref = hole ? 0 : alloc_blk(fs); + } + // first block in indirect block in double indirect block + else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1)) + { + bw->bnum++; + bw->bpdind = 0; + bw->bpind++; + b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]); + if(extend) // allocate indirect block + b[bw->bpind] = alloc_blk(fs); + b = (uint32*)get_blk(fs, b[bw->bpind]); + bkref = &b[bw->bpdind]; + if(extend) // allocate first block + *bkref = hole ? 0 : alloc_blk(fs); + } + // I don't do triple indirect - it's such a small filesystem ... + else + errexit("file too big ! blocks list for inode %d extends past double indirect blocks!", nod); + if(*bkref) + { + bw->bnum++; + if(!allocated(fs->bbm, *bkref)) + errexit("[block %d of inode %d is unallocated !]", *bkref, nod); + } + if(extend) + get_nod(fs, nod)->i_blocks = bw->bnum * INOBLK; + return *bkref; +} + +// add blocks to an inode (file/dir/etc...) +void extend_blk(filesystem *fs, uint32 nod, block b, int amount) +{ + int create = amount; + blockwalker bw, lbw; + uint32 bk; + init_bw(fs, nod, &bw); + lbw = bw; + while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END) + lbw = bw; + bw = lbw; + while(create) + { + int i, copyb = 0; + if(!(fs->sb.s_reserved[200] & OP_HOLES)) + copyb = 1; + else + for(i = 0; i < BLOCKSIZE / 4; i++) + if(((int32*)(b + BLOCKSIZE * (amount - create)))[i]) + { + copyb = 1; + break; + } + if((bk = walk_bw(fs, nod, &bw, &create, !copyb)) == WALK_END) + break; + if(copyb) + memcpy(get_blk(fs, bk), b + BLOCKSIZE * (amount - create - 1), BLOCKSIZE); + } +} + +// link an entry (inode #) to a directory +void add2dir(filesystem *fs, uint32 dnod, uint32 nod, const char* name, uint32 mode, uid_t uid, gid_t gid, time_t ctime) +{ + blockwalker bw; + uint32 bk; + uint8 *b; + directory *d; + int reclen, nlen; + inode *node; + inode *pnode; + + if (nosquash == 0) { + /* Ok, squash everything */ + uid = 0; + gid = 0; + if(!S_ISDIR(mode)) + mode &= ~(S_IWGRP | S_IWOTH); + mode &= ~(S_ISUID | S_ISGID); + } + pnode = get_nod(fs, dnod); + + if(!S_ISDIR(pnode->i_mode)) + errexit("can't add '%s' to a non-directory", name); + if(!*name) + errexit("bad name '%s' (not meaningful)", name); + if(strchr(name, '/')) + errexit("bad name '%s' (contains a slash)", name); + nlen = strlen(name); + reclen = sizeof(directory) + rndup(nlen, 4); + if(reclen > BLOCKSIZE) + errexit("bad name '%s' (too long)", name); + init_bw(fs, dnod, &bw); + while((bk = walk_bw(fs, dnod, &bw, 0, 0)) != WALK_END) // for all blocks in dir + { + b = get_blk(fs, bk); + // for all dir entries in block + for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len)) + { + // if empty dir entry, large enough, use it + if((!d->d_inode) && (d->d_rec_len >= reclen)) + { + d->d_inode = nod; + node = get_nod(fs, nod); + node->i_links_count++; + d->d_name_len = nlen; + strncpy(d->d_name, name, nlen); + node->i_mode = mode; + node->i_uid = uid; + node->i_gid = gid; + node->i_atime = ctime; + node->i_ctime = ctime; + node->i_mtime = ctime; + return; + } + // if entry with enough room (last one?), shrink it & use it + if(d->d_rec_len >= (sizeof(directory) + rndup(d->d_name_len, 4) + reclen)) + { + reclen = d->d_rec_len; + d->d_rec_len = sizeof(directory) + rndup(d->d_name_len, 4); + reclen -= d->d_rec_len; + d = (directory*) (((int8*)d) + d->d_rec_len); + d->d_rec_len = reclen; + d->d_inode = nod; + node = get_nod(fs, nod); + node->i_links_count++; + d->d_name_len = nlen; + strncpy(d->d_name, name, nlen); + node->i_mode = mode; + node->i_uid = uid; + node->i_gid = gid; + node->i_atime = ctime; + node->i_ctime = ctime; + node->i_mtime = ctime; + return; + } + } + } + // we found no free entry in the directory, so we add a block + b = get_workblk(); + d = (directory*)b; + d->d_inode = nod; + node = get_nod(fs, nod); + node->i_links_count++; + d->d_rec_len = BLOCKSIZE; + d->d_name_len = nlen; + strncpy(d->d_name, name, nlen); + node->i_mode = mode; + node->i_uid = uid; + node->i_gid = gid; + node->i_atime = ctime; + node->i_ctime = ctime; + node->i_mtime = ctime; + extend_blk(fs, dnod, b, 1); + get_nod(fs, dnod)->i_size += BLOCKSIZE; + free_workblk(b); +} + +// find an entry in a directory +uint32 find_dir(filesystem *fs, uint32 nod, const char * name) +{ + blockwalker bw; + uint32 bk; + int nlen = strlen(name); + init_bw(fs, nod, &bw); + while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END) + { + directory *d; + uint8 *b; + b = get_blk(fs, bk); + for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len)) + if(d->d_inode && (nlen == d->d_name_len) && !strncmp(d->d_name, name, nlen)) + return d->d_inode; + } + return 0; +} + +// find the inode of a full path +uint32 find_path(filesystem *fs, uint32 nod, const char * name) +{ + char *p, *n, *n2 = strdup(name); + n = n2; + while(*n == '/') + { + nod = EXT2_ROOT_INO; + n++; + } + while(*n) + { + if((p = strchr(n, '/'))) + (*p) = 0; + if(!(nod = find_dir(fs, nod, n))) + break; + if(p) + n = p + 1; + else + break; + } + free(n2); + return nod; +} + +// make a full-fledged directory (i.e. with "." & "..") +uint32 mkdir_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, uid_t uid, gid_t gid, time_t ctime) +{ + uint32 nod; + if((nod = find_dir(fs, parent_nod, name))) + return nod; + nod = alloc_nod(fs); + if (!(mode & FM_IFDIR)) + mode |= FM_IFDIR; + add2dir(fs, parent_nod, nod, name, mode, uid, gid, ctime); + add2dir(fs, nod, nod, ".", mode, uid, gid, ctime); + add2dir(fs, nod, parent_nod, "..", mode, uid, gid, ctime); + fs->gd.bg_used_dirs_count++; + return nod; +} + +// make a symlink +uint32 mklink_fs(filesystem *fs, uint32 parent_nod, const char *name, size_t size, uint8 * b, uid_t uid, gid_t gid, time_t ctime) +{ + uint32 mode; + uint32 nod = alloc_nod(fs); + mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO; + get_nod(fs, nod)->i_size = size; + add2dir(fs, parent_nod, nod, name, mode, uid, gid, ctime); + if(size <= 4 * (EXT2_TIND_BLOCK+1)) + { + strncpy((char*)get_nod(fs, nod)->i_block, (char*)b, size); + return nod; + } + extend_blk(fs, nod, b, rndup(size, BLOCKSIZE) / BLOCKSIZE); + return nod; +} + +// make a file from a FILE* +uint32 mkfile_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, size_t size, FILE *f, uid_t uid, gid_t gid, time_t ctime) +{ + uint8 * b; + uint32 nod = alloc_nod(fs); + mode |= FM_IFREG; + get_nod(fs, nod)->i_size = size; + add2dir(fs, parent_nod, nod, name, mode, uid, gid, ctime); + if(!(b = (uint8*)malloc(rndup(size, BLOCKSIZE)))) + errexit("not enough mem to read file '%s'", name); + if(f) + fread(b, size, 1, f); + else + memset(b, 0, size); + extend_blk(fs, nod, b, rndup(size, BLOCKSIZE) / BLOCKSIZE); + free(b); + return nod; +} + +// retrieves a mode info from a struct stat +uint32 get_mode(struct stat *st) +{ + uint32 mode = 0; + if (nosquash == 1) + return st->st_mode; + if(st->st_mode & S_IRUSR) + mode |= FM_IRUSR | FM_IRGRP | FM_IROTH; + if(st->st_mode & S_IWUSR) + mode |= FM_IWUSR | FM_IWGRP | FM_IWOTH; + if(st->st_mode & S_IXUSR) + mode |= FM_IXUSR | FM_IXGRP | FM_IXOTH; + return mode; +} + +// retrieves a mode info from a string +uint32 get_modestr(const char *p) +{ + uint32 mode = 0; + if(p[0] == 'r') + mode |= FM_IRUSR | FM_IRGRP | FM_IROTH; + if(p[1] == 'w') + mode |= FM_IWUSR | FM_IWGRP | FM_IWOTH; + if(p[2] == 'x' || p[2] == 's') + mode |= FM_IXUSR | FM_IXGRP | FM_IXOTH; + return mode; +} + +// basename of a path - free me +char * basename(const char * fullpath) +{ + char * p = strrchr(fullpath, '/'); + return strdup(p ? p + 1 : fullpath); +} + +// dirname of a path - free me +char * dirname(const char * fullpath) +{ + char * p, * n = strdup(fullpath); + if((p = strrchr(n, '/'))) + *(p+1) = 0; + else + *n = 0; + return n; +} + +// adds entries to the filesystem from a text file +void add2fs_from_file(filesystem *fs, uint32 this_nod, FILE * fh) +{ + uint32 mode; + uint32 nod, nod2; + char cmod[11], *path, *name, *dir; + int major, minor; + while(fscanf(fh, "%10s", cmod)) + { + if(feof(fh)) + break; + mode = get_modestr(cmod + 1); + switch(*cmod) + { + case 'd': + fscanf(fh, "%as\n", &path); + break; + case 'c': + mode |= FM_IFCHR; + fscanf(fh, "%i, %i %as\n", &major, &minor, &path); + break; + case 'b': + mode |= FM_IFBLK; + fscanf(fh, "%i, %i %as\n", &major, &minor, &path); + break; + case '#': + while(fgetc(fh) != '\n'); + continue; + default: + errexit("malformed text input file"); + } + name = basename(path); + dir = dirname(path); + free(path); + if(!(nod = find_path(fs, this_nod, dir))) + errexit("can't find directory '%s' to create '%s''", dir, name); + free(dir); + if((!strcmp(name, ".")) || (!strcmp(name, ".."))) + { + free(name); + continue; + } + switch(*cmod) + { + case 'd': + // FIXME - This really needs a get_uid_gid_str() + mkdir_fs(fs, nod, name, mode, 0, 0, time(NULL)); + break; + case 'c': + case 'b': + nod2 = alloc_nod(fs); + ((uint8*)get_nod(fs, nod2)->i_block)[0] = minor; + ((uint8*)get_nod(fs, nod2)->i_block)[1] = major; + // FIXME - This really needs a get_uid_gid_str() + add2dir(fs, nod, nod2, name, mode, 0, 0, time(NULL)); + break; + } + free(name); + } +} + +// adds a tree of entries to the filesystem from current dir +void add2fs_from_dir(filesystem *fs, uint32 this_nod) +{ + uint32 nod; + FILE *fh; + DIR *dh; + struct dirent *dent; + struct stat st; + uint8 *b; + if(!(dh = opendir("."))) + pexit("."); + while((dent = readdir(dh))) + { + if((!strcmp(dent->d_name, ".")) || (!strcmp(dent->d_name, ".."))) + continue; + lstat(dent->d_name, &st); + switch(st.st_mode & S_IFMT) + { + case S_IFCHR: + case S_IFBLK: + nod = alloc_nod(fs); + get_nod(fs, nod)->i_mode = (((st.st_mode & S_IFMT) == S_IFCHR) ? FM_IFCHR : FM_IFBLK) | get_mode(&st); + ((uint8*)get_nod(fs, nod)->i_block)[0] = (st.st_rdev & 0xff); + ((uint8*)get_nod(fs, nod)->i_block)[1] = (st.st_rdev >> 8); + add2dir(fs, this_nod, nod, dent->d_name, st.st_mode, st.st_uid, st.st_gid, st.st_ctime); + break; + case S_IFLNK: + if(!(b = (uint8*)malloc(rndup(st.st_size, BLOCKSIZE)))) + errexit("out of memory"); + if(readlink(dent->d_name, (char*)b, st.st_size) < 0) + pexit(dent->d_name); + mklink_fs(fs, this_nod, dent->d_name, st.st_size, b, st.st_uid, st.st_gid, st.st_ctime); + free(b); + break; + case S_IFREG: + if(!(fh = fopen(dent->d_name, "r"))) + pexit(dent->d_name); + mkfile_fs(fs, this_nod, dent->d_name, st.st_mode, st.st_size, fh, st.st_uid, st.st_gid, st.st_ctime); + fclose(fh); + break; + case S_IFDIR: + nod = mkdir_fs(fs, this_nod, dent->d_name, st.st_mode, st.st_uid, st.st_gid, st.st_ctime); + if(chdir(dent->d_name) < 0) + pexit(dent->d_name); + add2fs_from_dir(fs, nod); + chdir(".."); + break; + default: + fprintf(stderr, "ignoring entry %s", dent->d_name); + } + } + closedir(dh); +} + +// endianness swap of x-indirect blocks +void swap_goodblocks(filesystem *fs, inode *nod) +{ + int i; + int nblk = nod->i_blocks / INOBLK; + if(nod->i_size && !nblk) + for(i = 0; i <= EXT2_TIND_BLOCK; i++) + nod->i_block[i] = swab32(nod->i_block[i]); + if(nblk <= EXT2_IND_BLOCK) + return; + swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK])); + if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4) + return; + for(i = 0; i < BLOCKSIZE/4; i++) + if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + i) + swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i])); + swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK])); + if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4) + return; + errexit("too big file on the filesystem"); +} + +void swap_badblocks(filesystem *fs, inode *nod) +{ + int i; + int nblk = nod->i_blocks / INOBLK; + if(nod->i_size && !nblk) + for(i = 0; i <= EXT2_TIND_BLOCK; i++) + nod->i_block[i] = swab32(nod->i_block[i]); + if(nblk <= EXT2_IND_BLOCK) + return; + swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK])); + if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4) + return; + swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK])); + for(i = 0; i < BLOCKSIZE/4; i++) + if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + i) + swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i])); + if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4) + return; + errexit("too big file on the filesystem"); +} + +// endianness swap of the whole filesystem +void swap_goodfs(filesystem *fs) +{ + int i; + for(i = 1; i < fs->sb.s_inodes_count; i++) + { + inode *nod = get_nod(fs, i); + if(nod->i_mode & FM_IFDIR) + { + blockwalker bw; + uint32 bk; + init_bw(fs, i, &bw); + while((bk = walk_bw(fs, i, &bw, 0, 0)) != WALK_END) + { + directory *d; + uint8 *b; + b = get_blk(fs, bk); + for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + swab16(d->d_rec_len))) + swap_dir(d); + } + } + swap_goodblocks(fs, nod); + swap_nod(nod); + } + swap_gd(&fs->gd); + swap_sb(&fs->sb); +} + +void swap_badfs(filesystem *fs) +{ + int i; + swap_sb(&fs->sb); + swap_gd(&fs->gd); + for(i = 1; i < fs->sb.s_inodes_count; i++) + { + inode *nod = get_nod(fs, i); + swap_nod(nod); + swap_badblocks(fs, nod); + if(nod->i_mode & FM_IFDIR) + { + blockwalker bw; + uint32 bk; + init_bw(fs, i, &bw); + while((bk = walk_bw(fs, i, &bw, 0, 0)) != WALK_END) + { + directory *d; + uint8 *b; + b = get_blk(fs, bk); + for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len)) + swap_dir(d); + } + } + } +} + +// initialize an empty filesystem +filesystem * init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes) +{ + int i; + filesystem *fs; + directory *d; + uint8 * b; + uint32 nod; + + if(nbblocks < 16) // totally arbitrary + errexit("too small filesystem"); + if(nbblocks >BLOCKS_PER_GROUP) // I build only one group + errexit("too big filesystem"); + if(!(fs = (filesystem*)calloc(nbblocks, BLOCKSIZE))) + errexit("not enough memory for filesystem"); + + // create the superblock for an empty filesystem + fs->sb.s_inodes_count = rndup(nbinodes, BLOCKSIZE/sizeof(inode)); + fs->sb.s_blocks_count = nbblocks; + fs->sb.s_r_blocks_count = nbresrvd; + fs->sb.s_free_blocks_count = nbblocks; + fs->sb.s_free_inodes_count = fs->sb.s_inodes_count - EXT2_FIRST_INO + 1; + fs->sb.s_first_data_block = (BLOCKSIZE == 1024); + fs->sb.s_log_block_size = BLOCKSIZE >> 11; + fs->sb.s_log_frag_size = BLOCKSIZE >> 11; + fs->sb.s_blocks_per_group = BLOCKS_PER_GROUP; + fs->sb.s_frags_per_group = BLOCKS_PER_GROUP; + fs->sb.s_inodes_per_group = fs->sb.s_inodes_count; + fs->sb.s_magic = EXT2_MAGIC_NUMBER; + + // set up groupdescriptors + fs->sb.s_free_blocks_count -= 5 + fs->sb.s_inodes_count * sizeof(inode) / BLOCKSIZE; + fs->gd.bg_free_blocks_count = fs->sb.s_free_blocks_count; + fs->gd.bg_free_inodes_count = fs->sb.s_free_inodes_count; + fs->gd.bg_used_dirs_count = 1; + fs->gd.bg_block_bitmap = 3; + fs->gd.bg_inode_bitmap = 4; + fs->gd.bg_inode_table = 5; + + // mark non-filesystem blocks and inodes as allocated + for(i = fs->sb.s_blocks_count; i <= BLOCKSIZE * 8; i++) + allocate(fs->bbm, i); + for(i = fs->sb.s_inodes_count + 1; i <= BLOCKSIZE * 8; i++) + allocate(fs->ibm, i); + + // mark system blocsk and inodes as allocated + for(i = 1; i <= 4 + fs->sb.s_inodes_count * sizeof(inode) / BLOCKSIZE; i++) + allocate(fs->bbm, i); + for(i = 1; i < EXT2_FIRST_INO; i++) + allocate(fs->ibm, i); + + // make root inode and directory + fs->itab[EXT2_ROOT_INO-1].i_mode = FM_IFDIR | FM_IRWXU | FM_IRWXG | FM_IRWXO; + fs->itab[EXT2_ROOT_INO-1].i_size = BLOCKSIZE; + fs->itab[EXT2_ROOT_INO-1].i_links_count = 2; + b = get_workblk(); + d = (directory*)b; + d->d_inode = EXT2_ROOT_INO; + d->d_rec_len = sizeof(directory)+4; + d->d_name_len = 1; + strcpy(d->d_name, "."); + d = (directory*)(b + d->d_rec_len); + d->d_inode = EXT2_ROOT_INO; + d->d_rec_len = BLOCKSIZE - (sizeof(directory)+4); + d->d_name_len = 2; + strcpy(d->d_name, ".."); + extend_blk(fs, EXT2_ROOT_INO, b, 1); + + // make lost+found directory and reserve blocks + if(fs->sb.s_r_blocks_count) + { + nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH, 0, 0, time(NULL)); + memset(b, 0, BLOCKSIZE); + ((directory*)b)->d_rec_len = BLOCKSIZE; + for(i = 1; i < fs->sb.s_r_blocks_count; i++) + extend_blk(fs, nod, b, 1); + get_nod(fs, nod)->i_size = fs->sb.s_r_blocks_count * BLOCKSIZE; + } + free_workblk(b); + + // administrative info + fs->sb.s_state = 1; + fs->sb.s_max_mnt_count = 20; + + // options for me + if(holes) + fs->sb.s_reserved[200] |= OP_HOLES; + + return fs; +} + +// loads a filesystem from disk +filesystem * load_fs(FILE * fh, int swapit) +{ + size_t fssize; + filesystem *fs; + if((fseek(fh, 0, SEEK_END) < 0) || ((fssize = ftell(fh)) < 0)) + pexit("input filesystem image"); + rewind(fh); + fssize = (fssize + BLOCKSIZE - 1) / BLOCKSIZE; + if(fssize < 16) // totally arbitrary + errexit("too small filesystem"); + if(fssize > BLOCKS_PER_GROUP) // I build only one group + errexit("too big filesystem"); + if(!(fs = (filesystem*)calloc(fssize, BLOCKSIZE))) + errexit("not enough memory for filesystem"); + if(fread(fs, BLOCKSIZE, fssize, fh) != fssize) + pexit("input filesystem image"); + if(swapit) + swap_badfs(fs); + if(fs->sb.s_rev_level || (fs->sb.s_magic != EXT2_MAGIC_NUMBER)) + errexit("not a suitable ext2 filesystem"); + return fs; +} + +void free_fs(filesystem *fs) +{ + free(fs); +} + +// just walk through blocks list +void flist_blocks(filesystem *fs, uint32 nod, FILE *fh) +{ + blockwalker bw; + uint32 bk; + init_bw(fs, nod, &bw); + while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END) + fprintf(fh, " %d", bk); + fprintf(fh, "\n"); +} + +// walk through blocks list +void list_blocks(filesystem *fs, uint32 nod) +{ + int bn = 0; + blockwalker bw; + uint32 bk; + init_bw(fs, nod, &bw); + printf("blocks in inode %d:", nod); + while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END) + printf(" %d", bk), bn++; + printf("\n%d blocks (%d bytes)\n", bn, bn * BLOCKSIZE); +} + +// saves blocks to FILE* +void write_blocks(filesystem *fs, uint32 nod, FILE* f) +{ + blockwalker bw; + uint32 bk; + int32 fsize = get_nod(fs, nod)->i_size; + init_bw(fs, nod, &bw); + while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END) + { + if(fsize <= 0) + errexit("wrong size while saving inode %d", nod); + if(fwrite(get_blk(fs, bk), (fsize > BLOCKSIZE) ? BLOCKSIZE : fsize, 1, f) != 1) + errexit("error while saving inode %d", nod); + fsize -= BLOCKSIZE; + } +} + +// hexdumps blocks to a FILE* +void hexdump_blocks(filesystem *fs, uint32 nod, FILE* f) +{ + blockwalker bw; + uint32 bk; + uint8 *b; + int32 fsize = get_nod(fs, nod)->i_size; + init_bw(fs, nod, &bw); + printf("block: offset: data: ascii:\n"); + while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END) + { + int i, j; + if(fsize <= 0) + errexit("wrong size while saving inode %d", nod); + b = get_blk(fs, bk); + for(i = 0; i < 64; i++) + { + int dmp = 0; + for(j = 0; j < 4; j++) + if(*(int32*)&b[i * 16 + j * 4]) + dmp = 1; + if(!dmp) + continue; + printf("%5d: %03X:", bk, i * 16); + for(j = 0; j < 4; j++) + printf(" %08x", *(int32*)&b[i * 16 + j * 4]); + printf(" "); + for(j = 0; j < 16; j++) + printf("%c", (b[i * 16 + j] >= ' ' && b[i * 16 + j] < 127) ? b[i * 16 + j] : ' '); + printf("\n"); + } + fsize -= BLOCKSIZE; + } +} + +// print block/char device minor and major +void print_dev(filesystem *fs, uint32 nod) +{ + int minor, major; + minor = ((uint8*)get_nod(fs, nod)->i_block)[0]; + major = ((uint8*)get_nod(fs, nod)->i_block)[1]; + printf("major: %d, minor: %d\n", major, minor); +} + +// print an inode as a directory +void print_dir(filesystem *fs, uint32 nod) +{ + blockwalker bw; + uint32 bk; + init_bw(fs, nod, &bw); + printf("directory for inode %d:\n", nod); + while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END) + { + directory *d; + uint8 *b; + b = get_blk(fs, bk); + for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len)) + if(d->d_inode) + { + int i; + printf("entry '"); + for(i = 0; i < d->d_name_len; i++) + putchar(d->d_name[i]); + printf("' (inode %d): rec_len: %d (name_len: %d)\n", d->d_inode, d->d_rec_len, d->d_name_len); + } + } +} + +// print a symbolic link +void print_link(filesystem *fs, uint32 nod) +{ + if(!get_nod(fs, nod)->i_blocks) + printf("links to '%s'\n", (char*)get_nod(fs, nod)->i_block); + else + { + printf("links to '"); + write_blocks(fs, nod, stdout); + printf("'\n"); + } +} + +// make a ls-like printout of permissions +void make_perms(uint32 mode, char perms[11]) +{ + strcpy(perms, "----------"); + if(mode & FM_IRUSR) + perms[1] = 'r'; + if(mode & FM_IWUSR) + perms[2] = 'w'; + if(mode & FM_IXUSR) + perms[3] = 'x'; + if(mode & FM_IRGRP) + perms[4] = 'r'; + if(mode & FM_IWGRP) + perms[5] = 'w'; + if(mode & FM_IXGRP) + perms[6] = 'x'; + if(mode & FM_IROTH) + perms[7] = 'r'; + if(mode & FM_IWOTH) + perms[8] = 'w'; + if(mode & FM_IXOTH) + perms[9] = 'x'; + if(mode & FM_ISUID) + perms[3] = 's'; + if(mode & FM_ISGID) + perms[6] = 's'; + if(mode & FM_ISVTX) + perms[9] = 't'; + switch(mode & FM_IFMT) + { + case 0: + *perms = '0'; + break; + case FM_IFSOCK: + *perms = 's'; + break; + case FM_IFLNK: + *perms = 'l'; + break; + case FM_IFREG: + *perms = '-'; + break; + case FM_IFBLK: + *perms = 'b'; + break; + case FM_IFDIR: + *perms = 'd'; + break; + case FM_IFCHR: + *perms = 'c'; + break; + case FM_IFIFO: + *perms = 'p'; + break; + default: + *perms = '?'; + } +} + +// print an inode +void print_inode(filesystem *fs, uint32 nod) +{ + char *s; + char perms[11]; + if(!get_nod(fs, nod)->i_mode) + return; + switch(nod) + { + case EXT2_BAD_INO: + s = "bad blocks"; + break; + case EXT2_ROOT_INO: + s = "root"; + break; + case EXT2_ACL_IDX_INO: + case EXT2_ACL_DATA_INO: + s = "ACL"; + break; + case EXT2_BOOT_LOADER_INO: + s = "boot loader"; + break; + case EXT2_UNDEL_DIR_INO: + s = "undelete directory"; + break; + default: + s = (nod >= EXT2_FIRST_INO) ? "normal" : "unknown reserved"; + } + printf("inode %d (%s, %d links): ", nod, s, get_nod(fs, nod)->i_links_count); + if(!allocated(fs->ibm, nod)) + { + printf("unallocated\n"); + return; + } + make_perms(get_nod(fs, nod)->i_mode, perms); + printf("%s, size: %d byte%s (%d block%s)\n", perms, plural(get_nod(fs, nod)->i_size), plural(get_nod(fs, nod)->i_blocks / INOBLK)); + switch(get_nod(fs, nod)->i_mode & FM_IFMT) + { + case FM_IFSOCK: + list_blocks(fs, nod); + break; + case FM_IFLNK: + print_link(fs, nod); + break; + case FM_IFREG: + list_blocks(fs, nod); + break; + case FM_IFBLK: + print_dev(fs, nod); + break; + case FM_IFDIR: + list_blocks(fs, nod); + print_dir(fs, nod); + break; + case FM_IFCHR: + print_dev(fs, nod); + break; + case FM_IFIFO: + list_blocks(fs, nod); + break; + default: + list_blocks(fs, nod); + } +} + +// describes various fields in a filesystem +void print_fs(filesystem *fs) +{ + int i; + printf("%d blocks (%d free, %d reserved), first data block: %d\n", fs->sb.s_blocks_count, fs->sb.s_free_blocks_count, fs->sb.s_r_blocks_count, fs->sb.s_first_data_block); + printf("%d inodes (%d free)\n", fs->sb.s_inodes_count, fs->sb.s_free_inodes_count); + printf("block size = %d, frag size = %d\n", fs->sb.s_log_block_size ? (fs->sb.s_log_block_size << 11) : 1024, fs->sb.s_log_frag_size ? (fs->sb.s_log_frag_size << 11) : 1024); + printf("%d blocks per group, %d frags per group, %d inodes per group\n", fs->sb.s_blocks_per_group, fs->sb.s_frags_per_group, fs->sb.s_inodes_per_group); + printf("block bitmap: block %d, inode bitmap: block %d, inode table: block %d\n", fs->gd.bg_block_bitmap, fs->gd.bg_inode_bitmap, fs->gd.bg_inode_table); + printf("block bitmap allocation:\n"); + print_bm(fs->bbm, fs->sb.s_blocks_count); + printf("inode bitmap allocation:\n"); + print_bm(fs->ibm, fs->sb.s_inodes_count); + for(i=1; i<=fs->sb.s_inodes_count; i++) + if(allocated(fs->ibm, i)) + print_inode(fs, i); +} + +void dump_fs(filesystem *fs, FILE * fh, int swapit) +{ + int nbblocks = fs->sb.s_blocks_count; + fs->sb.s_reserved[200] = 0; + if(swapit) + swap_goodfs(fs); + if(fwrite(fs, BLOCKSIZE, nbblocks, fh) < nbblocks) + pexit("output filesystem image"); + if(swapit) + swap_badfs(fs); +} + +char *simple_ltoa(unsigned long i) +{ + /* 21 digits plus null terminator, good for 64-bit or smaller ints */ + static char local[21]; + char *p = local; + *p-- = '\0'; + do { + *p-- = '0' + i % 10; + i /= 10; + } while (i > 0); + return p + 1; +} + +//# device list table +//# +///dev/mem c 640 0 0 1 1 0 0 - +static int interpret_table_entry(filesystem *fs, char *line) +{ + int status; + char type, path[40]; + uint32 nod, nod2; + char *name, *dir; + unsigned long uid=0, gid=0, mode=755; + unsigned long major=0, minor=0, start=0, increment=1, count=0; + + status = sscanf(line, "%40s %c %lo %lu %lu %lu %lu %lu %lu %lu", path, + &type, &mode, &uid, &gid, &major, &minor, &start, &increment, &count); + if (status<0) + return status; + + name = basename(path); + dir = dirname(path); + if(!(nod = find_path(fs, EXT2_ROOT_INO, dir))) + errexit("can't find directory '%s' to create '%s''", dir, name); + free(dir); + if((!strcmp(name, ".")) || (!strcmp(name, ".."))) + { + free(name); + return 1; + } + + switch(type) + { + case 'd': + mkdir_fs(fs, nod, name, mode|FM_IFDIR, uid, gid, time(NULL)); + break; + case 'c': + case 'b': + mode|= (type=='c')? FM_IFCHR : FM_IFBLK; + if (count > 0) { + int i, last; + char buf[80]; + last = start+(count*increment); + for(i = start; ii_block)[0] = minor+(i*increment-start); + ((uint8*)get_nod(fs, nod2)->i_block)[1] = major; + strncpy(buf, name, sizeof(buf)-1); + strncat(buf, simple_ltoa(i*increment), sizeof(buf)-1); + buf[79]='\0'; + //fprintf(stderr, "start=%ld, i=%d adding '%s'(%ld, %ld)\n", start, i, buf, major, minor+(i*increment-start)); + add2dir(fs, nod, nod2, buf, mode, uid, gid, time(NULL)); + } + } + else { + nod2 = alloc_nod(fs); + ((uint8*)get_nod(fs, nod2)->i_block)[0] = minor; + ((uint8*)get_nod(fs, nod2)->i_block)[1] = major; + add2dir(fs, nod, nod2, name, mode, uid, gid, time(NULL)); + } + break; + default: + errexit("%s: Type '%c' is not supported", path, type); + + } + free(name); + return 0; +} + +int parse_device_table(filesystem *fs, char *filename) +{ + FILE *file; + char *line; + int status = 0; + size_t length = 0; + struct stat statbuf; + + if (!filename) { + fprintf(stderr, "No filename specified.\n"); + return(1); + } + if (!(file = fopen(filename, "r"))) { + perror(filename); + return(1); + } + if (fstat(fileno(file), &statbuf) < 0) { + perror(filename); + return(1); + } + + if (statbuf.st_size < 10) { + fprintf(stderr, "%s: not a proper device table file\n", filename); + return(1); + } + + /* Looks ok so far. The general plan now is to read in one + * line at a time, check for leading comment delimiters ('#'), + * then try and parse the line as a device table. If we fail + * to parse things, try and help the poor fool to fix their + * device table with a useful error msg... */ + line = NULL; + while (getline(&line, &length, file) != -1) { + /* First trim off any whitespace */ + int len = strlen(line); + /* trim trailing whitespace */ + while ( len > 0 && isspace(line[len-1])) + line[--len]='\0'; + /* trim leading whitespace */ + memmove(line, &line[strspn(line, " \n\r\t\v")], len); + + /* If this is NOT a comment line, try to interpret it */ + if (length && *line!='#') { + if (interpret_table_entry(fs, line)) + status=1; + } + + free(line); + line = NULL; + } + + + return status; +} + +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ + +void showhelp(void) +{ + fprintf(stderr, "Usage: %s [options] image\n" + "Create an ext2 filesystem image from directories/files\n\n" + " -x image Use this image as a starting point\n" + " -d directory Add this directory as source\n" + " -f file Add nodes (e.g. devices) from this spec file\n" + " -b blocks Size in blocks\n" + " -i inodes Number of inodes\n" + " -r reserved Number of reserved blocks\n" + " -g path Generate a block map file for this path\n" + " -e value Fill unallocated blocks with value\n" + " -z Make files with holes\n" + " -n Do not squash permissions and owners. By default everythig is\n" + " owned by root. This perserves file permissions and owners.\n" + " -v Print resulting filesystem structure\n" + " -h Show this help\n\n" + "Example of spec file:\n" + "drwx /dev\n" + "crw- 10,190 /dev/lcd\n" + "brw- 1,0 /dev/ram0\n\n" + "Report bugs to xavier.bestel@free.fr\n", argv0); +} + +#define MAX_DOPT 128 +#define MAX_GOPT 128 + +#define MAX_FILENAME 255 + +extern char* optarg; +extern int optind, opterr, optopt; + +int main(int argc, char **argv) +{ + int nbblocks = -1; + int nbinodes = -1; + int nbresrvd = -1; + char * fsout = "-"; + char * fsin = 0; + char * dopt[MAX_DOPT]; + int didx = 0; + char * gopt[MAX_GOPT]; + int gidx = 0; + int verbose = 0; + int holes = 0; + int emptyval = 0; + uint16 endian = 1; + int bigendian = !*(char*)&endian; + filesystem *fs; + int i; + char c; + char * devtable = NULL; + + argv0 = argv[0]; + while((c = getopt(argc, argv, "D:x:f:d:b:i:r:g:e:zvhn")) != EOF) + switch(c) + { + case 'x': + fsin = optarg; + break; + case 'D': + devtable = optarg; + break; + case 'd': + case 'f': + dopt[didx++] = optarg; + break; + case 'b': + nbblocks = atoi(optarg); + break; + case 'i': + nbinodes = atoi(optarg); + break; + case 'r': + nbresrvd = atoi(optarg); + break; + case 'g': + gopt[gidx++] = optarg; + break; + case 'e': + emptyval = atoi(optarg); + break; + case 'z': + holes = 1; + break; + case 'n': + nosquash = 1; + break; + case 'v': + verbose = 1; + break; + case 'h': + showhelp(); + exit(0); + default: + exit(1); + } + if(optind < (argc - 1)) + errexit("too many arguments"); + if(optind == (argc - 1)) + fsout = argv[optind]; + if(fsin) + { + if(strcmp(fsin, "-")) + { + FILE * fh = fopen(fsin, "r"); + if(!fh) + pexit(fsin); + fs = load_fs(fh, bigendian); + fclose(fh); + } + else + fs = load_fs(stdin, bigendian); + } + else + { + if(nbblocks == -1) + errexit("filesystem size unspecified"); + if(nbinodes == -1) + nbinodes = nbblocks * BLOCKSIZE / rndup(BYTES_PER_INODE, BLOCKSIZE); + if(nbresrvd == -1) + nbresrvd = nbblocks * RESERVED_INODES; + fs = init_fs(nbblocks, nbinodes, nbresrvd, holes); + } + for(i = 0; i < didx; i++) + { + struct stat st; + FILE *fh; + char *pdir; + stat(dopt[i], &st); + switch(st.st_mode & S_IFMT) + { + case S_IFREG: + if(!(fh = fopen(dopt[i], "r"))) + pexit(dopt[i]); + add2fs_from_file(fs, EXT2_ROOT_INO, fh); + fclose(fh); + break; + case S_IFDIR: + if(!(pdir = getcwd(0, 0))) + pexit(dopt[i]); + if(chdir(dopt[i]) < 0) + pexit(dopt[i]); + add2fs_from_dir(fs, EXT2_ROOT_INO); + if(chdir(pdir) < 0) + pexit(pdir); + free(pdir); + break; + default: + errexit("%s in neither a file nor a directory", dopt[i]); + } + } + if(emptyval) + for(i = 1; i < fs->sb.s_blocks_count; i++) + if(!allocated(fs->bbm, i)) + memset(get_blk(fs, i), emptyval, BLOCKSIZE); + if(devtable) + parse_device_table(fs, devtable); + if(verbose) + print_fs(fs); + for(i = 0; i < gidx; i++) + { + uint32 nod; + char fname[MAX_FILENAME]; + char *p; + FILE *fh; + if(!(nod = find_path(fs, EXT2_ROOT_INO, gopt[i]))) + errexit("path %s not found in filesystem", gopt[i]); + while((p = strchr(gopt[i], '/'))) + *p = '_'; + snprintf(fname, MAX_FILENAME-1, "%s.blk", gopt[i]); + if(!(fh = fopen(fname, "w"))) + pexit(fname); + fprintf(fh, "%d:", get_nod(fs, nod)->i_size); + flist_blocks(fs, nod, fh); + fclose(fh); + } + if(strcmp(fsout, "-")) + { + FILE * fh = fopen(fsout, "w"); + if(!fh) + pexit(fsout); + dump_fs(fs, fh, bigendian); + fclose(fh); + } + else + dump_fs(fs, stdout, bigendian); + return 0; +} diff --git a/genext2fs/genext2fs.o b/genext2fs/genext2fs.o new file mode 100644 index 0000000000000000000000000000000000000000..82cbd501937c05218ced00b1c0e54196724367e0 GIT binary patch literal 27080 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 Aj{pDw literal 0 HcmV?d00001 diff --git a/genext2fs/gpl.txt b/genext2fs/gpl.txt new file mode 100644 index 0000000..c4ccd33 --- /dev/null +++ b/genext2fs/gpl.txt @@ -0,0 +1,342 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +