| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971 |
- [PATCH] update genext2fs.c to CVS rev 1.118
- See http://genext2fs.cvs.sourceforge.net/viewvc/genext2fs/genext2fs/genext2fs.c?view=log
- for details.
- Numerous bugfixes, large file and filesystem support, rev 1 filesystems,
- volume id support, block size, ..
- Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
- ---
- cache.h | 128 ++++
- genext2fs.c | 1870 ++++++++++++++++++++++++++++++++++++++++++------------------
- list.h | 78 ++
- 3 files changed, 1527 insertions(+), 549 deletions(-)
- Index: genext2fs-1.4.1/genext2fs.c
- ===================================================================
- --- genext2fs-1.4.1.orig/genext2fs.c
- +++ genext2fs-1.4.1/genext2fs.c
- @@ -53,6 +53,12 @@
- // along with -q, -P, -U
-
-
- +/*
- + * Allow fseeko/off_t to be 64-bit offsets to allow filesystems and
- + * individual files >2GB.
- + */
- +#define _FILE_OFFSET_BITS 64
- +
- #include <config.h>
- #include <stdio.h>
-
- @@ -107,10 +113,8 @@
-
- #if HAVE_DIRENT_H
- # include <dirent.h>
- -# define NAMLEN(dirent) strlen((dirent)->d_name)
- #else
- # define dirent direct
- -# define NAMLEN(dirent) (dirent)->d_namlen
- # if HAVE_SYS_NDIR_H
- # include <sys/ndir.h>
- # endif
- @@ -144,6 +148,8 @@
- # include <limits.h>
- #endif
-
- +#include "cache.h"
- +
- struct stats {
- unsigned long nblocks;
- unsigned long ninodes;
- @@ -151,13 +157,42 @@
-
- // block size
-
- -#define BLOCKSIZE 1024
- +static int blocksize = 1024;
- +
- +#define SUPERBLOCK_OFFSET 1024
- +#define SUPERBLOCK_SIZE 1024
- +
- +#define BLOCKSIZE blocksize
- #define BLOCKS_PER_GROUP 8192
- #define INODES_PER_GROUP 8192
- /* Percentage of blocks that are reserved.*/
- #define RESERVED_BLOCKS 5/100
- #define MAX_RESERVED_BLOCKS 25/100
-
- +/* The default value for s_creator_os. */
- +#if defined(__linux__) && defined(EXT2_OS_LINUX)
- +#define CREATOR_OS EXT2_OS_LINUX
- +#define CREATOR_OS_NAME "linux"
- +#else
- +#if defined(__GNU__) && defined(EXT2_OS_HURD)
- +#define CREATOR_OS EXT2_OS_HURD
- +#define CREATOR_OS_NAME "hurd"
- +#else
- +#if defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD)
- +#define CREATOR_OS EXT2_OS_FREEBSD
- +#define CREATOR_OS_NAME "freebsd"
- +#else
- +#if defined(LITES) && defined(EXT2_OS_LITES)
- +#define CREATOR_OS EXT2_OS_LITES
- +#define CREATOR_OS_NAME "lites"
- +#else
- +#define CREATOR_OS EXT2_OS_LINUX /* by default */
- +#define CREATOR_OS_NAME "linux"
- +#endif /* defined(LITES) && defined(EXT2_OS_LITES) */
- +#endif /* defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD) */
- +#endif /* defined(__GNU__) && defined(EXT2_OS_HURD) */
- +#endif /* defined(__linux__) && defined(EXT2_OS_LINUX) */
- +
-
- // inode block size (why is it != BLOCKSIZE ?!?)
- /* The field i_blocks in the ext2 inode stores the number of data blocks
- @@ -190,6 +225,14 @@
- #define EXT2_TIND_BLOCK 14 // triple indirect block
- #define EXT2_INIT_BLOCK 0xFFFFFFFF // just initialized (not really a block address)
-
- +// codes for operating systems
- +
- +#define EXT2_OS_LINUX 0
- +#define EXT2_OS_HURD 1
- +#define EXT2_OS_MASIX 2
- +#define EXT2_OS_FREEBSD 3
- +#define EXT2_OS_LITES 4
- +
- // end of a block walk
-
- #define WALK_END 0xFFFFFFFE
- @@ -227,44 +270,46 @@
- #define FM_IWOTH 0000002 // write
- #define FM_IXOTH 0000001 // execute
-
- -// options
- -
- -#define OP_HOLES 0x01 // make files with holes
- -
- /* Defines for accessing group details */
-
- // Number of groups in the filesystem
- #define GRP_NBGROUPS(fs) \
- - (((fs)->sb.s_blocks_count - fs->sb.s_first_data_block + \
- - (fs)->sb.s_blocks_per_group - 1) / (fs)->sb.s_blocks_per_group)
- + (((fs)->sb->s_blocks_count - fs->sb->s_first_data_block + \
- + (fs)->sb->s_blocks_per_group - 1) / (fs)->sb->s_blocks_per_group)
-
- // Get group block bitmap (bbm) given the group number
- -#define GRP_GET_GROUP_BBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_block_bitmap) )
- +#define GRP_GET_GROUP_BBM(fs,grp,bi) (get_blk((fs),(grp)->bg_block_bitmap,(bi)))
- +#define GRP_PUT_GROUP_BBM(bi) ( put_blk((bi)) )
-
- // Get group inode bitmap (ibm) given the group number
- -#define GRP_GET_GROUP_IBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_inode_bitmap) )
- -
- +#define GRP_GET_GROUP_IBM(fs,grp,bi) (get_blk((fs), (grp)->bg_inode_bitmap,(bi)))
- +#define GRP_PUT_GROUP_IBM(bi) ( put_blk((bi)) )
- +
- // Given an inode number find the group it belongs to
- -#define GRP_GROUP_OF_INODE(fs,nod) ( ((nod)-1) / (fs)->sb.s_inodes_per_group)
- +#define GRP_GROUP_OF_INODE(fs,nod) ( ((nod)-1) / (fs)->sb->s_inodes_per_group)
-
- //Given an inode number get the inode bitmap that covers it
- -#define GRP_GET_INODE_BITMAP(fs,nod) \
- - ( GRP_GET_GROUP_IBM((fs),GRP_GROUP_OF_INODE((fs),(nod))) )
- +#define GRP_GET_INODE_BITMAP(fs,nod,bi,gi) \
- + ( GRP_GET_GROUP_IBM((fs),get_gd(fs,GRP_GROUP_OF_INODE((fs),(nod)),gi),bi) )
- +#define GRP_PUT_INODE_BITMAP(bi,gi) \
- + ( GRP_PUT_GROUP_IBM((bi)),put_gd((gi)) )
-
- //Given an inode number find its offset within the inode bitmap that covers it
- #define GRP_IBM_OFFSET(fs,nod) \
- - ( (nod) - GRP_GROUP_OF_INODE((fs),(nod))*(fs)->sb.s_inodes_per_group )
- + ( (nod) - GRP_GROUP_OF_INODE((fs),(nod))*(fs)->sb->s_inodes_per_group )
-
- // Given a block number find the group it belongs to
- -#define GRP_GROUP_OF_BLOCK(fs,blk) ( ((blk)-1) / (fs)->sb.s_blocks_per_group)
- +#define GRP_GROUP_OF_BLOCK(fs,blk) ( ((blk)-1) / (fs)->sb->s_blocks_per_group)
-
- -//Given a block number get the block bitmap that covers it
- -#define GRP_GET_BLOCK_BITMAP(fs,blk) \
- - ( GRP_GET_GROUP_BBM((fs),GRP_GROUP_OF_BLOCK((fs),(blk))) )
- +//Given a block number get/put the block bitmap that covers it
- +#define GRP_GET_BLOCK_BITMAP(fs,blk,bi,gi) \
- + ( GRP_GET_GROUP_BBM((fs),get_gd(fs,GRP_GROUP_OF_BLOCK((fs),(blk)),(gi)),(bi)) )
- +#define GRP_PUT_BLOCK_BITMAP(bi,gi) \
- + ( GRP_PUT_GROUP_BBM((bi)),put_gd((gi)) )
-
- //Given a block number find its offset within the block bitmap that covers it
- #define GRP_BBM_OFFSET(fs,blk) \
- - ( (blk) - GRP_GROUP_OF_BLOCK((fs),(blk))*(fs)->sb.s_blocks_per_group )
- + ( (blk) - GRP_GROUP_OF_BLOCK((fs),(blk))*(fs)->sb->s_blocks_per_group )
-
-
- // used types
- @@ -286,7 +331,9 @@
- // older solaris. Note that this is still not very portable, in that
- // the return value cannot be trusted.
-
- -#if SCANF_CAN_MALLOC
- +#if 0 // SCANF_CAN_MALLOC
- +// C99 define "a" for floating point, so you can have runtime surprise
- +// according the library versions
- # define SCANF_PREFIX "a"
- # define SCANF_STRING(s) (&s)
- #else
- @@ -430,6 +477,17 @@
- ((val<<8)&0xFF0000) | (val<<24));
- }
-
- +static inline int
- +is_blk_empty(uint8 *b)
- +{
- + uint32 i;
- + uint32 *v = (uint32 *) b;
- +
- + for(i = 0; i < BLOCKSIZE / 4; i++)
- + if (*v++)
- + return 0;
- + return 1;
- +}
-
- // on-disk structures
- // this trick makes me declare things only once
- @@ -460,7 +518,22 @@
- 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 */
- + udecl16(s_def_resgid) /* The default gid for reserved blocks */ \
- + /* rev 1 version fields start here */ \
- + udecl32(s_first_ino) /* First non-reserved inode */ \
- + udecl16(s_inode_size) /* size of inode structure */ \
- + udecl16(s_block_group_nr) /* block group # of this superblock */ \
- + udecl32(s_feature_compat) /* compatible feature set */ \
- + udecl32(s_feature_incompat) /* incompatible feature set */ \
- + udecl32(s_feature_ro_compat) /* readonly-compatible feature set */ \
- + utdecl8(s_uuid,16) /* 128-bit uuid for volume */ \
- + utdecl8(s_volume_name,16) /* volume name */ \
- + utdecl8(s_last_mounted,64) /* directory where last mounted */ \
- + udecl32(s_algorithm_usage_bitmap) /* For compression */
- +
- +#define EXT2_GOOD_OLD_FIRST_INO 11
- +#define EXT2_GOOD_OLD_INODE_SIZE 128
- +#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
-
- #define groupdescriptor_decl \
- udecl32(bg_block_bitmap) /* Block number of the block bitmap */ \
- @@ -500,6 +573,7 @@
-
- #define decl8(x) int8 x;
- #define udecl8(x) uint8 x;
- +#define utdecl8(x,n) uint8 x[n];
- #define decl16(x) int16 x;
- #define udecl16(x) uint16 x;
- #define decl32(x) int32 x;
- @@ -509,7 +583,7 @@
- typedef struct
- {
- superblock_decl
- - uint32 s_reserved[235]; // Reserved
- + uint32 s_reserved[205]; // Reserved
- } superblock;
-
- typedef struct
- @@ -527,10 +601,9 @@
- typedef struct
- {
- directory_decl
- - char d_name[0];
- } directory;
-
- -typedef uint8 block[BLOCKSIZE];
- +typedef uint8 *block;
-
- /* blockwalker fields:
- The blockwalker is used to access all the blocks of a file (including
- @@ -567,23 +640,41 @@
- uint32 bptind;
- } blockwalker;
-
- +#define HDLINK_CNT 16
- +struct hdlink_s
- +{
- + uint32 src_inode;
- + uint32 dst_nod;
- +};
- +
- +struct hdlinks_s
- +{
- + int32 count;
- + struct hdlink_s *hdl;
- +};
-
- /* Filesystem structure that support groups */
- -#if BLOCKSIZE == 1024
- typedef struct
- {
- - block zero; // The famous block 0
- - superblock sb; // The superblock
- - groupdescriptor gd[0]; // The group descriptors
- + FILE *f;
- + superblock *sb;
- + int swapit;
- + int32 hdlink_cnt;
- + struct hdlinks_s hdlinks;
- +
- + int holes;
- +
- + listcache blks;
- + listcache gds;
- + listcache inodes;
- + listcache blkmaps;
- } filesystem;
- -#else
- -#error UNHANDLED BLOCKSIZE
- -#endif
-
- // now the endianness swap
-
- #undef decl8
- #undef udecl8
- +#undef utdecl8
- #undef decl16
- #undef udecl16
- #undef decl32
- @@ -592,28 +683,13 @@
-
- #define decl8(x)
- #define udecl8(x)
- +#define utdecl8(x,n)
- #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; i<n; i++) this->x[i] = swab32(this->x[i]); }
-
- -#define HDLINK_CNT 16
- -static int32 hdlink_cnt = HDLINK_CNT;
- -struct hdlink_s
- -{
- - uint32 src_inode;
- - uint32 dst_nod;
- -};
- -
- -struct hdlinks_s
- -{
- - int32 count;
- - struct hdlink_s *hdl;
- -};
- -
- -static struct hdlinks_s hdlinks;
- -
- static void
- swap_sb(superblock *sb)
- {
- @@ -633,9 +709,24 @@
- static void
- swap_nod(inode *nod)
- {
- + uint32 nblk;
- +
- #define this nod
- inode_decl
- #undef this
- +
- + // block and character inodes store the major and minor in the
- + // i_block, so we need to unswap to get those. Also, if it's
- + // zero iblocks, put the data back like it belongs.
- + nblk = nod->i_blocks / INOBLK;
- + if ((nod->i_size && !nblk)
- + || ((nod->i_mode & FM_IFBLK) == FM_IFBLK)
- + || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
- + {
- + int i;
- + for(i = 0; i <= EXT2_TIND_BLOCK; i++)
- + nod->i_block[i] = swab32(nod->i_block[i]);
- + }
- }
-
- static void
- @@ -657,6 +748,7 @@
-
- #undef decl8
- #undef udecl8
- +#undef utdecl8
- #undef decl16
- #undef udecl16
- #undef decl32
- @@ -770,15 +862,15 @@
- }
-
- int
- -is_hardlink(ino_t inode)
- +is_hardlink(filesystem *fs, ino_t inode)
- {
- int i;
-
- - for(i = 0; i < hdlinks.count; i++) {
- - if(hdlinks.hdl[i].src_inode == inode)
- + for(i = 0; i < fs->hdlinks.count; i++) {
- + if(fs->hdlinks.hdl[i].src_inode == inode)
- return i;
- }
- - return -1;
- + return -1;
- }
-
- // printf helper macro
- @@ -789,6 +881,8 @@
- get_workblk(void)
- {
- unsigned char* b=calloc(1,BLOCKSIZE);
- + if (!b)
- + error_msg_and_die("get_workblk() failed, out of memory");
- return b;
- }
- static inline void
- @@ -811,24 +905,464 @@
- return b[(item-1) / 8] & (1 << ((item-1) % 8));
- }
-
- -// return a given block from a filesystem
- +// Used by get_blk/put_blk to hold information about a block owned
- +// by the user.
- +typedef struct
- +{
- + cache_link link;
- +
- + filesystem *fs;
- + uint32 blk;
- + uint8 *b;
- + uint32 usecount;
- +} blk_info;
- +
- +#define MAX_FREE_CACHE_BLOCKS 100
- +
- +static uint32
- +blk_elem_val(cache_link *elem)
- +{
- + blk_info *bi = container_of(elem, blk_info, link);
- + return bi->blk;
- +}
- +
- +static void
- +blk_freed(cache_link *elem)
- +{
- + blk_info *bi = container_of(elem, blk_info, link);
- +
- + if (fseeko(bi->fs->f, ((off_t) bi->blk) * BLOCKSIZE, SEEK_SET))
- + perror_msg_and_die("fseek");
- + if (fwrite(bi->b, BLOCKSIZE, 1, bi->fs->f) != 1)
- + perror_msg_and_die("get_blk: write");
- + free(bi->b);
- + free(bi);
- +}
- +
- +// Return a given block from a filesystem. Make sure to call
- +// put_blk when you are done with it.
- static inline uint8 *
- -get_blk(filesystem *fs, uint32 blk)
- +get_blk(filesystem *fs, uint32 blk, blk_info **rbi)
- {
- - return (uint8*)fs + blk*BLOCKSIZE;
- + cache_link *curr;
- + blk_info *bi;
- +
- + if (blk >= fs->sb->s_blocks_count)
- + error_msg_and_die("Internal error, block out of range");
- +
- + curr = cache_find(&fs->blks, blk);
- + if (curr) {
- + bi = container_of(curr, blk_info, link);
- + bi->usecount++;
- + goto out;
- + }
- +
- + bi = malloc(sizeof(*bi));
- + if (!bi)
- + error_msg_and_die("get_blk: out of memory");
- + bi->fs = fs;
- + bi->blk = blk;
- + bi->usecount = 1;
- + bi->b = malloc(BLOCKSIZE);
- + if (!bi->b)
- + error_msg_and_die("get_blk: out of memory");
- + cache_add(&fs->blks, &bi->link);
- + if (fseeko(fs->f, ((off_t) blk) * BLOCKSIZE, SEEK_SET))
- + perror_msg_and_die("fseek");
- + if (fread(bi->b, BLOCKSIZE, 1, fs->f) != 1) {
- + if (ferror(fs->f))
- + perror_msg_and_die("fread");
- + memset(bi->b, 0, BLOCKSIZE);
- + }
- +
- +out:
- + *rbi = bi;
- + return bi->b;
- }
-
- // return a given inode from a filesystem
- -static inline inode *
- -get_nod(filesystem *fs, uint32 nod)
- +static inline void
- +put_blk(blk_info *bi)
- +{
- + if (bi->usecount == 0)
- + error_msg_and_die("Internal error: put_blk usecount zero");
- + bi->usecount--;
- + if (bi->usecount == 0)
- + /* Free happens in the cache code */
- + cache_item_set_unused(&bi->fs->blks, &bi->link);
- +}
- +
- +typedef struct
- {
- - int grp,offset;
- + cache_link link;
- +
- + filesystem *fs;
- + int gds;
- + blk_info *bi;
- + groupdescriptor *gd;
- + uint32 usecount;
- +} gd_info;
- +
- +#define MAX_FREE_CACHE_GDS 100
- +
- +static uint32
- +gd_elem_val(cache_link *elem)
- +{
- + gd_info *gi = container_of(elem, gd_info, link);
- + return gi->gds;
- +}
- +
- +static void
- +gd_freed(cache_link *elem)
- +{
- + gd_info *gi = container_of(elem, gd_info, link);
- +
- + if (gi->fs->swapit)
- + swap_gd(gi->gd);
- + put_blk(gi->bi);
- + free(gi);
- +}
- +
- +#define GDS_START ((SUPERBLOCK_OFFSET + SUPERBLOCK_SIZE + BLOCKSIZE - 1) / BLOCKSIZE)
- +#define GDS_PER_BLOCK (BLOCKSIZE / sizeof(groupdescriptor))
- +// the group descriptors are aligned on the block size
- +static inline groupdescriptor *
- +get_gd(filesystem *fs, uint32 no, gd_info **rgi)
- +{
- + uint32 gdblk;
- + uint32 offset;
- + gd_info *gi;
- + cache_link *curr;
- +
- + curr = cache_find(&fs->gds, no);
- + if (curr) {
- + gi = container_of(curr, gd_info, link);
- + gi->usecount++;
- + goto out;
- + }
- +
- + gi = malloc(sizeof(*gi));
- + if (!gi)
- + error_msg_and_die("get_gd: out of memory");
- + gi->fs = fs;
- + gi->gds = no;
- + gi->usecount = 1;
- + gdblk = GDS_START + (no / GDS_PER_BLOCK);
- + offset = no % GDS_PER_BLOCK;
- + gi->gd = ((groupdescriptor *) get_blk(fs, gdblk, &gi->bi)) + offset;
- + cache_add(&fs->gds, &gi->link);
- + if (fs->swapit)
- + swap_gd(gi->gd);
- + out:
- + *rgi = gi;
- +
- + return gi->gd;
- +}
- +
- +static inline void
- +put_gd(gd_info *gi)
- +{
- + if (gi->usecount == 0)
- + error_msg_and_die("Internal error: put_gd usecount zero");
- +
- + gi->usecount--;
- + if (gi->usecount == 0)
- + /* Free happens in the cache code */
- + cache_item_set_unused(&gi->fs->gds, &gi->link);
- +}
- +
- +// Used by get_blkmap/put_blkmap to hold information about an block map
- +// owned by the user.
- +typedef struct
- +{
- + cache_link link;
- +
- + filesystem *fs;
- + uint32 blk;
- + uint8 *b;
- + blk_info *bi;
- + uint32 usecount;
- +} blkmap_info;
- +
- +#define MAX_FREE_CACHE_BLOCKMAPS 100
- +
- +static uint32
- +blkmap_elem_val(cache_link *elem)
- +{
- + blkmap_info *bmi = container_of(elem, blkmap_info, link);
- + return bmi->blk;
- +}
- +
- +static void
- +blkmap_freed(cache_link *elem)
- +{
- + blkmap_info *bmi = container_of(elem, blkmap_info, link);
- +
- + if (bmi->fs->swapit)
- + swap_block(bmi->b);
- + put_blk(bmi->bi);
- + free(bmi);
- +}
- +
- +// Return a given block map from a filesystem. Make sure to call
- +// put_blkmap when you are done with it.
- +static inline uint32 *
- +get_blkmap(filesystem *fs, uint32 blk, blkmap_info **rbmi)
- +{
- + blkmap_info *bmi;
- + cache_link *curr;
- +
- + curr = cache_find(&fs->blkmaps, blk);
- + if (curr) {
- + bmi = container_of(curr, blkmap_info, link);
- + bmi->usecount++;
- + goto out;
- + }
- +
- + bmi = malloc(sizeof(*bmi));
- + if (!bmi)
- + error_msg_and_die("get_blkmap: out of memory");
- + bmi->fs = fs;
- + bmi->blk = blk;
- + bmi->b = get_blk(fs, blk, &bmi->bi);
- + bmi->usecount = 1;
- + cache_add(&fs->blkmaps, &bmi->link);
- +
- + if (fs->swapit)
- + swap_block(bmi->b);
- + out:
- + *rbmi = bmi;
- + return (uint32 *) bmi->b;
- +}
- +
- +static inline void
- +put_blkmap(blkmap_info *bmi)
- +{
- + if (bmi->usecount == 0)
- + error_msg_and_die("Internal error: put_blkmap usecount zero");
- +
- + bmi->usecount--;
- + if (bmi->usecount == 0)
- + /* Free happens in the cache code */
- + cache_item_set_unused(&bmi->fs->blkmaps, &bmi->link);
- +}
- +
- +// Used by get_nod/put_nod to hold information about an inode owned
- +// by the user.
- +typedef struct
- +{
- + cache_link link;
- +
- + filesystem *fs;
- + uint32 nod;
- + uint8 *b;
- + blk_info *bi;
- inode *itab;
- + uint32 usecount;
- +} nod_info;
- +
- +#define MAX_FREE_CACHE_INODES 100
- +
- +static uint32
- +inode_elem_val(cache_link *elem)
- +{
- + nod_info *ni = container_of(elem, nod_info, link);
- + return ni->nod;
- +}
- +
- +static void
- +inode_freed(cache_link *elem)
- +{
- + nod_info *ni = container_of(elem, nod_info, link);
- +
- + if (ni->fs->swapit)
- + swap_nod(ni->itab);
- + put_blk(ni->bi);
- + free(ni);
- +}
- +
- +#define INODES_PER_BLOCK (BLOCKSIZE / sizeof(inode))
-
- - offset = GRP_IBM_OFFSET(fs,nod);
- +// return a given inode from a filesystem
- +static inline inode *
- +get_nod(filesystem *fs, uint32 nod, nod_info **rni)
- +{
- + uint32 grp, boffset, offset;
- + cache_link *curr;
- + groupdescriptor *gd;
- + gd_info *gi;
- + nod_info *ni;
- +
- + curr = cache_find(&fs->inodes, nod);
- + if (curr) {
- + ni = container_of(curr, nod_info, link);
- + ni->usecount++;
- + goto out;
- + }
- +
- + ni = malloc(sizeof(*ni));
- + if (!ni)
- + error_msg_and_die("get_nod: out of memory");
- + ni->fs = fs;
- + ni->nod = nod;
- + ni->usecount = 1;
- + cache_add(&fs->inodes, &ni->link);
- +
- + offset = GRP_IBM_OFFSET(fs,nod) - 1;
- + boffset = offset / INODES_PER_BLOCK;
- + offset %= INODES_PER_BLOCK;
- grp = GRP_GROUP_OF_INODE(fs,nod);
- - itab = (inode *)get_blk(fs, fs->gd[grp].bg_inode_table);
- - return itab+offset-1;
- + gd = get_gd(fs, grp, &gi);
- + ni->b = get_blk(fs, gd->bg_inode_table + boffset, &ni->bi);
- + ni->itab = ((inode *) ni->b) + offset;
- + if (fs->swapit)
- + swap_nod(ni->itab);
- + put_gd(gi);
- + out:
- + *rni = ni;
- + return ni->itab;
- +}
- +
- +static inline void
- +put_nod(nod_info *ni)
- +{
- + if (ni->usecount == 0)
- + error_msg_and_die("Internal error: put_nod usecount zero");
- +
- + ni->usecount--;
- + if (ni->usecount == 0)
- + /* Free happens in the cache code */
- + cache_item_set_unused(&ni->fs->inodes, &ni->link);
- +}
- +
- +// Used to hold state information while walking a directory inode.
- +typedef struct
- +{
- + directory d;
- + filesystem *fs;
- + uint32 nod;
- + directory *last_d;
- + uint8 *b;
- + blk_info *bi;
- +} dirwalker;
- +
- +// Start a directory walk on the given inode. You must pass in a
- +// dirwalker structure, then use that dirwalker for future operations.
- +// Call put_dir when you are done walking the directory.
- +static inline directory *
- +get_dir(filesystem *fs, uint32 nod, dirwalker *dw)
- +{
- + dw->fs = fs;
- + dw->b = get_blk(fs, nod, &dw->bi);
- + dw->nod = nod;
- + dw->last_d = (directory *) dw->b;
- +
- + memcpy(&dw->d, dw->last_d, sizeof(directory));
- + if (fs->swapit)
- + swap_dir(&dw->d);
- + return &dw->d;
- +}
- +
- +// Move to the next directory.
- +static inline directory *
- +next_dir(dirwalker *dw)
- +{
- + directory *next_d = (directory *)((int8*)dw->last_d + dw->d.d_rec_len);
- +
- + if (dw->fs->swapit)
- + swap_dir(&dw->d);
- + memcpy(dw->last_d, &dw->d, sizeof(directory));
- +
- + if (((int8 *) next_d) >= ((int8 *) dw->b + BLOCKSIZE))
- + return NULL;
- +
- + dw->last_d = next_d;
- + memcpy(&dw->d, next_d, sizeof(directory));
- + if (dw->fs->swapit)
- + swap_dir(&dw->d);
- + return &dw->d;
- +}
- +
- +// Call then when you are done with the directory walk.
- +static inline void
- +put_dir(dirwalker *dw)
- +{
- + if (dw->fs->swapit)
- + swap_dir(&dw->d);
- + memcpy(dw->last_d, &dw->d, sizeof(directory));
- +
- + if (dw->nod == 0)
- + free_workblk(dw->b);
- + else
- + put_blk(dw->bi);
- +}
- +
- +// Create a new directory block with the given inode as it's destination
- +// and append it to the current dirwalker.
- +static directory *
- +new_dir(filesystem *fs, uint32 dnod, const char *name, int nlen, dirwalker *dw)
- +{
- + directory *d;
- +
- + dw->fs = fs;
- + dw->b = get_workblk();
- + dw->nod = 0;
- + dw->last_d = (directory *) dw->b;
- + d = &dw->d;
- + d->d_inode = dnod;
- + d->d_rec_len = BLOCKSIZE;
- + d->d_name_len = nlen;
- + strncpy(((char *) dw->last_d) + sizeof(directory), name, nlen);
- + return d;
- +}
- +
- +// Shrink the current directory entry, make a new one with the free
- +// space, and return the new directory entry (making it current).
- +static inline directory *
- +shrink_dir(dirwalker *dw, uint32 nod, const char *name, int nlen)
- +{
- + int reclen, preclen;
- + directory *d = &dw->d;
- +
- + reclen = d->d_rec_len;
- + d->d_rec_len = sizeof(directory) + rndup(d->d_name_len, 4);
- + preclen = d->d_rec_len;
- + reclen -= preclen;
- + if (dw->fs->swapit)
- + swap_dir(&dw->d);
- + memcpy(dw->last_d, &dw->d, sizeof(directory));
- +
- + dw->last_d = (directory *) (((int8 *) dw->last_d) + preclen);
- + d->d_rec_len = reclen;
- + d->d_inode = nod;
- + d->d_name_len = nlen;
- + strncpy(((char *) dw->last_d) + sizeof(directory), name, nlen);
- +
- + return d;
- +}
- +
- +// Return the current block the directory is walking
- +static inline uint8 *
- +dir_data(dirwalker *dw)
- +{
- + return dw->b;
- +}
- +
- +// Return the pointer to the name for the current directory
- +static inline char *
- +dir_name(dirwalker *dw)
- +{
- + return ((char *) dw->last_d) + sizeof(directory);
- +}
- +
- +// Set the name for the current directory. Note that this doesn't
- +// verify that there is space for the directory name, you must do
- +// that yourself.
- +static void
- +dir_set_name(dirwalker *dw, const char *name, int nlen)
- +{
- + dw->d.d_name_len = nlen;
- + strncpy(((char *) dw->last_d) + sizeof(directory), name, nlen);
- }
-
- // allocate a given block/inode in the bitmap
- @@ -870,21 +1404,34 @@
- {
- uint32 bk=0;
- uint32 grp,nbgroups;
- + blk_info *bi;
- + groupdescriptor *gd;
- + gd_info *gi;
-
- grp = GRP_GROUP_OF_INODE(fs,nod);
- nbgroups = GRP_NBGROUPS(fs);
- - if(!(bk = allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap), 0))) {
- - for(grp=0;grp<nbgroups && !bk;grp++)
- - bk=allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap),0);
- + gd = get_gd(fs, grp, &gi);
- + bk = allocate(GRP_GET_GROUP_BBM(fs, gd, &bi), 0);
- + GRP_PUT_GROUP_BBM(bi);
- + put_gd(gi);
- + if (!bk) {
- + for (grp=0; grp<nbgroups && !bk; grp++) {
- + gd = get_gd(fs, grp, &gi);
- + bk = allocate(GRP_GET_GROUP_BBM(fs, gd, &bi), 0);
- + GRP_PUT_GROUP_BBM(bi);
- + put_gd(gi);
- + }
- grp--;
- }
- if (!bk)
- error_msg_and_die("couldn't allocate a block (no free space)");
- - if(!(fs->gd[grp].bg_free_blocks_count--))
- + gd = get_gd(fs, grp, &gi);
- + if(!(gd->bg_free_blocks_count--))
- error_msg_and_die("group descr %d. free blocks count == 0 (corrupted fs?)",grp);
- - if(!(fs->sb.s_free_blocks_count--))
- + put_gd(gi);
- + if(!(fs->sb->s_free_blocks_count--))
- error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
- - return fs->sb.s_blocks_per_group*grp + bk;
- + return fs->sb->s_first_data_block + fs->sb->s_blocks_per_group*grp + (bk-1);
- }
-
- // free a block
- @@ -892,12 +1439,18 @@
- free_blk(filesystem *fs, uint32 bk)
- {
- uint32 grp;
- -
- - grp = bk / fs->sb.s_blocks_per_group;
- - bk %= fs->sb.s_blocks_per_group;
- - deallocate(get_blk(fs,fs->gd[grp].bg_block_bitmap), bk);
- - fs->gd[grp].bg_free_blocks_count++;
- - fs->sb.s_free_blocks_count++;
- + blk_info *bi;
- + gd_info *gi;
- + groupdescriptor *gd;
- +
- + grp = bk / fs->sb->s_blocks_per_group;
- + bk %= fs->sb->s_blocks_per_group;
- + gd = get_gd(fs, grp, &gi);
- + deallocate(GRP_GET_GROUP_BBM(fs, gd, &bi), bk);
- + GRP_PUT_GROUP_BBM(bi);
- + gd->bg_free_blocks_count++;
- + put_gd(gi);
- + fs->sb->s_free_blocks_count++;
- }
-
- // allocate an inode
- @@ -906,6 +1459,9 @@
- {
- uint32 nod,best_group=0;
- uint32 grp,nbgroups,avefreei;
- + blk_info *bi;
- + gd_info *gi, *bestgi;
- + groupdescriptor *gd, *bestgd;
-
- nbgroups = GRP_NBGROUPS(fs);
-
- @@ -914,22 +1470,32 @@
- /* find the one with the most free blocks and allocate node there */
- /* Idea from find_group_dir in fs/ext2/ialloc.c in 2.4.19 kernel */
- /* We do it for all inodes. */
- - avefreei = fs->sb.s_free_inodes_count / nbgroups;
- + avefreei = fs->sb->s_free_inodes_count / nbgroups;
- + bestgd = get_gd(fs, best_group, &bestgi);
- for(grp=0; grp<nbgroups; grp++) {
- - if (fs->gd[grp].bg_free_inodes_count < avefreei ||
- - fs->gd[grp].bg_free_inodes_count == 0)
- + gd = get_gd(fs, grp, &gi);
- + if (gd->bg_free_inodes_count < avefreei ||
- + gd->bg_free_inodes_count == 0) {
- + put_gd(gi);
- continue;
- - if (!best_group ||
- - fs->gd[grp].bg_free_blocks_count > fs->gd[best_group].bg_free_blocks_count)
- + }
- + if (!best_group || gd->bg_free_blocks_count > bestgd->bg_free_blocks_count) {
- + put_gd(bestgi);
- best_group = grp;
- + bestgd = gd;
- + bestgi = gi;
- + } else
- + put_gd(gi);
- }
- - if (!(nod = allocate(get_blk(fs,fs->gd[best_group].bg_inode_bitmap),0)))
- + if (!(nod = allocate(GRP_GET_GROUP_IBM(fs, bestgd, &bi), 0)))
- error_msg_and_die("couldn't allocate an inode (no free inode)");
- - if(!(fs->gd[best_group].bg_free_inodes_count--))
- + GRP_PUT_GROUP_IBM(bi);
- + if(!(bestgd->bg_free_inodes_count--))
- error_msg_and_die("group descr. free blocks count == 0 (corrupted fs?)");
- - if(!(fs->sb.s_free_inodes_count--))
- + put_gd(bestgi);
- + if(!(fs->sb->s_free_inodes_count--))
- error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
- - return fs->sb.s_inodes_per_group*best_group+nod;
- + return fs->sb->s_inodes_per_group*best_group+nod;
- }
-
- // print a bitmap allocation
- @@ -962,30 +1528,40 @@
- // used after being freed, so once you start
- // freeing blocks don't stop until the end of
- // the file. moreover, i_blocks isn't updated.
- -// in fact, don't do that, just use extend_blk
- // if hole!=0, create a hole in the file
- static uint32
- walk_bw(filesystem *fs, uint32 nod, blockwalker *bw, int32 *create, uint32 hole)
- {
- uint32 *bkref = 0;
- + uint32 bk = 0;
- + blkmap_info *bmi1 = NULL, *bmi2 = NULL, *bmi3 = NULL;
- uint32 *b;
- int extend = 0, reduce = 0;
- + inode *inod;
- + nod_info *ni;
- + uint32 *iblk;
- +
- if(create && (*create) < 0)
- reduce = 1;
- - if(bw->bnum >= get_nod(fs, nod)->i_blocks / INOBLK)
- + inod = get_nod(fs, nod, &ni);
- + if(bw->bnum >= inod->i_blocks / INOBLK)
- {
- if(create && (*create) > 0)
- {
- (*create)--;
- extend = 1;
- }
- - else
- + else
- + {
- + put_nod(ni);
- return WALK_END;
- + }
- }
- + iblk = inod->i_block;
- // first direct block
- if(bw->bpdir == EXT2_INIT_BLOCK)
- {
- - bkref = &get_nod(fs, nod)->i_block[bw->bpdir = 0];
- + bkref = &iblk[bw->bpdir = 0];
- if(extend) // allocate first block
- *bkref = hole ? 0 : alloc_blk(fs,nod);
- if(reduce) // free first block
- @@ -994,7 +1570,7 @@
- // direct block
- else if(bw->bpdir < EXT2_NDIR_BLOCKS)
- {
- - bkref = &get_nod(fs, nod)->i_block[++bw->bpdir];
- + bkref = &iblk[++bw->bpdir];
- if(extend) // allocate block
- *bkref = hole ? 0 : alloc_blk(fs,nod);
- if(reduce) // free block
- @@ -1007,10 +1583,10 @@
- bw->bpdir = EXT2_IND_BLOCK;
- bw->bpind = 0;
- if(extend) // allocate indirect block
- - get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
- + iblk[bw->bpdir] = alloc_blk(fs,nod);
- if(reduce) // free indirect block
- - free_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
- - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
- + free_blk(fs, iblk[bw->bpdir]);
- + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
- bkref = &b[bw->bpind];
- if(extend) // allocate first block
- *bkref = hole ? 0 : alloc_blk(fs,nod);
- @@ -1021,7 +1597,7 @@
- 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]);
- + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
- bkref = &b[bw->bpind];
- if(extend) // allocate block
- *bkref = hole ? 0 : alloc_blk(fs,nod);
- @@ -1036,15 +1612,15 @@
- bw->bpind = 0;
- bw->bpdind = 0;
- if(extend) // allocate double indirect block
- - get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
- + iblk[bw->bpdir] = alloc_blk(fs,nod);
- if(reduce) // free double indirect block
- - free_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
- - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
- + free_blk(fs, iblk[bw->bpdir]);
- + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
- if(extend) // allocate first indirect block
- b[bw->bpind] = alloc_blk(fs,nod);
- if(reduce) // free firstindirect block
- free_blk(fs, b[bw->bpind]);
- - b = (uint32*)get_blk(fs, b[bw->bpind]);
- + b = get_blkmap(fs, b[bw->bpind], &bmi2);
- bkref = &b[bw->bpdind];
- if(extend) // allocate first block
- *bkref = hole ? 0 : alloc_blk(fs,nod);
- @@ -1055,8 +1631,8 @@
- 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]);
- + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
- + b = get_blkmap(fs, b[bw->bpind], &bmi2);
- bkref = &b[bw->bpdind];
- if(extend) // allocate block
- *bkref = hole ? 0 : alloc_blk(fs,nod);
- @@ -1069,12 +1645,12 @@
- bw->bnum++;
- bw->bpdind = 0;
- bw->bpind++;
- - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
- + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
- if(extend) // allocate indirect block
- b[bw->bpind] = alloc_blk(fs,nod);
- if(reduce) // free indirect block
- free_blk(fs, b[bw->bpind]);
- - b = (uint32*)get_blk(fs, b[bw->bpind]);
- + b = get_blkmap(fs, b[bw->bpind], &bmi2);
- bkref = &b[bw->bpdind];
- if(extend) // allocate first block
- *bkref = hole ? 0 : alloc_blk(fs,nod);
- @@ -1094,20 +1670,20 @@
- bw->bpdind = 0;
- bw->bptind = 0;
- if(extend) // allocate triple indirect block
- - get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
- + iblk[bw->bpdir] = alloc_blk(fs,nod);
- if(reduce) // free triple indirect block
- - free_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
- - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
- + free_blk(fs, iblk[bw->bpdir]);
- + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
- if(extend) // allocate first double indirect block
- b[bw->bpind] = alloc_blk(fs,nod);
- if(reduce) // free first double indirect block
- free_blk(fs, b[bw->bpind]);
- - b = (uint32*)get_blk(fs, b[bw->bpind]);
- + b = get_blkmap(fs, b[bw->bpind], &bmi2);
- if(extend) // allocate first indirect block
- b[bw->bpdind] = alloc_blk(fs,nod);
- if(reduce) // free first indirect block
- free_blk(fs, b[bw->bpind]);
- - b = (uint32*)get_blk(fs, b[bw->bpdind]);
- + b = get_blkmap(fs, b[bw->bpdind], &bmi3);
- bkref = &b[bw->bptind];
- if(extend) // allocate first data block
- *bkref = hole ? 0 : alloc_blk(fs,nod);
- @@ -1121,9 +1697,9 @@
- (bw->bptind < BLOCKSIZE/4 -1) )
- {
- bw->bptind++;
- - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
- - b = (uint32*)get_blk(fs, b[bw->bpind]);
- - b = (uint32*)get_blk(fs, b[bw->bpdind]);
- + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
- + b = get_blkmap(fs, b[bw->bpind], &bmi2);
- + b = get_blkmap(fs, b[bw->bpdind], &bmi3);
- bkref = &b[bw->bptind];
- if(extend) // allocate data block
- *bkref = hole ? 0 : alloc_blk(fs,nod);
- @@ -1140,13 +1716,13 @@
- bw->bnum++;
- bw->bptind = 0;
- bw->bpdind++;
- - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
- - b = (uint32*)get_blk(fs, b[bw->bpind]);
- + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
- + b = get_blkmap(fs, b[bw->bpind], &bmi2);
- if(extend) // allocate single indirect block
- b[bw->bpdind] = alloc_blk(fs,nod);
- if(reduce) // free indirect block
- free_blk(fs, b[bw->bpind]);
- - b = (uint32*)get_blk(fs, b[bw->bpdind]);
- + b = get_blkmap(fs, b[bw->bpdind], &bmi3);
- bkref = &b[bw->bptind];
- if(extend) // allocate first data block
- *bkref = hole ? 0 : alloc_blk(fs,nod);
- @@ -1163,17 +1739,17 @@
- bw->bpdind = 0;
- bw->bptind = 0;
- bw->bpind++;
- - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
- + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
- if(extend) // allocate double indirect block
- b[bw->bpind] = alloc_blk(fs,nod);
- if(reduce) // free double indirect block
- free_blk(fs, b[bw->bpind]);
- - b = (uint32*)get_blk(fs, b[bw->bpind]);
- + b = get_blkmap(fs, b[bw->bpind], &bmi2);
- if(extend) // allocate single indirect block
- b[bw->bpdind] = alloc_blk(fs,nod);
- if(reduce) // free indirect block
- free_blk(fs, b[bw->bpind]);
- - b = (uint32*)get_blk(fs, b[bw->bpdind]);
- + b = get_blkmap(fs, b[bw->bpdind], &bmi3);
- bkref = &b[bw->bptind];
- if(extend) // allocate first block
- *bkref = hole ? 0 : alloc_blk(fs,nod);
- @@ -1184,56 +1760,105 @@
- error_msg_and_die("file too big !");
- /* End change for walking triple indirection */
-
- - if(*bkref)
- - {
- + bk = *bkref;
- + if (bmi3)
- + put_blkmap(bmi3);
- + if (bmi2)
- + put_blkmap(bmi2);
- + if (bmi1)
- + put_blkmap(bmi1);
- +
- + if(bk)
- + {
- + blk_info *bi;
- + gd_info *gi;
- + uint8 *block;
- bw->bnum++;
- - if(!reduce && !allocated(GRP_GET_BLOCK_BITMAP(fs,*bkref), GRP_BBM_OFFSET(fs,*bkref)))
- - error_msg_and_die("[block %d of inode %d is unallocated !]", *bkref, nod);
- + block = GRP_GET_BLOCK_BITMAP(fs,bk,&bi,&gi);
- + if(!reduce && !allocated(block, GRP_BBM_OFFSET(fs,bk)))
- + error_msg_and_die("[block %d of inode %d is unallocated !]", bk, nod);
- + GRP_PUT_BLOCK_BITMAP(bi, gi);
- }
- if(extend)
- - get_nod(fs, nod)->i_blocks = bw->bnum * INOBLK;
- - return *bkref;
- + inod->i_blocks = bw->bnum * INOBLK;
- + put_nod(ni);
- + return bk;
- }
-
- -// add blocks to an inode (file/dir/etc...)
- -static void
- -extend_blk(filesystem *fs, uint32 nod, block b, int amount)
- +typedef struct
- {
- - int create = amount;
- - blockwalker bw, lbw;
- - uint32 bk;
- - init_bw(&bw);
- - if(amount < 0)
- - {
- - uint32 i;
- - for(i = 0; i < get_nod(fs, nod)->i_blocks / INOBLK + amount; i++)
- - walk_bw(fs, nod, &bw, 0, 0);
- - while(walk_bw(fs, nod, &bw, &create, 0) != WALK_END)
- + blockwalker bw;
- + uint32 nod;
- + nod_info *ni;
- + inode *inod;
- +} inode_pos;
- +#define INODE_POS_TRUNCATE 0
- +#define INODE_POS_EXTEND 1
- +
- +// Call this to set up an ipos structure for future use with
- +// extend_inode_blk to append blocks to the given inode. If
- +// op is INODE_POS_TRUNCATE, the inode is truncated to zero size.
- +// If op is INODE_POS_EXTEND, the position is moved to the end
- +// of the inode's data blocks.
- +// Call inode_pos_finish when done with the inode_pos structure.
- +static void
- +inode_pos_init(filesystem *fs, inode_pos *ipos, uint32 nod, int op,
- + blockwalker *endbw)
- +{
- + blockwalker lbw;
- +
- + init_bw(&ipos->bw);
- + ipos->nod = nod;
- + ipos->inod = get_nod(fs, nod, &ipos->ni);
- + if (op == INODE_POS_TRUNCATE) {
- + int32 create = -1;
- + while(walk_bw(fs, nod, &ipos->bw, &create, 0) != WALK_END)
- /*nop*/;
- - get_nod(fs, nod)->i_blocks += amount * INOBLK;
- + ipos->inod->i_blocks = 0;
- }
- - else
- +
- + if (endbw)
- + ipos->bw = *endbw;
- + else {
- + /* Seek to the end */
- + init_bw(&ipos->bw);
- + lbw = ipos->bw;
- + while(walk_bw(fs, nod, &ipos->bw, 0, 0) != WALK_END)
- + lbw = ipos->bw;
- + ipos->bw = lbw;
- + }
- +}
- +
- +// Clean up the inode_pos structure.
- +static void
- +inode_pos_finish(filesystem *fs, inode_pos *ipos)
- +{
- + put_nod(ipos->ni);
- +}
- +
- +// add blocks to an inode (file/dir/etc...) at the given position.
- +// This will only work when appending to the end of an inode.
- +static void
- +extend_inode_blk(filesystem *fs, inode_pos *ipos, block b, int amount)
- +{
- + uint32 bk;
- + uint32 pos;
- +
- + if (amount < 0)
- + error_msg_and_die("extend_inode_blk: Got negative amount");
- +
- + for (pos = 0; amount; pos += BLOCKSIZE)
- {
- - 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);
- + int hole = (fs->holes && is_blk_empty(b + pos));
- +
- + bk = walk_bw(fs, ipos->nod, &ipos->bw, &amount, hole);
- + if (bk == WALK_END)
- + error_msg_and_die("extend_inode_blk: extend failed");
- + if (!hole) {
- + blk_info *bi;
- + uint8 *block = get_blk(fs, bk, &bi);
- + memcpy(block, b + pos, BLOCKSIZE);
- + put_blk(bi);
- }
- }
- }
- @@ -1242,15 +1867,17 @@
- static void
- add2dir(filesystem *fs, uint32 dnod, uint32 nod, const char* name)
- {
- - blockwalker bw;
- + blockwalker bw, lbw;
- uint32 bk;
- - uint8 *b;
- directory *d;
- + dirwalker dw;
- int reclen, nlen;
- inode *node;
- inode *pnode;
- + nod_info *dni, *ni;
- + inode_pos ipos;
-
- - pnode = get_nod(fs, dnod);
- + pnode = get_nod(fs, dnod, &dni);
- if((pnode->i_mode & FM_IFMT) != FM_IFDIR)
- error_msg_and_die("can't add '%s' to a non-directory", name);
- if(!*name)
- @@ -1262,52 +1889,52 @@
- if(reclen > BLOCKSIZE)
- error_msg_and_die("bad name '%s' (too long)", name);
- init_bw(&bw);
- + lbw = 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))
- + for(d = get_dir(fs, bk, &dw); d; d = next_dir(&dw))
- {
- // 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 = get_nod(fs, nod, &ni);
- + dir_set_name(&dw, name, nlen);
- + put_dir(&dw);
- node->i_links_count++;
- - d->d_name_len = nlen;
- - strncpy(d->d_name, name, nlen);
- - return;
- + put_nod(ni);
- + goto out;
- }
- // 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);
- + d = shrink_dir(&dw, nod, name, nlen);
- + put_dir(&dw);
- + node = get_nod(fs, nod, &ni);
- node->i_links_count++;
- - d->d_name_len = nlen;
- - strncpy(d->d_name, name, nlen);
- - return;
- + put_nod(ni);
- + goto out;
- }
- }
- + put_dir(&dw);
- + lbw = bw;
- }
- // we found no free entry in the directory, so we add a block
- - if(!(b = get_workblk()))
- - error_msg_and_die("get_workblk() failed.");
- - d = (directory*)b;
- - d->d_inode = nod;
- - node = get_nod(fs, nod);
- + node = get_nod(fs, nod, &ni);
- + d = new_dir(fs, nod, name, nlen, &dw);
- node->i_links_count++;
- - d->d_rec_len = BLOCKSIZE;
- - d->d_name_len = nlen;
- - strncpy(d->d_name, name, nlen);
- - extend_blk(fs, dnod, b, 1);
- - get_nod(fs, dnod)->i_size += BLOCKSIZE;
- - free_workblk(b);
- + put_nod(ni);
- + next_dir(&dw); // Force the data into the buffer
- +
- + inode_pos_init(fs, &ipos, dnod, INODE_POS_EXTEND, &lbw);
- + extend_inode_blk(fs, &ipos, dir_data(&dw), 1);
- + inode_pos_finish(fs, &ipos);
- +
- + put_dir(&dw);
- + pnode->i_size += BLOCKSIZE;
- +out:
- + put_nod(dni);
- }
-
- // find an entry in a directory
- @@ -1321,11 +1948,13 @@
- 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))
- + dirwalker dw;
- + for (d = get_dir(fs, bk, &dw); d; d=next_dir(&dw))
- + if(d->d_inode && (nlen == d->d_name_len) && !strncmp(dir_name(&dw), name, nlen)) {
- + put_dir(&dw);
- return d->d_inode;
- + }
- + put_dir(&dw);
- }
- return 0;
- }
- @@ -1356,47 +1985,55 @@
- return nod;
- }
-
- +// chmod an inode
- +void
- +chmod_fs(filesystem *fs, uint32 nod, uint16 mode, uint16 uid, uint16 gid)
- +{
- + inode *node;
- + nod_info *ni;
- + node = get_nod(fs, nod, &ni);
- + node->i_mode = (node->i_mode & ~FM_IMASK) | (mode & FM_IMASK);
- + node->i_uid = uid;
- + node->i_gid = gid;
- + put_nod(ni);
- +}
- +
- // create a simple inode
- static uint32
- mknod_fs(filesystem *fs, uint32 parent_nod, const char *name, uint16 mode, uint16 uid, uint16 gid, uint8 major, uint8 minor, uint32 ctime, uint32 mtime)
- {
- uint32 nod;
- inode *node;
- - if((nod = find_dir(fs, parent_nod, name)))
- - {
- - node = get_nod(fs, nod);
- - if((node->i_mode & FM_IFMT) != (mode & FM_IFMT))
- - error_msg_and_die("node '%s' already exists and isn't of the same type", name);
- - node->i_mode = mode;
- - }
- - else
- + nod_info *ni;
- + gd_info *gi;
- +
- + nod = alloc_nod(fs);
- + node = get_nod(fs, nod, &ni);
- + node->i_mode = mode;
- + add2dir(fs, parent_nod, nod, name);
- + switch(mode & FM_IFMT)
- {
- - nod = alloc_nod(fs);
- - node = get_nod(fs, nod);
- - node->i_mode = mode;
- - add2dir(fs, parent_nod, nod, name);
- - switch(mode & FM_IFMT)
- - {
- - case FM_IFLNK:
- - mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO;
- - break;
- - case FM_IFBLK:
- - case FM_IFCHR:
- - ((uint8*)get_nod(fs, nod)->i_block)[0] = minor;
- - ((uint8*)get_nod(fs, nod)->i_block)[1] = major;
- - break;
- - case FM_IFDIR:
- - add2dir(fs, nod, nod, ".");
- - add2dir(fs, nod, parent_nod, "..");
- - fs->gd[GRP_GROUP_OF_INODE(fs,nod)].bg_used_dirs_count++;
- - break;
- - }
- + case FM_IFLNK:
- + mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO;
- + break;
- + case FM_IFBLK:
- + case FM_IFCHR:
- + ((uint8*)node->i_block)[0] = minor;
- + ((uint8*)node->i_block)[1] = major;
- + break;
- + case FM_IFDIR:
- + add2dir(fs, nod, nod, ".");
- + add2dir(fs, nod, parent_nod, "..");
- + get_gd(fs,GRP_GROUP_OF_INODE(fs,nod),&gi)->bg_used_dirs_count++;
- + put_gd(gi);
- + break;
- }
- node->i_uid = uid;
- node->i_gid = gid;
- node->i_atime = mtime;
- node->i_ctime = ctime;
- node->i_mtime = mtime;
- + put_nod(ni);
- return nod;
- }
-
- @@ -1413,33 +2050,73 @@
- mklink_fs(filesystem *fs, uint32 parent_nod, const char *name, size_t size, uint8 *b, uid_t uid, gid_t gid, uint32 ctime, uint32 mtime)
- {
- uint32 nod = mknod_fs(fs, parent_nod, name, FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO, uid, gid, 0, 0, ctime, mtime);
- - extend_blk(fs, nod, 0, - (int)get_nod(fs, nod)->i_blocks / INOBLK);
- - get_nod(fs, nod)->i_size = size;
- - if(size <= 4 * (EXT2_TIND_BLOCK+1))
- - {
- - strncpy((char*)get_nod(fs, nod)->i_block, (char*)b, size);
- + nod_info *ni;
- + inode *node = get_nod(fs, nod, &ni);
- + inode_pos ipos;
- +
- + inode_pos_init(fs, &ipos, nod, INODE_POS_TRUNCATE, NULL);
- + node->i_size = size;
- + if(size < 4 * (EXT2_TIND_BLOCK+1))
- + {
- + strncpy((char*)node->i_block, (char*)b, size);
- + ((char*)node->i_block)[size+1] = '\0';
- + inode_pos_finish(fs, &ipos);
- + put_nod(ni);
- return nod;
- }
- - extend_blk(fs, nod, b, rndup(size, BLOCKSIZE) / BLOCKSIZE);
- + extend_inode_blk(fs, &ipos, b, rndup(size, BLOCKSIZE) / BLOCKSIZE);
- + inode_pos_finish(fs, &ipos);
- + put_nod(ni);
- return nod;
- }
-
- +static void
- +fs_upgrade_rev1_largefile(filesystem *fs)
- +{
- + fs->sb->s_rev_level = 1;
- + fs->sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
- + fs->sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
- +}
- +
- +#define COPY_BLOCKS 16
- +#define CB_SIZE (COPY_BLOCKS * BLOCKSIZE)
- +
- // make a file from a FILE*
- static uint32
- -mkfile_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, size_t size, FILE *f, uid_t uid, gid_t gid, uint32 ctime, uint32 mtime)
- +mkfile_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, FILE *f, uid_t uid, gid_t gid, uint32 ctime, uint32 mtime)
- {
- uint8 * b;
- uint32 nod = mknod_fs(fs, parent_nod, name, mode|FM_IFREG, uid, gid, 0, 0, ctime, mtime);
- - extend_blk(fs, nod, 0, - (int)get_nod(fs, nod)->i_blocks / INOBLK);
- - get_nod(fs, nod)->i_size = size;
- - if (size) {
- - if(!(b = (uint8*)calloc(rndup(size, BLOCKSIZE), 1)))
- - error_msg_and_die("not enough mem to read file '%s'", name);
- - if(f)
- - fread(b, size, 1, f); // FIXME: ugly. use mmap() ...
- - extend_blk(fs, nod, b, rndup(size, BLOCKSIZE) / BLOCKSIZE);
- - free(b);
- - }
- + nod_info *ni;
- + inode *node = get_nod(fs, nod, &ni);
- + off_t size = 0;
- + size_t readbytes;
- + inode_pos ipos;
- + int fullsize;
- +
- + b = malloc(CB_SIZE);
- + if (!b)
- + error_msg_and_die("mkfile_fs: out of memory");
- + inode_pos_init(fs, &ipos, nod, INODE_POS_TRUNCATE, NULL);
- + readbytes = fread(b, 1, CB_SIZE, f);
- + while (readbytes) {
- + fullsize = rndup(readbytes, BLOCKSIZE);
- + // Fill to end of block with zeros.
- + memset(b + readbytes, 0, fullsize - readbytes);
- + extend_inode_blk(fs, &ipos, b, fullsize / BLOCKSIZE);
- + size += readbytes;
- + readbytes = fread(b, 1, CB_SIZE, f);
- + }
- + if (size > 0x7fffffff) {
- + if (fs->sb->s_rev_level < 1)
- + fs_upgrade_rev1_largefile(fs);
- + fs->sb->s_feature_ro_compat |= EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
- + }
- + node->i_dir_acl = size >> 32;
- + node->i_size = size;
- + inode_pos_finish(fs, &ipos);
- + put_nod(ni);
- + free(b);
- return nod;
- }
-
- @@ -1591,13 +2268,24 @@
- dname = malloc(len + 1);
- for(i = start; i < count; i++)
- {
- + uint32 oldnod;
- SNPRINTF(dname, len, "%s%lu", name, i);
- - mknod_fs(fs, nod, dname, mode, uid, gid, major, minor + (i * increment - start), ctime, mtime);
- + oldnod = find_dir(fs, nod, dname);
- + if(oldnod)
- + chmod_fs(fs, oldnod, mode, uid, gid);
- + else
- + mknod_fs(fs, nod, dname, mode, uid, gid, major, minor + (i * increment - start), ctime, mtime);
- }
- free(dname);
- }
- else
- - mknod_fs(fs, nod, name, mode, uid, gid, major, minor, ctime, mtime);
- + {
- + uint32 oldnod = find_dir(fs, nod, name);
- + if(oldnod)
- + chmod_fs(fs, oldnod, mode, uid, gid);
- + else
- + mknod_fs(fs, nod, name, mode, uid, gid, major, minor, ctime, mtime);
- + }
- }
- }
- if (line)
- @@ -1643,6 +2331,10 @@
- switch(st.st_mode & S_IFMT)
- {
- case S_IFLNK:
- + if((st.st_mode & S_IFMT) == S_IFREG || st.st_size >= 4 * (EXT2_TIND_BLOCK+1))
- + stats->nblocks += (st.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
- + stats->ninodes++;
- + break;
- case S_IFREG:
- if((st.st_mode & S_IFMT) == S_IFREG || st.st_size > 4 * (EXT2_TIND_BLOCK+1))
- stats->nblocks += (st.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
- @@ -1657,19 +2349,33 @@
- if(chdir(dent->d_name) < 0)
- perror_msg_and_die(dent->d_name);
- add2fs_from_dir(fs, this_nod, squash_uids, squash_perms, fs_timestamp, stats);
- - chdir("..");
- + if (chdir("..") == -1)
- + perror_msg_and_die("..");
- +
- break;
- default:
- break;
- }
- else
- {
- + if((nod = find_dir(fs, this_nod, name)))
- + {
- + error_msg("ignoring duplicate entry %s", name);
- + if(S_ISDIR(st.st_mode)) {
- + if(chdir(dent->d_name) < 0)
- + perror_msg_and_die(name);
- + add2fs_from_dir(fs, nod, squash_uids, squash_perms, fs_timestamp, stats);
- + if (chdir("..") == -1)
- + perror_msg_and_die("..");
- + }
- + continue;
- + }
- save_nod = 0;
- /* Check for hardlinks */
- if (!S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode) && st.st_nlink > 1) {
- - int32 hdlink = is_hardlink(st.st_ino);
- + int32 hdlink = is_hardlink(fs, st.st_ino);
- if (hdlink >= 0) {
- - add2dir(fs, this_nod, hdlinks.hdl[hdlink].dst_nod, name);
- + add2dir(fs, this_nod, fs->hdlinks.hdl[hdlink].dst_nod, name);
- continue;
- } else {
- save_nod = 1;
- @@ -1697,8 +2403,12 @@
- free(lnk);
- break;
- case S_IFREG:
- - fh = xfopen(dent->d_name, "rb");
- - nod = mkfile_fs(fs, this_nod, name, mode, st.st_size, fh, uid, gid, ctime, mtime);
- + fh = fopen(dent->d_name, "rb");
- + if (!fh) {
- + error_msg("Unable to open file %s", dent->d_name);
- + break;
- + }
- + nod = mkfile_fs(fs, this_nod, name, mode, fh, uid, gid, ctime, mtime);
- fclose(fh);
- break;
- case S_IFDIR:
- @@ -1706,199 +2416,128 @@
- if(chdir(dent->d_name) < 0)
- perror_msg_and_die(name);
- add2fs_from_dir(fs, nod, squash_uids, squash_perms, fs_timestamp, stats);
- - chdir("..");
- + if (chdir("..") == -1)
- + perror_msg_and_die("..");
- break;
- default:
- error_msg("ignoring entry %s", name);
- }
- if (save_nod) {
- - if (hdlinks.count == hdlink_cnt) {
- - if ((hdlinks.hdl =
- - realloc (hdlinks.hdl, (hdlink_cnt + HDLINK_CNT) *
- + if (fs->hdlinks.count == fs->hdlink_cnt) {
- + if ((fs->hdlinks.hdl =
- + realloc (fs->hdlinks.hdl, (fs->hdlink_cnt + HDLINK_CNT) *
- sizeof (struct hdlink_s))) == NULL) {
- error_msg_and_die("Not enough memory");
- }
- - hdlink_cnt += HDLINK_CNT;
- + fs->hdlink_cnt += HDLINK_CNT;
- }
- - hdlinks.hdl[hdlinks.count].src_inode = st.st_ino;
- - hdlinks.hdl[hdlinks.count].dst_nod = nod;
- - hdlinks.count++;
- + fs->hdlinks.hdl[fs->hdlinks.count].src_inode = st.st_ino;
- + fs->hdlinks.hdl[fs->hdlinks.count].dst_nod = nod;
- + fs->hdlinks.count++;
- }
- }
- }
- closedir(dh);
- }
-
- -// endianness swap of x-indirect blocks
- +// Copy size blocks from src to dst, putting holes in the output
- +// file (if possible) if the input block is all zeros.
- +// Copy size blocks from src to dst, putting holes in the output
- +// file (if possible) if the input block is all zeros.
- static void
- -swap_goodblocks(filesystem *fs, inode *nod)
- +copy_file(filesystem *fs, FILE *dst, FILE *src, size_t size)
- {
- - uint32 i,j;
- - int done=0;
- - uint32 *b,*b2;
- + uint8 *b;
-
- - uint32 nblk = nod->i_blocks / INOBLK;
- - if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
- - 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_DIND_BLOCK + BLOCKSIZE/4)
- - return;
- - /* Currently this will fail b'cos the number of blocks as stored
- - in i_blocks also includes the indirection blocks (see
- - walk_bw). But this function assumes that i_blocks only
- - stores the count of data blocks ( Actually according to
- - "Understanding the Linux Kernel" (Table 17-3 p502 1st Ed)
- - i_blocks IS supposed to store the count of data blocks). so
- - with a file of size 268K nblk would be 269.The above check
- - will be false even though double indirection hasn't been
- - started.This is benign as 0 means block 0 which has been
- - zeroed out and therefore points back to itself from any offset
- - */
- - // FIXME: I have fixed that, but I have the feeling the rest of
- - // ths function needs to be fixed for the same reasons - Xav
- - assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
- - for(i = 0; i < BLOCKSIZE/4; i++)
- - if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + (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;
- - /* Adding support for triple indirection */
- - b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
- - for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
- - b2 = (uint32*)get_blk(fs,b[i]);
- - for(j=0; j<BLOCKSIZE/4;j++) {
- - if (nblk > ( EXT2_IND_BLOCK + BLOCKSIZE/4 +
- - (BLOCKSIZE/4)*(BLOCKSIZE/4) +
- - i*(BLOCKSIZE/4)*(BLOCKSIZE/4) +
- - j*(BLOCKSIZE/4)) )
- - swap_block(get_blk(fs,b2[j]));
- - else {
- - done = 1;
- - break;
- - }
- + b = malloc(BLOCKSIZE);
- + if (!b)
- + error_msg_and_die("copy_file: out of memory");
- + if (fseek(src, 0, SEEK_SET))
- + perror_msg_and_die("fseek");
- + if (ftruncate(fileno(dst), 0))
- + perror_msg_and_die("copy_file: ftruncate");
- + while (size > 0) {
- + if (fread(b, BLOCKSIZE, 1, src) != 1)
- + perror_msg_and_die("copy failed on read");
- + if ((dst != stdout) && fs->holes && is_blk_empty(b)) {
- + /* Empty block, just skip it */
- + if (fseek(dst, BLOCKSIZE, SEEK_CUR))
- + perror_msg_and_die("fseek");
- + } else {
- + if (fwrite(b, BLOCKSIZE, 1, dst) != 1)
- + perror_msg_and_die("copy failed on write");
- }
- - swap_block((uint8 *)b2);
- + size--;
- }
- - swap_block((uint8 *)b);
- - return;
- + free(b);
- }
-
- -static void
- -swap_badblocks(filesystem *fs, inode *nod)
- +// Allocate a new filesystem structure, allocate internal memory,
- +// and initialize the contents.
- +static filesystem *
- +alloc_fs(int swapit, char *fname, uint32 nbblocks, FILE *srcfile)
- {
- - uint32 i,j;
- - int done=0;
- - uint32 *b,*b2;
- + filesystem *fs;
- + struct stat srcstat, dststat;
-
- - uint32 nblk = nod->i_blocks / INOBLK;
- - if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
- - 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_DIND_BLOCK + BLOCKSIZE/4)
- - return;
- - /* See comment in swap_goodblocks */
- - assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
- - 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 + (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;
- - /* Adding support for triple indirection */
- - b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
- - swap_block((uint8 *)b);
- - for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
- - b2 = (uint32*)get_blk(fs,b[i]);
- - swap_block((uint8 *)b2);
- - for(j=0; j<BLOCKSIZE/4;j++) {
- - if (nblk > ( EXT2_IND_BLOCK + BLOCKSIZE/4 +
- - (BLOCKSIZE/4)*(BLOCKSIZE/4) +
- - i*(BLOCKSIZE/4)*(BLOCKSIZE/4) +
- - j*(BLOCKSIZE/4)) )
- - swap_block(get_blk(fs,b2[j]));
- - else {
- - done = 1;
- - break;
- - }
- - }
- - }
- - return;
- -}
- + fs = malloc(sizeof(*fs));
- + if (!fs)
- + error_msg_and_die("not enough memory for filesystem");
- + memset(fs, 0, sizeof(*fs));
- + fs->swapit = swapit;
- + cache_init(&fs->blks, MAX_FREE_CACHE_BLOCKS, blk_elem_val, blk_freed);
- + cache_init(&fs->gds, MAX_FREE_CACHE_GDS, gd_elem_val, gd_freed);
- + cache_init(&fs->blkmaps, MAX_FREE_CACHE_BLOCKMAPS,
- + blkmap_elem_val, blkmap_freed);
- + cache_init(&fs->inodes, MAX_FREE_CACHE_INODES,
- + inode_elem_val, inode_freed);
- + fs->hdlink_cnt = HDLINK_CNT;
- + fs->hdlinks.hdl = calloc(sizeof(struct hdlink_s), fs->hdlink_cnt);
- + if (!fs->hdlinks.hdl)
- + error_msg_and_die("Not enough memory");
- + fs->hdlinks.count = 0 ;
-
- -// endianness swap of the whole filesystem
- -static void
- -swap_goodfs(filesystem *fs)
- -{
- - uint32 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(&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);
- - }
- - for(i=0;i<GRP_NBGROUPS(fs);i++)
- - swap_gd(&(fs->gd[i]));
- - swap_sb(&fs->sb);
- + if (strcmp(fname, "-") == 0)
- + fs->f = tmpfile();
- + else if (srcfile) {
- + if (fstat(fileno(srcfile), &srcstat))
- + perror_msg_and_die("fstat srcfile");
- + if (stat(fname, &dststat) == 0
- + && srcstat.st_ino == dststat.st_ino
- + && srcstat.st_dev == dststat.st_dev)
- + {
- + // source and destination are the same file, don't
- + // truncate or copy, just use the file.
- + fs->f = fopen(fname, "r+b");
- + } else {
- + fs->f = fopen(fname, "w+b");
- + if (fs->f)
- + copy_file(fs, fs->f, srcfile, nbblocks);
- + }
- + } else
- + fs->f = fopen(fname, "w+b");
- + if (!fs->f)
- + perror_msg_and_die("opening %s", fname);
- + return fs;
- }
-
- +/* Make sure the output file is the right size */
- static void
- -swap_badfs(filesystem *fs)
- +set_file_size(filesystem *fs)
- {
- - uint32 i;
- - swap_sb(&fs->sb);
- - for(i=0;i<GRP_NBGROUPS(fs);i++)
- - swap_gd(&(fs->gd[i]));
- - 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(&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);
- - }
- - }
- - }
- + if (ftruncate(fileno(fs->f),
- + ((off_t) fs->sb->s_blocks_count) * BLOCKSIZE))
- + perror_msg_and_die("set_file_size: ftruncate");
- }
-
- // initialize an empty filesystem
- static filesystem *
- -init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes, uint32 fs_timestamp)
- +init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes,
- + uint32 fs_timestamp, uint32 creator_os, int swapit, char *fname)
- {
- uint32 i;
- filesystem *fs;
- - directory *d;
- - uint8 * b;
- + dirwalker dw;
- uint32 nod, first_block;
- uint32 nbgroups,nbinodes_per_group,overhead_per_group,free_blocks,
- free_blocks_per_group,nbblocks_per_group,min_nbgroups;
- @@ -1906,6 +2545,11 @@
- uint32 j;
- uint8 *bbm,*ibm;
- inode *itab0;
- + blk_info *bi;
- + nod_info *ni;
- + groupdescriptor *gd;
- + gd_info *gi;
- + inode_pos ipos;
-
- if(nbresrvd < 0)
- error_msg_and_die("reserved blocks value is invalid. Note: options have changed, see --help or the man page.");
- @@ -1919,10 +2563,14 @@
- */
- min_nbgroups = (nbinodes + INODES_PER_GROUP - 1) / INODES_PER_GROUP;
-
- + /* On filesystems with 1k block size, the bootloader area uses a full
- + * block. For 2048 and up, the superblock can be fitted into block 0.
- + */
- + first_block = (BLOCKSIZE == 1024);
- +
- /* nbblocks is the total number of blocks in the filesystem.
- * a block group can have no more than 8192 blocks.
- */
- - first_block = (BLOCKSIZE == 1024);
- nbgroups = (nbblocks - first_block + BLOCKS_PER_GROUP - 1) / BLOCKS_PER_GROUP;
- if(nbgroups < min_nbgroups) nbgroups = min_nbgroups;
- nbblocks_per_group = rndup((nbblocks - first_block + nbgroups - 1)/nbgroups, 8);
- @@ -1934,51 +2582,59 @@
- gdsz = rndup(nbgroups*sizeof(groupdescriptor),BLOCKSIZE)/BLOCKSIZE;
- itblsz = nbinodes_per_group * sizeof(inode)/BLOCKSIZE;
- overhead_per_group = 3 /*sb,bbm,ibm*/ + gdsz + itblsz;
- - if((uint32)nbblocks - 1 < overhead_per_group * nbgroups)
- - error_msg_and_die("too much overhead, try fewer inodes or more blocks. Note: options have changed, see --help or the man page.");
- - free_blocks = nbblocks - overhead_per_group*nbgroups - 1 /*boot block*/;
- + free_blocks = nbblocks - overhead_per_group*nbgroups - first_block;
- free_blocks_per_group = nbblocks_per_group - overhead_per_group;
- + if(free_blocks < 0)
- + error_msg_and_die("too much overhead, try fewer inodes or more blocks. Note: options have changed, see --help or the man page.");
-
- - if(!(fs = (filesystem*)calloc(nbblocks, BLOCKSIZE)))
- - error_msg_and_die("not enough memory for filesystem");
- + fs = alloc_fs(swapit, fname, nbblocks, NULL);
- + fs->sb = calloc(1, SUPERBLOCK_SIZE);
- + if (!fs->sb)
- + error_msg_and_die("error allocating header memory");
-
- // create the superblock for an empty filesystem
- - fs->sb.s_inodes_count = nbinodes_per_group * nbgroups;
- - fs->sb.s_blocks_count = nbblocks;
- - fs->sb.s_r_blocks_count = nbresrvd;
- - fs->sb.s_free_blocks_count = free_blocks;
- - fs->sb.s_free_inodes_count = fs->sb.s_inodes_count - EXT2_FIRST_INO + 1;
- - fs->sb.s_first_data_block = first_block;
- - fs->sb.s_log_block_size = BLOCKSIZE >> 11;
- - fs->sb.s_log_frag_size = BLOCKSIZE >> 11;
- - fs->sb.s_blocks_per_group = nbblocks_per_group;
- - fs->sb.s_frags_per_group = nbblocks_per_group;
- - fs->sb.s_inodes_per_group = nbinodes_per_group;
- - fs->sb.s_wtime = fs_timestamp;
- - fs->sb.s_magic = EXT2_MAGIC_NUMBER;
- - fs->sb.s_lastcheck = fs_timestamp;
- + fs->sb->s_inodes_count = nbinodes_per_group * nbgroups;
- + fs->sb->s_blocks_count = nbblocks;
- + fs->sb->s_r_blocks_count = nbresrvd;
- + fs->sb->s_free_blocks_count = free_blocks;
- + fs->sb->s_free_inodes_count = fs->sb->s_inodes_count - EXT2_FIRST_INO + 1;
- + fs->sb->s_first_data_block = first_block;
- + fs->sb->s_log_block_size = BLOCKSIZE >> 11;
- + fs->sb->s_log_frag_size = BLOCKSIZE >> 11;
- + fs->sb->s_blocks_per_group = nbblocks_per_group;
- + fs->sb->s_frags_per_group = nbblocks_per_group;
- + fs->sb->s_inodes_per_group = nbinodes_per_group;
- + fs->sb->s_wtime = fs_timestamp;
- + fs->sb->s_magic = EXT2_MAGIC_NUMBER;
- + fs->sb->s_lastcheck = fs_timestamp;
- + fs->sb->s_creator_os = creator_os;
- +
- + set_file_size(fs);
-
- // set up groupdescriptors
- - for(i=0, bbmpos=gdsz+2, ibmpos=bbmpos+1, itblpos=ibmpos+1;
- + for(i=0, bbmpos=first_block+1+gdsz, ibmpos=bbmpos+1, itblpos=ibmpos+1;
- i<nbgroups;
- i++, bbmpos+=nbblocks_per_group, ibmpos+=nbblocks_per_group, itblpos+=nbblocks_per_group)
- {
- + gd = get_gd(fs, i, &gi);
- +
- if(free_blocks > free_blocks_per_group) {
- - fs->gd[i].bg_free_blocks_count = free_blocks_per_group;
- + gd->bg_free_blocks_count = free_blocks_per_group;
- free_blocks -= free_blocks_per_group;
- } else {
- - fs->gd[i].bg_free_blocks_count = free_blocks;
- + gd->bg_free_blocks_count = free_blocks;
- free_blocks = 0; // this is the last block group
- }
- if(i)
- - fs->gd[i].bg_free_inodes_count = nbinodes_per_group;
- + gd->bg_free_inodes_count = nbinodes_per_group;
- else
- - fs->gd[i].bg_free_inodes_count = nbinodes_per_group -
- + gd->bg_free_inodes_count = nbinodes_per_group -
- EXT2_FIRST_INO + 2;
- - fs->gd[i].bg_used_dirs_count = 0;
- - fs->gd[i].bg_block_bitmap = bbmpos;
- - fs->gd[i].bg_inode_bitmap = ibmpos;
- - fs->gd[i].bg_inode_table = itblpos;
- + gd->bg_used_dirs_count = 0;
- + gd->bg_block_bitmap = bbmpos;
- + gd->bg_inode_bitmap = ibmpos;
- + gd->bg_inode_table = itblpos;
- + put_gd(gi);
- }
-
- /* Mark non-filesystem blocks and inodes as allocated */
- @@ -1984,110 +2640,143 @@
- /* Mark non-filesystem blocks and inodes as allocated */
- /* Mark system blocks and inodes as allocated */
- for(i = 0; i<nbgroups;i++) {
- -
- /* Block bitmap */
- - bbm = get_blk(fs,fs->gd[i].bg_block_bitmap);
- + gd = get_gd(fs, i, &gi);
- + bbm = GRP_GET_GROUP_BBM(fs, gd, &bi);
- //non-filesystem blocks
- - for(j = fs->gd[i].bg_free_blocks_count
- + for(j = gd->bg_free_blocks_count
- + overhead_per_group + 1; j <= BLOCKSIZE * 8; j++)
- allocate(bbm, j);
- //system blocks
- for(j = 1; j <= overhead_per_group; j++)
- allocate(bbm, j);
- -
- + GRP_PUT_GROUP_BBM(bi);
- +
- /* Inode bitmap */
- - ibm = get_blk(fs,fs->gd[i].bg_inode_bitmap);
- + ibm = GRP_GET_GROUP_IBM(fs, gd, &bi);
- //non-filesystem inodes
- - for(j = fs->sb.s_inodes_per_group+1; j <= BLOCKSIZE * 8; j++)
- + for(j = fs->sb->s_inodes_per_group+1; j <= BLOCKSIZE * 8; j++)
- allocate(ibm, j);
-
- //system inodes
- if(i == 0)
- for(j = 1; j < EXT2_FIRST_INO; j++)
- allocate(ibm, j);
- + GRP_PUT_GROUP_IBM(bi);
- + put_gd(gi);
- }
-
- // make root inode and directory
- /* We have groups now. Add the root filesystem in group 0 */
- /* Also increment the directory count for group 0 */
- - fs->gd[0].bg_free_inodes_count--;
- - fs->gd[0].bg_used_dirs_count = 1;
- - itab0 = (inode *)get_blk(fs,fs->gd[0].bg_inode_table);
- - itab0[EXT2_ROOT_INO-1].i_mode = FM_IFDIR | FM_IRWXU | FM_IRGRP | FM_IROTH | FM_IXGRP | FM_IXOTH;
- - itab0[EXT2_ROOT_INO-1].i_ctime = fs_timestamp;
- - itab0[EXT2_ROOT_INO-1].i_mtime = fs_timestamp;
- - itab0[EXT2_ROOT_INO-1].i_atime = fs_timestamp;
- - itab0[EXT2_ROOT_INO-1].i_size = BLOCKSIZE;
- - itab0[EXT2_ROOT_INO-1].i_links_count = 2;
- -
- - if(!(b = get_workblk()))
- - error_msg_and_die("get_workblk() failed.");
- - 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);
- + gd = get_gd(fs, 0, &gi);
- + gd->bg_free_inodes_count--;
- + gd->bg_used_dirs_count = 1;
- + put_gd(gi);
- + itab0 = get_nod(fs, EXT2_ROOT_INO, &ni);
- + itab0->i_mode = FM_IFDIR | FM_IRWXU | FM_IRGRP | FM_IROTH | FM_IXGRP | FM_IXOTH;
- + itab0->i_ctime = fs_timestamp;
- + itab0->i_mtime = fs_timestamp;
- + itab0->i_atime = fs_timestamp;
- + itab0->i_size = BLOCKSIZE;
- + itab0->i_links_count = 2;
- + put_nod(ni);
- +
- + new_dir(fs, EXT2_ROOT_INO, ".", 1, &dw);
- + shrink_dir(&dw, EXT2_ROOT_INO, "..", 2);
- + next_dir(&dw); // Force the data into the buffer
- + inode_pos_init(fs, &ipos, EXT2_ROOT_INO, INODE_POS_EXTEND, NULL);
- + extend_inode_blk(fs, &ipos, dir_data(&dw), 1);
- + inode_pos_finish(fs, &ipos);
- + put_dir(&dw);
-
- - // make lost+found directory and reserve blocks
- - if(fs->sb.s_r_blocks_count)
- + // make lost+found directory
- + if(fs->sb->s_r_blocks_count)
- {
- - nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", FM_IRWXU, 0, 0, fs_timestamp, fs_timestamp);
- + inode *node;
- + uint8 *b;
- +
- + nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", FM_IRWXU,
- + 0, 0, fs_timestamp, fs_timestamp);
- + b = get_workblk();
- memset(b, 0, BLOCKSIZE);
- ((directory*)b)->d_rec_len = BLOCKSIZE;
- - /* We run into problems with e2fsck if directory lost+found grows
- - * bigger than this. Need to find out why this happens - sundar
- - */
- - if (fs->sb.s_r_blocks_count > fs->sb.s_blocks_count * MAX_RESERVED_BLOCKS )
- - fs->sb.s_r_blocks_count = fs->sb.s_blocks_count * MAX_RESERVED_BLOCKS;
- - 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;
- + inode_pos_init(fs, &ipos, nod, INODE_POS_EXTEND, NULL);
- + // It is always 16 blocks to start out with
- + for(i = 1; i < 16; i++)
- + extend_inode_blk(fs, &ipos, b, 1);
- + inode_pos_finish(fs, &ipos);
- + free_workblk(b);
- + node = get_nod(fs, nod, &ni);
- + node->i_size = 16 * BLOCKSIZE;
- + put_nod(ni);
- }
- - free_workblk(b);
-
- // administrative info
- - fs->sb.s_state = 1;
- - fs->sb.s_max_mnt_count = 20;
- + fs->sb->s_state = 1;
- + fs->sb->s_max_mnt_count = 20;
-
- // options for me
- - if(holes)
- - fs->sb.s_reserved[200] |= OP_HOLES;
- + fs->holes = holes;
-
- return fs;
- }
-
- // loads a filesystem from disk
- static filesystem *
- -load_fs(FILE * fh, int swapit)
- +load_fs(FILE *fh, int swapit, char *fname)
- {
- - size_t fssize;
- + off_t fssize;
- filesystem *fs;
- - if((fseek(fh, 0, SEEK_END) < 0) || ((ssize_t)(fssize = ftell(fh)) == -1))
- +
- + if((fseek(fh, 0, SEEK_END) < 0) || ((fssize = ftello(fh)) == -1))
- perror_msg_and_die("input filesystem image");
- rewind(fh);
- - fssize = (fssize + BLOCKSIZE - 1) / BLOCKSIZE;
- + if ((fssize % BLOCKSIZE) != 0)
- + error_msg_and_die("Input file not a multiple of block size");
- + fssize /= BLOCKSIZE;
- if(fssize < 16) // totally arbitrary
- error_msg_and_die("too small filesystem");
- - if(!(fs = (filesystem*)calloc(fssize, BLOCKSIZE)))
- - error_msg_and_die("not enough memory for filesystem");
- - if(fread(fs, BLOCKSIZE, fssize, fh) != fssize)
- - perror_msg_and_die("input filesystem image");
- + fs = alloc_fs(swapit, fname, fssize, fh);
- +
- + /* Read and check the superblock, then read the superblock
- + * and all the group descriptors */
- + fs->sb = malloc(SUPERBLOCK_SIZE);
- + if (!fs->sb)
- + error_msg_and_die("error allocating header memory");
- + if (fseek(fs->f, SUPERBLOCK_OFFSET, SEEK_SET))
- + perror_msg_and_die("fseek");
- + if (fread(fs->sb, SUPERBLOCK_SIZE, 1, fs->f) != 1)
- + perror_msg_and_die("fread filesystem image superblock");
- if(swapit)
- - swap_badfs(fs);
- - if(fs->sb.s_rev_level || (fs->sb.s_magic != EXT2_MAGIC_NUMBER))
- + swap_sb(fs->sb);
- +
- + if((fs->sb->s_rev_level > 1) || (fs->sb->s_magic != EXT2_MAGIC_NUMBER))
- error_msg_and_die("not a suitable ext2 filesystem");
- + if (fs->sb->s_rev_level > 0) {
- + if (fs->sb->s_first_ino != EXT2_GOOD_OLD_FIRST_INO)
- + error_msg_and_die("First inode incompatible");
- + if (fs->sb->s_inode_size != EXT2_GOOD_OLD_INODE_SIZE)
- + error_msg_and_die("inode size incompatible");
- + if (fs->sb->s_feature_compat)
- + error_msg_and_die("Unsupported compat features");
- + if (fs->sb->s_feature_incompat)
- + error_msg_and_die("Unsupported incompat features");
- + if (fs->sb->s_feature_ro_compat
- + & ~EXT2_FEATURE_RO_COMPAT_LARGE_FILE)
- + error_msg_and_die("Unsupported ro compat features");
- + }
- +
- + set_file_size(fs);
- return fs;
- }
-
- static void
- free_fs(filesystem *fs)
- {
- + free(fs->hdlinks.hdl);
- + fclose(fs->f);
- + free(fs->sb);
- free(fs);
- }
-
- @@ -2123,16 +2812,23 @@
- {
- blockwalker bw;
- uint32 bk;
- - int32 fsize = get_nod(fs, nod)->i_size;
- + nod_info *ni;
- + inode *node = get_nod(fs, nod, &ni);
- + int32 fsize = node->i_size;
- + blk_info *bi;
- +
- init_bw(&bw);
- while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
- {
- if(fsize <= 0)
- error_msg_and_die("wrong size while saving inode %d", nod);
- - if(fwrite(get_blk(fs, bk), (fsize > BLOCKSIZE) ? BLOCKSIZE : fsize, 1, f) != 1)
- + if(fwrite(get_blk(fs, bk, &bi),
- + (fsize > BLOCKSIZE) ? BLOCKSIZE : fsize, 1, f) != 1)
- error_msg_and_die("error while saving inode %d", nod);
- + put_blk(bi);
- fsize -= BLOCKSIZE;
- }
- + put_nod(ni);
- }
-
-
- @@ -2141,8 +2837,11 @@
- 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];
- + nod_info *ni;
- + inode *node = get_nod(fs, nod, &ni);
- + minor = ((uint8*)node->i_block)[0];
- + major = ((uint8*)node->i_block)[1];
- + put_nod(ni);
- printf("major: %d, minor: %d\n", major, minor);
- }
-
- @@ -2157,17 +2856,15 @@
- 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))
- + dirwalker dw;
- + for (d = get_dir(fs, bk, &dw); d; d = next_dir(&dw))
- if(d->d_inode)
- {
- - int i;
- printf("entry '");
- - for(i = 0; i < d->d_name_len; i++)
- - putchar(d->d_name[i]);
- + fwrite(dir_name(&dw), 1, d->d_name_len, stdout);
- printf("' (inode %d): rec_len: %d (name_len: %d)\n", d->d_inode, d->d_rec_len, d->d_name_len);
- }
- + put_dir(&dw);
- }
- }
-
- @@ -2175,14 +2872,18 @@
- static 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);
- + nod_info *ni;
- + inode *node = get_nod(fs, nod, &ni);
- +
- + if(!node->i_blocks)
- + printf("links to '%s'\n", (char*)node->i_block);
- else
- {
- printf("links to '");
- write_blocks(fs, nod, stdout);
- printf("'\n");
- }
- + put_nod(ni);
- }
-
- // make a ls-like printout of permissions
- @@ -2251,8 +2952,13 @@
- {
- char *s;
- char perms[11];
- - if(!get_nod(fs, nod)->i_mode)
- - return;
- + nod_info *ni;
- + inode *node = get_nod(fs, nod, &ni);
- + blk_info *bi;
- + gd_info *gi;
- +
- + if(!node->i_mode)
- + goto out;
- switch(nod)
- {
- case EXT2_BAD_INO:
- @@ -2274,15 +2980,18 @@
- 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(GRP_GET_INODE_BITMAP(fs,nod), GRP_IBM_OFFSET(fs,nod)))
- + printf("inode %d (%s, %d links): ", nod, s, node->i_links_count);
- + if(!allocated(GRP_GET_INODE_BITMAP(fs,nod,&bi,&gi), GRP_IBM_OFFSET(fs,nod)))
- {
- + GRP_PUT_INODE_BITMAP(bi,gi);
- printf("unallocated\n");
- - return;
- + goto out;
- }
- - 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)
- + GRP_PUT_INODE_BITMAP(bi,gi);
- + make_perms(node->i_mode, perms);
- + printf("%s, size: %d byte%s (%d block%s)\n", perms,
- + plural(node->i_size), plural(node->i_blocks / INOBLK));
- + switch(node->i_mode & FM_IFMT)
- {
- case FM_IFSOCK:
- list_blocks(fs, nod);
- @@ -2310,6 +3019,8 @@
- list_blocks(fs, nod);
- }
- printf("Done with inode %d\n",nod);
- +out:
- + put_nod(ni);
- }
-
- // describes various fields in a filesystem
- @@ -2317,49 +3028,65 @@
- print_fs(filesystem *fs)
- {
- uint32 i;
- + blk_info *bi;
- + groupdescriptor *gd;
- + gd_info *gi;
- uint8 *ibm;
-
- 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);
- + 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);
- + 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("number of groups: %d\n",GRP_NBGROUPS(fs));
- 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);
- + fs->sb->s_blocks_per_group, fs->sb->s_frags_per_group,
- + fs->sb->s_inodes_per_group);
- printf("Size of inode table: %d blocks\n",
- - (int)(fs->sb.s_inodes_per_group * sizeof(inode) / BLOCKSIZE));
- + (int)(fs->sb->s_inodes_per_group * sizeof(inode) / BLOCKSIZE));
- for (i = 0; i < GRP_NBGROUPS(fs); i++) {
- printf("Group No: %d\n", i+1);
- + gd = get_gd(fs, i, &gi);
- printf("block bitmap: block %d,inode bitmap: block %d, inode table: block %d\n",
- - fs->gd[i].bg_block_bitmap, fs->gd[i].bg_inode_bitmap,
- - fs->gd[i].bg_inode_table);
- + gd->bg_block_bitmap,
- + gd->bg_inode_bitmap,
- + gd->bg_inode_table);
- printf("block bitmap allocation:\n");
- - print_bm(GRP_GET_GROUP_BBM(fs, i),fs->sb.s_blocks_per_group);
- + print_bm(GRP_GET_GROUP_BBM(fs, gd, &bi),fs->sb->s_blocks_per_group);
- + GRP_PUT_GROUP_BBM(bi);
- printf("inode bitmap allocation:\n");
- - ibm = GRP_GET_GROUP_IBM(fs, i);
- - print_bm(ibm, fs->sb.s_inodes_per_group);
- - for (i = 1; i <= fs->sb.s_inodes_per_group; i++)
- + ibm = GRP_GET_GROUP_IBM(fs, gd, &bi);
- + print_bm(ibm, fs->sb->s_inodes_per_group);
- + for (i = 1; i <= fs->sb->s_inodes_per_group; i++)
- if (allocated(ibm, i))
- print_inode(fs, i);
- + GRP_PUT_GROUP_IBM(bi);
- + put_gd(gi);
- }
- }
-
- static void
- -dump_fs(filesystem *fs, FILE * fh, int swapit)
- +finish_fs(filesystem *fs)
- {
- - uint32 nbblocks = fs->sb.s_blocks_count;
- - fs->sb.s_reserved[200] = 0;
- - if(swapit)
- - swap_goodfs(fs);
- - if(fwrite(fs, BLOCKSIZE, nbblocks, fh) < nbblocks)
- - perror_msg_and_die("output filesystem image");
- - if(swapit)
- - swap_badfs(fs);
- + if (cache_flush(&fs->inodes))
- + error_msg_and_die("entry mismatch on inode cache flush");
- + if (cache_flush(&fs->blkmaps))
- + error_msg_and_die("entry mismatch on blockmap cache flush");
- + if (cache_flush(&fs->gds))
- + error_msg_and_die("entry mismatch on gd cache flush");
- + if (cache_flush(&fs->blks))
- + error_msg_and_die("entry mismatch on block cache flush");
- + if(fs->swapit)
- + swap_sb(fs->sb);
- + if (fseek(fs->f, SUPERBLOCK_OFFSET, SEEK_SET))
- + perror_msg_and_die("fseek");
- + if(fwrite(fs->sb, SUPERBLOCK_SIZE, 1, fs->f) != 1)
- + perror_msg_and_die("output filesystem superblock");
- + if(fs->swapit)
- + swap_sb(fs->sb);
- }
-
- static void
- @@ -2419,10 +3146,12 @@
- " -x, --starting-image <image>\n"
- " -d, --root <directory>\n"
- " -D, --devtable <file>\n"
- + " -B, --block-size <bytes>\n"
- " -b, --size-in-blocks <blocks>\n"
- " -i, --bytes-per-inode <bytes per inode>\n"
- " -N, --number-of-inodes <number of inodes>\n"
- " -m, --reserved-percentage <percentage of blocks to reserve>\n"
- + " -o, --creator-os <os> 'linux' (default), 'hurd', 'freebsd' or number.\n"
- " -g, --block-map <path> Generate a block map file for this path.\n"
- " -e, --fill-value <value> Fill unallocated blocks with value.\n"
- " -z, --allow-holes Allow files with holes.\n"
- @@ -2444,15 +3173,34 @@
- extern char* optarg;
- extern int optind, opterr, optopt;
-
- +// parse the value for -o <os>
- +int
- +lookup_creator_os(const char *name)
- +{
- + if (isdigit (*name))
- + return atoi(name);
- + else if (strcasecmp(name, "linux") == 0)
- + return EXT2_OS_LINUX;
- + else if (strcasecmp(name, "GNU") == 0 || strcasecmp(name, "hurd") == 0)
- + return EXT2_OS_HURD;
- + else if (strcasecmp(name, "freebsd") == 0)
- + return EXT2_OS_FREEBSD;
- + else if (strcasecmp(name, "lites") == 0)
- + return EXT2_OS_LITES;
- + else
- + return EXT2_OS_LINUX;
- +}
- +
- int
- main(int argc, char **argv)
- {
- - int nbblocks = -1;
- + long long nbblocks = -1;
- int nbinodes = -1;
- int nbresrvd = -1;
- float bytes_per_inode = -1;
- float reserved_frac = -1;
- int fs_timestamp = -1;
- + int creator_os = CREATOR_OS;
- char * fsout = "-";
- char * fsin = 0;
- char * dopt[MAX_DOPT];
- @@ -2466,6 +3214,7 @@
- int squash_perms = 0;
- uint16 endian = 1;
- int bigendian = !*(char*)&endian;
- + char *volumelabel = NULL;
- filesystem *fs;
- int i;
- int c;
- @@ -2476,13 +3225,16 @@
- { "starting-image", required_argument, NULL, 'x' },
- { "root", required_argument, NULL, 'd' },
- { "devtable", required_argument, NULL, 'D' },
- + { "block-size", required_argument, NULL, 'B' },
- { "size-in-blocks", required_argument, NULL, 'b' },
- { "bytes-per-inode", required_argument, NULL, 'i' },
- { "number-of-inodes", required_argument, NULL, 'N' },
- + { "volume-label", required_argument, NULL, 'L' },
- { "reserved-percentage", required_argument, NULL, 'm' },
- + { "creator-os", required_argument, NULL, 'o' },
- { "block-map", required_argument, NULL, 'g' },
- { "fill-value", required_argument, NULL, 'e' },
- - { "allow-holes", no_argument, NULL, 'z' },
- + { "allow-holes", no_argument, NULL, 'z' },
- { "faketime", no_argument, NULL, 'f' },
- { "squash", no_argument, NULL, 'q' },
- { "squash-uids", no_argument, NULL, 'U' },
- @@ -2495,11 +3247,11 @@
-
- app_name = argv[0];
-
- - while((c = getopt_long(argc, argv, "x:d:D:b:i:N:m:g:e:zfqUPhVv", longopts, NULL)) != EOF) {
- + while((c = getopt_long(argc, argv, "x:d:D:B:b:i:N:L:m:o:g:e:zfqUPhVv", longopts, NULL)) != EOF) {
- #else
- app_name = argv[0];
-
- - while((c = getopt(argc, argv, "x:d:D:b:i:N:m:g:e:zfqUPhVv")) != EOF) {
- + while((c = getopt(argc, argv, "x:d:D:B:b:i:N:L:m:o:g:e:zfqUPhVv")) != EOF) {
- #endif /* HAVE_GETOPT_LONG */
- switch(c)
- {
- @@ -2510,6 +3262,9 @@
- case 'D':
- dopt[didx++] = optarg;
- break;
- + case 'B':
- + blocksize = SI_atof(optarg);
- + break;
- case 'b':
- nbblocks = SI_atof(optarg);
- break;
- @@ -2519,9 +3274,15 @@
- case 'N':
- nbinodes = SI_atof(optarg);
- break;
- + case 'L':
- + volumelabel = optarg;
- + break;
- case 'm':
- reserved_frac = SI_atof(optarg) / 100;
- break;
- + case 'o':
- + creator_os = lookup_creator_os(optarg);
- + break;
- case 'g':
- gopt[gidx++] = optarg;
- break;
- @@ -2565,21 +3326,21 @@
- error_msg_and_die("Not enough arguments. Try --help or else see the man page.");
- fsout = argv[optind];
-
- - hdlinks.hdl = (struct hdlink_s *)malloc(hdlink_cnt * sizeof(struct hdlink_s));
- - if (!hdlinks.hdl)
- - error_msg_and_die("Not enough memory");
- - hdlinks.count = 0 ;
- + if(blocksize != 1024 && blocksize != 2048 && blocksize != 4096)
- + error_msg_and_die("Valid block sizes: 1024, 2048 or 4096.");
- + if(creator_os < 0)
- + error_msg_and_die("Creator OS unknown.");
-
- if(fsin)
- {
- if(strcmp(fsin, "-"))
- {
- FILE * fh = xfopen(fsin, "rb");
- - fs = load_fs(fh, bigendian);
- + fs = load_fs(fh, bigendian, fsout);
- fclose(fh);
- }
- else
- - fs = load_fs(stdin, bigendian);
- + fs = load_fs(stdin, bigendian, fsout);
- }
- else
- {
- @@ -2609,16 +3370,29 @@
- }
- if(fs_timestamp == -1)
- fs_timestamp = time(NULL);
- - fs = init_fs(nbblocks, nbinodes, nbresrvd, holes, fs_timestamp);
- + fs = init_fs(nbblocks, nbinodes, nbresrvd, holes,
- + fs_timestamp, creator_os, bigendian, fsout);
- }
- + if (volumelabel != NULL)
- + strncpy((char *)fs->sb->s_volume_name, volumelabel,
- + sizeof(fs->sb->s_volume_name));
-
- populate_fs(fs, dopt, didx, squash_uids, squash_perms, fs_timestamp, NULL);
-
- if(emptyval) {
- uint32 b;
- - for(b = 1; b < fs->sb.s_blocks_count; b++)
- - if(!allocated(GRP_GET_BLOCK_BITMAP(fs,b),GRP_BBM_OFFSET(fs,b)))
- - memset(get_blk(fs, b), emptyval, BLOCKSIZE);
- + for(b = 1; b < fs->sb->s_blocks_count; b++) {
- + blk_info *bi;
- + gd_info *gi;
- + if(!allocated(GRP_GET_BLOCK_BITMAP(fs,b,&bi,&gi),
- + GRP_BBM_OFFSET(fs,b))) {
- + blk_info *bi2;
- + memset(get_blk(fs, b, &bi2), emptyval,
- + BLOCKSIZE);
- + put_blk(bi2);
- + }
- + GRP_PUT_BLOCK_BITMAP(bi,gi);
- + }
- }
- if(verbose)
- print_fs(fs);
- @@ -2628,24 +3402,22 @@
- char fname[MAX_FILENAME];
- char *p;
- FILE *fh;
- + nod_info *ni;
- if(!(nod = find_path(fs, EXT2_ROOT_INO, gopt[i])))
- error_msg_and_die("path %s not found in filesystem", gopt[i]);
- while((p = strchr(gopt[i], '/')))
- *p = '_';
- SNPRINTF(fname, MAX_FILENAME-1, "%s.blk", gopt[i]);
- fh = xfopen(fname, "wb");
- - fprintf(fh, "%d:", get_nod(fs, nod)->i_size);
- + fprintf(fh, "%d:", get_nod(fs, nod, &ni)->i_size);
- + put_nod(ni);
- flist_blocks(fs, nod, fh);
- fclose(fh);
- }
- - if(strcmp(fsout, "-"))
- - {
- - FILE * fh = xfopen(fsout, "wb");
- - dump_fs(fs, fh, bigendian);
- - fclose(fh);
- - }
- - else
- - dump_fs(fs, stdout, bigendian);
- + finish_fs(fs);
- + if(strcmp(fsout, "-") == 0)
- + copy_file(fs, stdout, fs->f, fs->sb->s_blocks_count);
- +
- free_fs(fs);
- return 0;
- }
- Index: genext2fs-1.4.1/cache.h
- ===================================================================
- --- /dev/null
- +++ genext2fs-1.4.1/cache.h
- @@ -0,0 +1,128 @@
- +#ifndef __CACHE_H__
- +#define __CACHE_H__
- +
- +#include "list.h"
- +
- +#define CACHE_LISTS 256
- +
- +typedef struct
- +{
- + list_elem link;
- + list_elem lru_link;
- +} cache_link;
- +
- +typedef struct
- +{
- + /* LRU list holds unused items */
- + unsigned int lru_entries;
- + list_elem lru_list;
- + unsigned int max_free_entries;
- +
- + unsigned int entries;
- + list_elem lists[CACHE_LISTS];
- + unsigned int (*elem_val)(cache_link *elem);
- + void (*freed)(cache_link *elem);
- +} listcache;
- +
- +static inline void
- +cache_add(listcache *c, cache_link *elem)
- +{
- + unsigned int hash = c->elem_val(elem) % CACHE_LISTS;
- + int delcount = c->lru_entries - c->max_free_entries;
- +
- + if (delcount > 0) {
- + /* Delete some unused items. */
- + list_elem *lru, *next;
- + cache_link *l;
- + list_for_each_elem_safe(&c->lru_list, lru, next) {
- + l = container_of(lru, cache_link, lru_link);
- + list_del(lru);
- + list_del(&l->link);
- + c->entries--;
- + c->lru_entries--;
- + c->freed(l);
- + delcount--;
- + if (delcount <= 0)
- + break;
- + }
- + }
- +
- + c->entries++;
- + list_item_init(&elem->lru_link); /* Mark it not in the LRU list */
- + list_add_after(&c->lists[hash], &elem->link);
- +}
- +
- +static inline void
- +cache_item_set_unused(listcache *c, cache_link *elem)
- +{
- + list_add_before(&c->lru_list, &elem->lru_link);
- + c->lru_entries++;
- +}
- +
- +static inline cache_link *
- +cache_find(listcache *c, unsigned int val)
- +{
- + unsigned int hash = val % CACHE_LISTS;
- + list_elem *elem;
- +
- + list_for_each_elem(&c->lists[hash], elem) {
- + cache_link *l = container_of(elem, cache_link, link);
- + if (c->elem_val(l) == val) {
- + if (!list_empty(&l->lru_link)) {
- + /* It's in the unused list, remove it. */
- + list_del(&l->lru_link);
- + list_item_init(&l->lru_link);
- + c->lru_entries--;
- + }
- + return l;
- + }
- + }
- + return NULL;
- +}
- +
- +static inline int
- +cache_flush(listcache *c)
- +{
- + list_elem *elem, *next;
- + cache_link *l;
- + int i;
- +
- + list_for_each_elem_safe(&c->lru_list, elem, next) {
- + l = container_of(elem, cache_link, lru_link);
- + list_del(elem);
- + list_del(&l->link);
- + c->entries--;
- + c->lru_entries--;
- + c->freed(l);
- + }
- +
- + for (i = 0; i < CACHE_LISTS; i++) {
- + list_for_each_elem_safe(&c->lists[i], elem, next) {
- + l = container_of(elem, cache_link, link);
- + list_del(&l->link);
- + c->entries--;
- + c->freed(l);
- + }
- + }
- +
- + return c->entries || c->lru_entries;
- +}
- +
- +static inline void
- +cache_init(listcache *c, unsigned int max_free_entries,
- + unsigned int (*elem_val)(cache_link *elem),
- + void (*freed)(cache_link *elem))
- +{
- + int i;
- +
- + c->entries = 0;
- + c->lru_entries = 0;
- + c->max_free_entries = max_free_entries;
- + list_init(&c->lru_list);
- + for (i = 0; i < CACHE_LISTS; i++)
- + list_init(&c->lists[i]);
- + c->elem_val = elem_val;
- + c->freed = freed;
- +}
- +
- +#endif /* __CACHE_H__ */
- Index: genext2fs-1.4.1/list.h
- ===================================================================
- --- /dev/null
- +++ genext2fs-1.4.1/list.h
- @@ -0,0 +1,78 @@
- +#ifndef __LIST_H__
- +#define __LIST_H__
- +
- +#if STDC_HEADERS
- +# include <stdlib.h>
- +# include <stddef.h>
- +#else
- +# if HAVE_STDLIB_H
- +# include <stdlib.h>
- +# endif
- +# if HAVE_STDDEF_H
- +# include <stddef.h>
- +# endif
- +#endif
- +
- +#ifndef offsetof
- +#define offsetof(st, m) \
- + ((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))
- +#endif
- +
- +#define container_of(ptr, type, member) ({ \
- + const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- + (type *)( (char *)__mptr - offsetof(type,member) );})
- +
- +typedef struct list_elem
- +{
- + struct list_elem *next;
- + struct list_elem *prev;
- +} list_elem;
- +
- +static inline void list_init(list_elem *list)
- +{
- + list->next = list;
- + list->prev = list;
- +}
- +
- +static inline void list_add_after(list_elem *pos, list_elem *elem)
- +{
- + elem->next = pos->next;
- + elem->prev = pos;
- + pos->next->prev = elem;
- + pos->next = elem;
- +}
- +
- +static inline void list_add_before(list_elem *pos, list_elem *elem)
- +{
- + elem->prev = pos->prev;
- + elem->next = pos;
- + pos->prev->next = elem;
- + pos->prev = elem;
- +}
- +
- +static inline void list_del(list_elem *elem)
- +{
- + elem->next->prev = elem->prev;
- + elem->prev->next = elem->next;
- +}
- +
- +static inline void list_item_init(list_elem *elem)
- +{
- + elem->next = elem;
- + elem->prev = elem;
- +}
- +
- +static inline int list_empty(list_elem *elem)
- +{
- + return elem->next == elem;
- +}
- +
- +#define list_for_each_elem(list, curr) \
- + for ((curr) = (list)->next; (curr) != (list); (curr) = (curr)->next)
- +
- +#define list_for_each_elem_safe(list, curr, next) \
- + for ((curr) = (list)->next, (next) = (curr)->next; \
- + (curr) != (list); \
- + (curr) = (next), (next) = (curr)->next)
- +
- +#endif /* __LIST_H__ */
|