0001-update-genext2fs.c-to-rev-1.118.patch 85 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971
  1. [PATCH] update genext2fs.c to CVS rev 1.118
  2. See http://genext2fs.cvs.sourceforge.net/viewvc/genext2fs/genext2fs/genext2fs.c?view=log
  3. for details.
  4. Numerous bugfixes, large file and filesystem support, rev 1 filesystems,
  5. volume id support, block size, ..
  6. Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
  7. ---
  8. cache.h | 128 ++++
  9. genext2fs.c | 1870 ++++++++++++++++++++++++++++++++++++++++++------------------
  10. list.h | 78 ++
  11. 3 files changed, 1527 insertions(+), 549 deletions(-)
  12. Index: genext2fs-1.4.1/genext2fs.c
  13. ===================================================================
  14. --- genext2fs-1.4.1.orig/genext2fs.c
  15. +++ genext2fs-1.4.1/genext2fs.c
  16. @@ -53,6 +53,12 @@
  17. // along with -q, -P, -U
  18. +/*
  19. + * Allow fseeko/off_t to be 64-bit offsets to allow filesystems and
  20. + * individual files >2GB.
  21. + */
  22. +#define _FILE_OFFSET_BITS 64
  23. +
  24. #include <config.h>
  25. #include <stdio.h>
  26. @@ -107,10 +113,8 @@
  27. #if HAVE_DIRENT_H
  28. # include <dirent.h>
  29. -# define NAMLEN(dirent) strlen((dirent)->d_name)
  30. #else
  31. # define dirent direct
  32. -# define NAMLEN(dirent) (dirent)->d_namlen
  33. # if HAVE_SYS_NDIR_H
  34. # include <sys/ndir.h>
  35. # endif
  36. @@ -144,6 +148,8 @@
  37. # include <limits.h>
  38. #endif
  39. +#include "cache.h"
  40. +
  41. struct stats {
  42. unsigned long nblocks;
  43. unsigned long ninodes;
  44. @@ -151,13 +157,42 @@
  45. // block size
  46. -#define BLOCKSIZE 1024
  47. +static int blocksize = 1024;
  48. +
  49. +#define SUPERBLOCK_OFFSET 1024
  50. +#define SUPERBLOCK_SIZE 1024
  51. +
  52. +#define BLOCKSIZE blocksize
  53. #define BLOCKS_PER_GROUP 8192
  54. #define INODES_PER_GROUP 8192
  55. /* Percentage of blocks that are reserved.*/
  56. #define RESERVED_BLOCKS 5/100
  57. #define MAX_RESERVED_BLOCKS 25/100
  58. +/* The default value for s_creator_os. */
  59. +#if defined(__linux__) && defined(EXT2_OS_LINUX)
  60. +#define CREATOR_OS EXT2_OS_LINUX
  61. +#define CREATOR_OS_NAME "linux"
  62. +#else
  63. +#if defined(__GNU__) && defined(EXT2_OS_HURD)
  64. +#define CREATOR_OS EXT2_OS_HURD
  65. +#define CREATOR_OS_NAME "hurd"
  66. +#else
  67. +#if defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD)
  68. +#define CREATOR_OS EXT2_OS_FREEBSD
  69. +#define CREATOR_OS_NAME "freebsd"
  70. +#else
  71. +#if defined(LITES) && defined(EXT2_OS_LITES)
  72. +#define CREATOR_OS EXT2_OS_LITES
  73. +#define CREATOR_OS_NAME "lites"
  74. +#else
  75. +#define CREATOR_OS EXT2_OS_LINUX /* by default */
  76. +#define CREATOR_OS_NAME "linux"
  77. +#endif /* defined(LITES) && defined(EXT2_OS_LITES) */
  78. +#endif /* defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD) */
  79. +#endif /* defined(__GNU__) && defined(EXT2_OS_HURD) */
  80. +#endif /* defined(__linux__) && defined(EXT2_OS_LINUX) */
  81. +
  82. // inode block size (why is it != BLOCKSIZE ?!?)
  83. /* The field i_blocks in the ext2 inode stores the number of data blocks
  84. @@ -190,6 +225,14 @@
  85. #define EXT2_TIND_BLOCK 14 // triple indirect block
  86. #define EXT2_INIT_BLOCK 0xFFFFFFFF // just initialized (not really a block address)
  87. +// codes for operating systems
  88. +
  89. +#define EXT2_OS_LINUX 0
  90. +#define EXT2_OS_HURD 1
  91. +#define EXT2_OS_MASIX 2
  92. +#define EXT2_OS_FREEBSD 3
  93. +#define EXT2_OS_LITES 4
  94. +
  95. // end of a block walk
  96. #define WALK_END 0xFFFFFFFE
  97. @@ -227,44 +270,46 @@
  98. #define FM_IWOTH 0000002 // write
  99. #define FM_IXOTH 0000001 // execute
  100. -// options
  101. -
  102. -#define OP_HOLES 0x01 // make files with holes
  103. -
  104. /* Defines for accessing group details */
  105. // Number of groups in the filesystem
  106. #define GRP_NBGROUPS(fs) \
  107. - (((fs)->sb.s_blocks_count - fs->sb.s_first_data_block + \
  108. - (fs)->sb.s_blocks_per_group - 1) / (fs)->sb.s_blocks_per_group)
  109. + (((fs)->sb->s_blocks_count - fs->sb->s_first_data_block + \
  110. + (fs)->sb->s_blocks_per_group - 1) / (fs)->sb->s_blocks_per_group)
  111. // Get group block bitmap (bbm) given the group number
  112. -#define GRP_GET_GROUP_BBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_block_bitmap) )
  113. +#define GRP_GET_GROUP_BBM(fs,grp,bi) (get_blk((fs),(grp)->bg_block_bitmap,(bi)))
  114. +#define GRP_PUT_GROUP_BBM(bi) ( put_blk((bi)) )
  115. // Get group inode bitmap (ibm) given the group number
  116. -#define GRP_GET_GROUP_IBM(fs,grp) ( get_blk((fs),(fs)->gd[(grp)].bg_inode_bitmap) )
  117. -
  118. +#define GRP_GET_GROUP_IBM(fs,grp,bi) (get_blk((fs), (grp)->bg_inode_bitmap,(bi)))
  119. +#define GRP_PUT_GROUP_IBM(bi) ( put_blk((bi)) )
  120. +
  121. // Given an inode number find the group it belongs to
  122. -#define GRP_GROUP_OF_INODE(fs,nod) ( ((nod)-1) / (fs)->sb.s_inodes_per_group)
  123. +#define GRP_GROUP_OF_INODE(fs,nod) ( ((nod)-1) / (fs)->sb->s_inodes_per_group)
  124. //Given an inode number get the inode bitmap that covers it
  125. -#define GRP_GET_INODE_BITMAP(fs,nod) \
  126. - ( GRP_GET_GROUP_IBM((fs),GRP_GROUP_OF_INODE((fs),(nod))) )
  127. +#define GRP_GET_INODE_BITMAP(fs,nod,bi,gi) \
  128. + ( GRP_GET_GROUP_IBM((fs),get_gd(fs,GRP_GROUP_OF_INODE((fs),(nod)),gi),bi) )
  129. +#define GRP_PUT_INODE_BITMAP(bi,gi) \
  130. + ( GRP_PUT_GROUP_IBM((bi)),put_gd((gi)) )
  131. //Given an inode number find its offset within the inode bitmap that covers it
  132. #define GRP_IBM_OFFSET(fs,nod) \
  133. - ( (nod) - GRP_GROUP_OF_INODE((fs),(nod))*(fs)->sb.s_inodes_per_group )
  134. + ( (nod) - GRP_GROUP_OF_INODE((fs),(nod))*(fs)->sb->s_inodes_per_group )
  135. // Given a block number find the group it belongs to
  136. -#define GRP_GROUP_OF_BLOCK(fs,blk) ( ((blk)-1) / (fs)->sb.s_blocks_per_group)
  137. +#define GRP_GROUP_OF_BLOCK(fs,blk) ( ((blk)-1) / (fs)->sb->s_blocks_per_group)
  138. -//Given a block number get the block bitmap that covers it
  139. -#define GRP_GET_BLOCK_BITMAP(fs,blk) \
  140. - ( GRP_GET_GROUP_BBM((fs),GRP_GROUP_OF_BLOCK((fs),(blk))) )
  141. +//Given a block number get/put the block bitmap that covers it
  142. +#define GRP_GET_BLOCK_BITMAP(fs,blk,bi,gi) \
  143. + ( GRP_GET_GROUP_BBM((fs),get_gd(fs,GRP_GROUP_OF_BLOCK((fs),(blk)),(gi)),(bi)) )
  144. +#define GRP_PUT_BLOCK_BITMAP(bi,gi) \
  145. + ( GRP_PUT_GROUP_BBM((bi)),put_gd((gi)) )
  146. //Given a block number find its offset within the block bitmap that covers it
  147. #define GRP_BBM_OFFSET(fs,blk) \
  148. - ( (blk) - GRP_GROUP_OF_BLOCK((fs),(blk))*(fs)->sb.s_blocks_per_group )
  149. + ( (blk) - GRP_GROUP_OF_BLOCK((fs),(blk))*(fs)->sb->s_blocks_per_group )
  150. // used types
  151. @@ -286,7 +331,9 @@
  152. // older solaris. Note that this is still not very portable, in that
  153. // the return value cannot be trusted.
  154. -#if SCANF_CAN_MALLOC
  155. +#if 0 // SCANF_CAN_MALLOC
  156. +// C99 define "a" for floating point, so you can have runtime surprise
  157. +// according the library versions
  158. # define SCANF_PREFIX "a"
  159. # define SCANF_STRING(s) (&s)
  160. #else
  161. @@ -430,6 +477,17 @@
  162. ((val<<8)&0xFF0000) | (val<<24));
  163. }
  164. +static inline int
  165. +is_blk_empty(uint8 *b)
  166. +{
  167. + uint32 i;
  168. + uint32 *v = (uint32 *) b;
  169. +
  170. + for(i = 0; i < BLOCKSIZE / 4; i++)
  171. + if (*v++)
  172. + return 0;
  173. + return 1;
  174. +}
  175. // on-disk structures
  176. // this trick makes me declare things only once
  177. @@ -460,7 +518,22 @@
  178. udecl32(s_creator_os) /* Indicator of which OS created the filesystem */ \
  179. udecl32(s_rev_level) /* The revision level of the filesystem */ \
  180. udecl16(s_def_resuid) /* The default uid for reserved blocks */ \
  181. - udecl16(s_def_resgid) /* The default gid for reserved blocks */
  182. + udecl16(s_def_resgid) /* The default gid for reserved blocks */ \
  183. + /* rev 1 version fields start here */ \
  184. + udecl32(s_first_ino) /* First non-reserved inode */ \
  185. + udecl16(s_inode_size) /* size of inode structure */ \
  186. + udecl16(s_block_group_nr) /* block group # of this superblock */ \
  187. + udecl32(s_feature_compat) /* compatible feature set */ \
  188. + udecl32(s_feature_incompat) /* incompatible feature set */ \
  189. + udecl32(s_feature_ro_compat) /* readonly-compatible feature set */ \
  190. + utdecl8(s_uuid,16) /* 128-bit uuid for volume */ \
  191. + utdecl8(s_volume_name,16) /* volume name */ \
  192. + utdecl8(s_last_mounted,64) /* directory where last mounted */ \
  193. + udecl32(s_algorithm_usage_bitmap) /* For compression */
  194. +
  195. +#define EXT2_GOOD_OLD_FIRST_INO 11
  196. +#define EXT2_GOOD_OLD_INODE_SIZE 128
  197. +#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
  198. #define groupdescriptor_decl \
  199. udecl32(bg_block_bitmap) /* Block number of the block bitmap */ \
  200. @@ -500,6 +573,7 @@
  201. #define decl8(x) int8 x;
  202. #define udecl8(x) uint8 x;
  203. +#define utdecl8(x,n) uint8 x[n];
  204. #define decl16(x) int16 x;
  205. #define udecl16(x) uint16 x;
  206. #define decl32(x) int32 x;
  207. @@ -509,7 +583,7 @@
  208. typedef struct
  209. {
  210. superblock_decl
  211. - uint32 s_reserved[235]; // Reserved
  212. + uint32 s_reserved[205]; // Reserved
  213. } superblock;
  214. typedef struct
  215. @@ -527,10 +601,9 @@
  216. typedef struct
  217. {
  218. directory_decl
  219. - char d_name[0];
  220. } directory;
  221. -typedef uint8 block[BLOCKSIZE];
  222. +typedef uint8 *block;
  223. /* blockwalker fields:
  224. The blockwalker is used to access all the blocks of a file (including
  225. @@ -567,23 +640,41 @@
  226. uint32 bptind;
  227. } blockwalker;
  228. +#define HDLINK_CNT 16
  229. +struct hdlink_s
  230. +{
  231. + uint32 src_inode;
  232. + uint32 dst_nod;
  233. +};
  234. +
  235. +struct hdlinks_s
  236. +{
  237. + int32 count;
  238. + struct hdlink_s *hdl;
  239. +};
  240. /* Filesystem structure that support groups */
  241. -#if BLOCKSIZE == 1024
  242. typedef struct
  243. {
  244. - block zero; // The famous block 0
  245. - superblock sb; // The superblock
  246. - groupdescriptor gd[0]; // The group descriptors
  247. + FILE *f;
  248. + superblock *sb;
  249. + int swapit;
  250. + int32 hdlink_cnt;
  251. + struct hdlinks_s hdlinks;
  252. +
  253. + int holes;
  254. +
  255. + listcache blks;
  256. + listcache gds;
  257. + listcache inodes;
  258. + listcache blkmaps;
  259. } filesystem;
  260. -#else
  261. -#error UNHANDLED BLOCKSIZE
  262. -#endif
  263. // now the endianness swap
  264. #undef decl8
  265. #undef udecl8
  266. +#undef utdecl8
  267. #undef decl16
  268. #undef udecl16
  269. #undef decl32
  270. @@ -592,28 +683,13 @@
  271. #define decl8(x)
  272. #define udecl8(x)
  273. +#define utdecl8(x,n)
  274. #define decl16(x) this->x = swab16(this->x);
  275. #define udecl16(x) this->x = swab16(this->x);
  276. #define decl32(x) this->x = swab32(this->x);
  277. #define udecl32(x) this->x = swab32(this->x);
  278. #define utdecl32(x,n) { int i; for(i=0; i<n; i++) this->x[i] = swab32(this->x[i]); }
  279. -#define HDLINK_CNT 16
  280. -static int32 hdlink_cnt = HDLINK_CNT;
  281. -struct hdlink_s
  282. -{
  283. - uint32 src_inode;
  284. - uint32 dst_nod;
  285. -};
  286. -
  287. -struct hdlinks_s
  288. -{
  289. - int32 count;
  290. - struct hdlink_s *hdl;
  291. -};
  292. -
  293. -static struct hdlinks_s hdlinks;
  294. -
  295. static void
  296. swap_sb(superblock *sb)
  297. {
  298. @@ -633,9 +709,24 @@
  299. static void
  300. swap_nod(inode *nod)
  301. {
  302. + uint32 nblk;
  303. +
  304. #define this nod
  305. inode_decl
  306. #undef this
  307. +
  308. + // block and character inodes store the major and minor in the
  309. + // i_block, so we need to unswap to get those. Also, if it's
  310. + // zero iblocks, put the data back like it belongs.
  311. + nblk = nod->i_blocks / INOBLK;
  312. + if ((nod->i_size && !nblk)
  313. + || ((nod->i_mode & FM_IFBLK) == FM_IFBLK)
  314. + || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
  315. + {
  316. + int i;
  317. + for(i = 0; i <= EXT2_TIND_BLOCK; i++)
  318. + nod->i_block[i] = swab32(nod->i_block[i]);
  319. + }
  320. }
  321. static void
  322. @@ -657,6 +748,7 @@
  323. #undef decl8
  324. #undef udecl8
  325. +#undef utdecl8
  326. #undef decl16
  327. #undef udecl16
  328. #undef decl32
  329. @@ -770,15 +862,15 @@
  330. }
  331. int
  332. -is_hardlink(ino_t inode)
  333. +is_hardlink(filesystem *fs, ino_t inode)
  334. {
  335. int i;
  336. - for(i = 0; i < hdlinks.count; i++) {
  337. - if(hdlinks.hdl[i].src_inode == inode)
  338. + for(i = 0; i < fs->hdlinks.count; i++) {
  339. + if(fs->hdlinks.hdl[i].src_inode == inode)
  340. return i;
  341. }
  342. - return -1;
  343. + return -1;
  344. }
  345. // printf helper macro
  346. @@ -789,6 +881,8 @@
  347. get_workblk(void)
  348. {
  349. unsigned char* b=calloc(1,BLOCKSIZE);
  350. + if (!b)
  351. + error_msg_and_die("get_workblk() failed, out of memory");
  352. return b;
  353. }
  354. static inline void
  355. @@ -811,24 +905,464 @@
  356. return b[(item-1) / 8] & (1 << ((item-1) % 8));
  357. }
  358. -// return a given block from a filesystem
  359. +// Used by get_blk/put_blk to hold information about a block owned
  360. +// by the user.
  361. +typedef struct
  362. +{
  363. + cache_link link;
  364. +
  365. + filesystem *fs;
  366. + uint32 blk;
  367. + uint8 *b;
  368. + uint32 usecount;
  369. +} blk_info;
  370. +
  371. +#define MAX_FREE_CACHE_BLOCKS 100
  372. +
  373. +static uint32
  374. +blk_elem_val(cache_link *elem)
  375. +{
  376. + blk_info *bi = container_of(elem, blk_info, link);
  377. + return bi->blk;
  378. +}
  379. +
  380. +static void
  381. +blk_freed(cache_link *elem)
  382. +{
  383. + blk_info *bi = container_of(elem, blk_info, link);
  384. +
  385. + if (fseeko(bi->fs->f, ((off_t) bi->blk) * BLOCKSIZE, SEEK_SET))
  386. + perror_msg_and_die("fseek");
  387. + if (fwrite(bi->b, BLOCKSIZE, 1, bi->fs->f) != 1)
  388. + perror_msg_and_die("get_blk: write");
  389. + free(bi->b);
  390. + free(bi);
  391. +}
  392. +
  393. +// Return a given block from a filesystem. Make sure to call
  394. +// put_blk when you are done with it.
  395. static inline uint8 *
  396. -get_blk(filesystem *fs, uint32 blk)
  397. +get_blk(filesystem *fs, uint32 blk, blk_info **rbi)
  398. {
  399. - return (uint8*)fs + blk*BLOCKSIZE;
  400. + cache_link *curr;
  401. + blk_info *bi;
  402. +
  403. + if (blk >= fs->sb->s_blocks_count)
  404. + error_msg_and_die("Internal error, block out of range");
  405. +
  406. + curr = cache_find(&fs->blks, blk);
  407. + if (curr) {
  408. + bi = container_of(curr, blk_info, link);
  409. + bi->usecount++;
  410. + goto out;
  411. + }
  412. +
  413. + bi = malloc(sizeof(*bi));
  414. + if (!bi)
  415. + error_msg_and_die("get_blk: out of memory");
  416. + bi->fs = fs;
  417. + bi->blk = blk;
  418. + bi->usecount = 1;
  419. + bi->b = malloc(BLOCKSIZE);
  420. + if (!bi->b)
  421. + error_msg_and_die("get_blk: out of memory");
  422. + cache_add(&fs->blks, &bi->link);
  423. + if (fseeko(fs->f, ((off_t) blk) * BLOCKSIZE, SEEK_SET))
  424. + perror_msg_and_die("fseek");
  425. + if (fread(bi->b, BLOCKSIZE, 1, fs->f) != 1) {
  426. + if (ferror(fs->f))
  427. + perror_msg_and_die("fread");
  428. + memset(bi->b, 0, BLOCKSIZE);
  429. + }
  430. +
  431. +out:
  432. + *rbi = bi;
  433. + return bi->b;
  434. }
  435. // return a given inode from a filesystem
  436. -static inline inode *
  437. -get_nod(filesystem *fs, uint32 nod)
  438. +static inline void
  439. +put_blk(blk_info *bi)
  440. +{
  441. + if (bi->usecount == 0)
  442. + error_msg_and_die("Internal error: put_blk usecount zero");
  443. + bi->usecount--;
  444. + if (bi->usecount == 0)
  445. + /* Free happens in the cache code */
  446. + cache_item_set_unused(&bi->fs->blks, &bi->link);
  447. +}
  448. +
  449. +typedef struct
  450. {
  451. - int grp,offset;
  452. + cache_link link;
  453. +
  454. + filesystem *fs;
  455. + int gds;
  456. + blk_info *bi;
  457. + groupdescriptor *gd;
  458. + uint32 usecount;
  459. +} gd_info;
  460. +
  461. +#define MAX_FREE_CACHE_GDS 100
  462. +
  463. +static uint32
  464. +gd_elem_val(cache_link *elem)
  465. +{
  466. + gd_info *gi = container_of(elem, gd_info, link);
  467. + return gi->gds;
  468. +}
  469. +
  470. +static void
  471. +gd_freed(cache_link *elem)
  472. +{
  473. + gd_info *gi = container_of(elem, gd_info, link);
  474. +
  475. + if (gi->fs->swapit)
  476. + swap_gd(gi->gd);
  477. + put_blk(gi->bi);
  478. + free(gi);
  479. +}
  480. +
  481. +#define GDS_START ((SUPERBLOCK_OFFSET + SUPERBLOCK_SIZE + BLOCKSIZE - 1) / BLOCKSIZE)
  482. +#define GDS_PER_BLOCK (BLOCKSIZE / sizeof(groupdescriptor))
  483. +// the group descriptors are aligned on the block size
  484. +static inline groupdescriptor *
  485. +get_gd(filesystem *fs, uint32 no, gd_info **rgi)
  486. +{
  487. + uint32 gdblk;
  488. + uint32 offset;
  489. + gd_info *gi;
  490. + cache_link *curr;
  491. +
  492. + curr = cache_find(&fs->gds, no);
  493. + if (curr) {
  494. + gi = container_of(curr, gd_info, link);
  495. + gi->usecount++;
  496. + goto out;
  497. + }
  498. +
  499. + gi = malloc(sizeof(*gi));
  500. + if (!gi)
  501. + error_msg_and_die("get_gd: out of memory");
  502. + gi->fs = fs;
  503. + gi->gds = no;
  504. + gi->usecount = 1;
  505. + gdblk = GDS_START + (no / GDS_PER_BLOCK);
  506. + offset = no % GDS_PER_BLOCK;
  507. + gi->gd = ((groupdescriptor *) get_blk(fs, gdblk, &gi->bi)) + offset;
  508. + cache_add(&fs->gds, &gi->link);
  509. + if (fs->swapit)
  510. + swap_gd(gi->gd);
  511. + out:
  512. + *rgi = gi;
  513. +
  514. + return gi->gd;
  515. +}
  516. +
  517. +static inline void
  518. +put_gd(gd_info *gi)
  519. +{
  520. + if (gi->usecount == 0)
  521. + error_msg_and_die("Internal error: put_gd usecount zero");
  522. +
  523. + gi->usecount--;
  524. + if (gi->usecount == 0)
  525. + /* Free happens in the cache code */
  526. + cache_item_set_unused(&gi->fs->gds, &gi->link);
  527. +}
  528. +
  529. +// Used by get_blkmap/put_blkmap to hold information about an block map
  530. +// owned by the user.
  531. +typedef struct
  532. +{
  533. + cache_link link;
  534. +
  535. + filesystem *fs;
  536. + uint32 blk;
  537. + uint8 *b;
  538. + blk_info *bi;
  539. + uint32 usecount;
  540. +} blkmap_info;
  541. +
  542. +#define MAX_FREE_CACHE_BLOCKMAPS 100
  543. +
  544. +static uint32
  545. +blkmap_elem_val(cache_link *elem)
  546. +{
  547. + blkmap_info *bmi = container_of(elem, blkmap_info, link);
  548. + return bmi->blk;
  549. +}
  550. +
  551. +static void
  552. +blkmap_freed(cache_link *elem)
  553. +{
  554. + blkmap_info *bmi = container_of(elem, blkmap_info, link);
  555. +
  556. + if (bmi->fs->swapit)
  557. + swap_block(bmi->b);
  558. + put_blk(bmi->bi);
  559. + free(bmi);
  560. +}
  561. +
  562. +// Return a given block map from a filesystem. Make sure to call
  563. +// put_blkmap when you are done with it.
  564. +static inline uint32 *
  565. +get_blkmap(filesystem *fs, uint32 blk, blkmap_info **rbmi)
  566. +{
  567. + blkmap_info *bmi;
  568. + cache_link *curr;
  569. +
  570. + curr = cache_find(&fs->blkmaps, blk);
  571. + if (curr) {
  572. + bmi = container_of(curr, blkmap_info, link);
  573. + bmi->usecount++;
  574. + goto out;
  575. + }
  576. +
  577. + bmi = malloc(sizeof(*bmi));
  578. + if (!bmi)
  579. + error_msg_and_die("get_blkmap: out of memory");
  580. + bmi->fs = fs;
  581. + bmi->blk = blk;
  582. + bmi->b = get_blk(fs, blk, &bmi->bi);
  583. + bmi->usecount = 1;
  584. + cache_add(&fs->blkmaps, &bmi->link);
  585. +
  586. + if (fs->swapit)
  587. + swap_block(bmi->b);
  588. + out:
  589. + *rbmi = bmi;
  590. + return (uint32 *) bmi->b;
  591. +}
  592. +
  593. +static inline void
  594. +put_blkmap(blkmap_info *bmi)
  595. +{
  596. + if (bmi->usecount == 0)
  597. + error_msg_and_die("Internal error: put_blkmap usecount zero");
  598. +
  599. + bmi->usecount--;
  600. + if (bmi->usecount == 0)
  601. + /* Free happens in the cache code */
  602. + cache_item_set_unused(&bmi->fs->blkmaps, &bmi->link);
  603. +}
  604. +
  605. +// Used by get_nod/put_nod to hold information about an inode owned
  606. +// by the user.
  607. +typedef struct
  608. +{
  609. + cache_link link;
  610. +
  611. + filesystem *fs;
  612. + uint32 nod;
  613. + uint8 *b;
  614. + blk_info *bi;
  615. inode *itab;
  616. + uint32 usecount;
  617. +} nod_info;
  618. +
  619. +#define MAX_FREE_CACHE_INODES 100
  620. +
  621. +static uint32
  622. +inode_elem_val(cache_link *elem)
  623. +{
  624. + nod_info *ni = container_of(elem, nod_info, link);
  625. + return ni->nod;
  626. +}
  627. +
  628. +static void
  629. +inode_freed(cache_link *elem)
  630. +{
  631. + nod_info *ni = container_of(elem, nod_info, link);
  632. +
  633. + if (ni->fs->swapit)
  634. + swap_nod(ni->itab);
  635. + put_blk(ni->bi);
  636. + free(ni);
  637. +}
  638. +
  639. +#define INODES_PER_BLOCK (BLOCKSIZE / sizeof(inode))
  640. - offset = GRP_IBM_OFFSET(fs,nod);
  641. +// return a given inode from a filesystem
  642. +static inline inode *
  643. +get_nod(filesystem *fs, uint32 nod, nod_info **rni)
  644. +{
  645. + uint32 grp, boffset, offset;
  646. + cache_link *curr;
  647. + groupdescriptor *gd;
  648. + gd_info *gi;
  649. + nod_info *ni;
  650. +
  651. + curr = cache_find(&fs->inodes, nod);
  652. + if (curr) {
  653. + ni = container_of(curr, nod_info, link);
  654. + ni->usecount++;
  655. + goto out;
  656. + }
  657. +
  658. + ni = malloc(sizeof(*ni));
  659. + if (!ni)
  660. + error_msg_and_die("get_nod: out of memory");
  661. + ni->fs = fs;
  662. + ni->nod = nod;
  663. + ni->usecount = 1;
  664. + cache_add(&fs->inodes, &ni->link);
  665. +
  666. + offset = GRP_IBM_OFFSET(fs,nod) - 1;
  667. + boffset = offset / INODES_PER_BLOCK;
  668. + offset %= INODES_PER_BLOCK;
  669. grp = GRP_GROUP_OF_INODE(fs,nod);
  670. - itab = (inode *)get_blk(fs, fs->gd[grp].bg_inode_table);
  671. - return itab+offset-1;
  672. + gd = get_gd(fs, grp, &gi);
  673. + ni->b = get_blk(fs, gd->bg_inode_table + boffset, &ni->bi);
  674. + ni->itab = ((inode *) ni->b) + offset;
  675. + if (fs->swapit)
  676. + swap_nod(ni->itab);
  677. + put_gd(gi);
  678. + out:
  679. + *rni = ni;
  680. + return ni->itab;
  681. +}
  682. +
  683. +static inline void
  684. +put_nod(nod_info *ni)
  685. +{
  686. + if (ni->usecount == 0)
  687. + error_msg_and_die("Internal error: put_nod usecount zero");
  688. +
  689. + ni->usecount--;
  690. + if (ni->usecount == 0)
  691. + /* Free happens in the cache code */
  692. + cache_item_set_unused(&ni->fs->inodes, &ni->link);
  693. +}
  694. +
  695. +// Used to hold state information while walking a directory inode.
  696. +typedef struct
  697. +{
  698. + directory d;
  699. + filesystem *fs;
  700. + uint32 nod;
  701. + directory *last_d;
  702. + uint8 *b;
  703. + blk_info *bi;
  704. +} dirwalker;
  705. +
  706. +// Start a directory walk on the given inode. You must pass in a
  707. +// dirwalker structure, then use that dirwalker for future operations.
  708. +// Call put_dir when you are done walking the directory.
  709. +static inline directory *
  710. +get_dir(filesystem *fs, uint32 nod, dirwalker *dw)
  711. +{
  712. + dw->fs = fs;
  713. + dw->b = get_blk(fs, nod, &dw->bi);
  714. + dw->nod = nod;
  715. + dw->last_d = (directory *) dw->b;
  716. +
  717. + memcpy(&dw->d, dw->last_d, sizeof(directory));
  718. + if (fs->swapit)
  719. + swap_dir(&dw->d);
  720. + return &dw->d;
  721. +}
  722. +
  723. +// Move to the next directory.
  724. +static inline directory *
  725. +next_dir(dirwalker *dw)
  726. +{
  727. + directory *next_d = (directory *)((int8*)dw->last_d + dw->d.d_rec_len);
  728. +
  729. + if (dw->fs->swapit)
  730. + swap_dir(&dw->d);
  731. + memcpy(dw->last_d, &dw->d, sizeof(directory));
  732. +
  733. + if (((int8 *) next_d) >= ((int8 *) dw->b + BLOCKSIZE))
  734. + return NULL;
  735. +
  736. + dw->last_d = next_d;
  737. + memcpy(&dw->d, next_d, sizeof(directory));
  738. + if (dw->fs->swapit)
  739. + swap_dir(&dw->d);
  740. + return &dw->d;
  741. +}
  742. +
  743. +// Call then when you are done with the directory walk.
  744. +static inline void
  745. +put_dir(dirwalker *dw)
  746. +{
  747. + if (dw->fs->swapit)
  748. + swap_dir(&dw->d);
  749. + memcpy(dw->last_d, &dw->d, sizeof(directory));
  750. +
  751. + if (dw->nod == 0)
  752. + free_workblk(dw->b);
  753. + else
  754. + put_blk(dw->bi);
  755. +}
  756. +
  757. +// Create a new directory block with the given inode as it's destination
  758. +// and append it to the current dirwalker.
  759. +static directory *
  760. +new_dir(filesystem *fs, uint32 dnod, const char *name, int nlen, dirwalker *dw)
  761. +{
  762. + directory *d;
  763. +
  764. + dw->fs = fs;
  765. + dw->b = get_workblk();
  766. + dw->nod = 0;
  767. + dw->last_d = (directory *) dw->b;
  768. + d = &dw->d;
  769. + d->d_inode = dnod;
  770. + d->d_rec_len = BLOCKSIZE;
  771. + d->d_name_len = nlen;
  772. + strncpy(((char *) dw->last_d) + sizeof(directory), name, nlen);
  773. + return d;
  774. +}
  775. +
  776. +// Shrink the current directory entry, make a new one with the free
  777. +// space, and return the new directory entry (making it current).
  778. +static inline directory *
  779. +shrink_dir(dirwalker *dw, uint32 nod, const char *name, int nlen)
  780. +{
  781. + int reclen, preclen;
  782. + directory *d = &dw->d;
  783. +
  784. + reclen = d->d_rec_len;
  785. + d->d_rec_len = sizeof(directory) + rndup(d->d_name_len, 4);
  786. + preclen = d->d_rec_len;
  787. + reclen -= preclen;
  788. + if (dw->fs->swapit)
  789. + swap_dir(&dw->d);
  790. + memcpy(dw->last_d, &dw->d, sizeof(directory));
  791. +
  792. + dw->last_d = (directory *) (((int8 *) dw->last_d) + preclen);
  793. + d->d_rec_len = reclen;
  794. + d->d_inode = nod;
  795. + d->d_name_len = nlen;
  796. + strncpy(((char *) dw->last_d) + sizeof(directory), name, nlen);
  797. +
  798. + return d;
  799. +}
  800. +
  801. +// Return the current block the directory is walking
  802. +static inline uint8 *
  803. +dir_data(dirwalker *dw)
  804. +{
  805. + return dw->b;
  806. +}
  807. +
  808. +// Return the pointer to the name for the current directory
  809. +static inline char *
  810. +dir_name(dirwalker *dw)
  811. +{
  812. + return ((char *) dw->last_d) + sizeof(directory);
  813. +}
  814. +
  815. +// Set the name for the current directory. Note that this doesn't
  816. +// verify that there is space for the directory name, you must do
  817. +// that yourself.
  818. +static void
  819. +dir_set_name(dirwalker *dw, const char *name, int nlen)
  820. +{
  821. + dw->d.d_name_len = nlen;
  822. + strncpy(((char *) dw->last_d) + sizeof(directory), name, nlen);
  823. }
  824. // allocate a given block/inode in the bitmap
  825. @@ -870,21 +1404,34 @@
  826. {
  827. uint32 bk=0;
  828. uint32 grp,nbgroups;
  829. + blk_info *bi;
  830. + groupdescriptor *gd;
  831. + gd_info *gi;
  832. grp = GRP_GROUP_OF_INODE(fs,nod);
  833. nbgroups = GRP_NBGROUPS(fs);
  834. - if(!(bk = allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap), 0))) {
  835. - for(grp=0;grp<nbgroups && !bk;grp++)
  836. - bk=allocate(get_blk(fs,fs->gd[grp].bg_block_bitmap),0);
  837. + gd = get_gd(fs, grp, &gi);
  838. + bk = allocate(GRP_GET_GROUP_BBM(fs, gd, &bi), 0);
  839. + GRP_PUT_GROUP_BBM(bi);
  840. + put_gd(gi);
  841. + if (!bk) {
  842. + for (grp=0; grp<nbgroups && !bk; grp++) {
  843. + gd = get_gd(fs, grp, &gi);
  844. + bk = allocate(GRP_GET_GROUP_BBM(fs, gd, &bi), 0);
  845. + GRP_PUT_GROUP_BBM(bi);
  846. + put_gd(gi);
  847. + }
  848. grp--;
  849. }
  850. if (!bk)
  851. error_msg_and_die("couldn't allocate a block (no free space)");
  852. - if(!(fs->gd[grp].bg_free_blocks_count--))
  853. + gd = get_gd(fs, grp, &gi);
  854. + if(!(gd->bg_free_blocks_count--))
  855. error_msg_and_die("group descr %d. free blocks count == 0 (corrupted fs?)",grp);
  856. - if(!(fs->sb.s_free_blocks_count--))
  857. + put_gd(gi);
  858. + if(!(fs->sb->s_free_blocks_count--))
  859. error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
  860. - return fs->sb.s_blocks_per_group*grp + bk;
  861. + return fs->sb->s_first_data_block + fs->sb->s_blocks_per_group*grp + (bk-1);
  862. }
  863. // free a block
  864. @@ -892,12 +1439,18 @@
  865. free_blk(filesystem *fs, uint32 bk)
  866. {
  867. uint32 grp;
  868. -
  869. - grp = bk / fs->sb.s_blocks_per_group;
  870. - bk %= fs->sb.s_blocks_per_group;
  871. - deallocate(get_blk(fs,fs->gd[grp].bg_block_bitmap), bk);
  872. - fs->gd[grp].bg_free_blocks_count++;
  873. - fs->sb.s_free_blocks_count++;
  874. + blk_info *bi;
  875. + gd_info *gi;
  876. + groupdescriptor *gd;
  877. +
  878. + grp = bk / fs->sb->s_blocks_per_group;
  879. + bk %= fs->sb->s_blocks_per_group;
  880. + gd = get_gd(fs, grp, &gi);
  881. + deallocate(GRP_GET_GROUP_BBM(fs, gd, &bi), bk);
  882. + GRP_PUT_GROUP_BBM(bi);
  883. + gd->bg_free_blocks_count++;
  884. + put_gd(gi);
  885. + fs->sb->s_free_blocks_count++;
  886. }
  887. // allocate an inode
  888. @@ -906,6 +1459,9 @@
  889. {
  890. uint32 nod,best_group=0;
  891. uint32 grp,nbgroups,avefreei;
  892. + blk_info *bi;
  893. + gd_info *gi, *bestgi;
  894. + groupdescriptor *gd, *bestgd;
  895. nbgroups = GRP_NBGROUPS(fs);
  896. @@ -914,22 +1470,32 @@
  897. /* find the one with the most free blocks and allocate node there */
  898. /* Idea from find_group_dir in fs/ext2/ialloc.c in 2.4.19 kernel */
  899. /* We do it for all inodes. */
  900. - avefreei = fs->sb.s_free_inodes_count / nbgroups;
  901. + avefreei = fs->sb->s_free_inodes_count / nbgroups;
  902. + bestgd = get_gd(fs, best_group, &bestgi);
  903. for(grp=0; grp<nbgroups; grp++) {
  904. - if (fs->gd[grp].bg_free_inodes_count < avefreei ||
  905. - fs->gd[grp].bg_free_inodes_count == 0)
  906. + gd = get_gd(fs, grp, &gi);
  907. + if (gd->bg_free_inodes_count < avefreei ||
  908. + gd->bg_free_inodes_count == 0) {
  909. + put_gd(gi);
  910. continue;
  911. - if (!best_group ||
  912. - fs->gd[grp].bg_free_blocks_count > fs->gd[best_group].bg_free_blocks_count)
  913. + }
  914. + if (!best_group || gd->bg_free_blocks_count > bestgd->bg_free_blocks_count) {
  915. + put_gd(bestgi);
  916. best_group = grp;
  917. + bestgd = gd;
  918. + bestgi = gi;
  919. + } else
  920. + put_gd(gi);
  921. }
  922. - if (!(nod = allocate(get_blk(fs,fs->gd[best_group].bg_inode_bitmap),0)))
  923. + if (!(nod = allocate(GRP_GET_GROUP_IBM(fs, bestgd, &bi), 0)))
  924. error_msg_and_die("couldn't allocate an inode (no free inode)");
  925. - if(!(fs->gd[best_group].bg_free_inodes_count--))
  926. + GRP_PUT_GROUP_IBM(bi);
  927. + if(!(bestgd->bg_free_inodes_count--))
  928. error_msg_and_die("group descr. free blocks count == 0 (corrupted fs?)");
  929. - if(!(fs->sb.s_free_inodes_count--))
  930. + put_gd(bestgi);
  931. + if(!(fs->sb->s_free_inodes_count--))
  932. error_msg_and_die("superblock free blocks count == 0 (corrupted fs?)");
  933. - return fs->sb.s_inodes_per_group*best_group+nod;
  934. + return fs->sb->s_inodes_per_group*best_group+nod;
  935. }
  936. // print a bitmap allocation
  937. @@ -962,30 +1528,40 @@
  938. // used after being freed, so once you start
  939. // freeing blocks don't stop until the end of
  940. // the file. moreover, i_blocks isn't updated.
  941. -// in fact, don't do that, just use extend_blk
  942. // if hole!=0, create a hole in the file
  943. static uint32
  944. walk_bw(filesystem *fs, uint32 nod, blockwalker *bw, int32 *create, uint32 hole)
  945. {
  946. uint32 *bkref = 0;
  947. + uint32 bk = 0;
  948. + blkmap_info *bmi1 = NULL, *bmi2 = NULL, *bmi3 = NULL;
  949. uint32 *b;
  950. int extend = 0, reduce = 0;
  951. + inode *inod;
  952. + nod_info *ni;
  953. + uint32 *iblk;
  954. +
  955. if(create && (*create) < 0)
  956. reduce = 1;
  957. - if(bw->bnum >= get_nod(fs, nod)->i_blocks / INOBLK)
  958. + inod = get_nod(fs, nod, &ni);
  959. + if(bw->bnum >= inod->i_blocks / INOBLK)
  960. {
  961. if(create && (*create) > 0)
  962. {
  963. (*create)--;
  964. extend = 1;
  965. }
  966. - else
  967. + else
  968. + {
  969. + put_nod(ni);
  970. return WALK_END;
  971. + }
  972. }
  973. + iblk = inod->i_block;
  974. // first direct block
  975. if(bw->bpdir == EXT2_INIT_BLOCK)
  976. {
  977. - bkref = &get_nod(fs, nod)->i_block[bw->bpdir = 0];
  978. + bkref = &iblk[bw->bpdir = 0];
  979. if(extend) // allocate first block
  980. *bkref = hole ? 0 : alloc_blk(fs,nod);
  981. if(reduce) // free first block
  982. @@ -994,7 +1570,7 @@
  983. // direct block
  984. else if(bw->bpdir < EXT2_NDIR_BLOCKS)
  985. {
  986. - bkref = &get_nod(fs, nod)->i_block[++bw->bpdir];
  987. + bkref = &iblk[++bw->bpdir];
  988. if(extend) // allocate block
  989. *bkref = hole ? 0 : alloc_blk(fs,nod);
  990. if(reduce) // free block
  991. @@ -1007,10 +1583,10 @@
  992. bw->bpdir = EXT2_IND_BLOCK;
  993. bw->bpind = 0;
  994. if(extend) // allocate indirect block
  995. - get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
  996. + iblk[bw->bpdir] = alloc_blk(fs,nod);
  997. if(reduce) // free indirect block
  998. - free_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
  999. - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
  1000. + free_blk(fs, iblk[bw->bpdir]);
  1001. + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
  1002. bkref = &b[bw->bpind];
  1003. if(extend) // allocate first block
  1004. *bkref = hole ? 0 : alloc_blk(fs,nod);
  1005. @@ -1021,7 +1597,7 @@
  1006. else if((bw->bpdir == EXT2_IND_BLOCK) && (bw->bpind < BLOCKSIZE/4 - 1))
  1007. {
  1008. bw->bpind++;
  1009. - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
  1010. + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
  1011. bkref = &b[bw->bpind];
  1012. if(extend) // allocate block
  1013. *bkref = hole ? 0 : alloc_blk(fs,nod);
  1014. @@ -1036,15 +1612,15 @@
  1015. bw->bpind = 0;
  1016. bw->bpdind = 0;
  1017. if(extend) // allocate double indirect block
  1018. - get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
  1019. + iblk[bw->bpdir] = alloc_blk(fs,nod);
  1020. if(reduce) // free double indirect block
  1021. - free_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
  1022. - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
  1023. + free_blk(fs, iblk[bw->bpdir]);
  1024. + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
  1025. if(extend) // allocate first indirect block
  1026. b[bw->bpind] = alloc_blk(fs,nod);
  1027. if(reduce) // free firstindirect block
  1028. free_blk(fs, b[bw->bpind]);
  1029. - b = (uint32*)get_blk(fs, b[bw->bpind]);
  1030. + b = get_blkmap(fs, b[bw->bpind], &bmi2);
  1031. bkref = &b[bw->bpdind];
  1032. if(extend) // allocate first block
  1033. *bkref = hole ? 0 : alloc_blk(fs,nod);
  1034. @@ -1055,8 +1631,8 @@
  1035. else if((bw->bpdir == EXT2_DIND_BLOCK) && (bw->bpdind < BLOCKSIZE/4 - 1))
  1036. {
  1037. bw->bpdind++;
  1038. - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
  1039. - b = (uint32*)get_blk(fs, b[bw->bpind]);
  1040. + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
  1041. + b = get_blkmap(fs, b[bw->bpind], &bmi2);
  1042. bkref = &b[bw->bpdind];
  1043. if(extend) // allocate block
  1044. *bkref = hole ? 0 : alloc_blk(fs,nod);
  1045. @@ -1069,12 +1645,12 @@
  1046. bw->bnum++;
  1047. bw->bpdind = 0;
  1048. bw->bpind++;
  1049. - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
  1050. + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
  1051. if(extend) // allocate indirect block
  1052. b[bw->bpind] = alloc_blk(fs,nod);
  1053. if(reduce) // free indirect block
  1054. free_blk(fs, b[bw->bpind]);
  1055. - b = (uint32*)get_blk(fs, b[bw->bpind]);
  1056. + b = get_blkmap(fs, b[bw->bpind], &bmi2);
  1057. bkref = &b[bw->bpdind];
  1058. if(extend) // allocate first block
  1059. *bkref = hole ? 0 : alloc_blk(fs,nod);
  1060. @@ -1094,20 +1670,20 @@
  1061. bw->bpdind = 0;
  1062. bw->bptind = 0;
  1063. if(extend) // allocate triple indirect block
  1064. - get_nod(fs, nod)->i_block[bw->bpdir] = alloc_blk(fs,nod);
  1065. + iblk[bw->bpdir] = alloc_blk(fs,nod);
  1066. if(reduce) // free triple indirect block
  1067. - free_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
  1068. - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
  1069. + free_blk(fs, iblk[bw->bpdir]);
  1070. + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
  1071. if(extend) // allocate first double indirect block
  1072. b[bw->bpind] = alloc_blk(fs,nod);
  1073. if(reduce) // free first double indirect block
  1074. free_blk(fs, b[bw->bpind]);
  1075. - b = (uint32*)get_blk(fs, b[bw->bpind]);
  1076. + b = get_blkmap(fs, b[bw->bpind], &bmi2);
  1077. if(extend) // allocate first indirect block
  1078. b[bw->bpdind] = alloc_blk(fs,nod);
  1079. if(reduce) // free first indirect block
  1080. free_blk(fs, b[bw->bpind]);
  1081. - b = (uint32*)get_blk(fs, b[bw->bpdind]);
  1082. + b = get_blkmap(fs, b[bw->bpdind], &bmi3);
  1083. bkref = &b[bw->bptind];
  1084. if(extend) // allocate first data block
  1085. *bkref = hole ? 0 : alloc_blk(fs,nod);
  1086. @@ -1121,9 +1697,9 @@
  1087. (bw->bptind < BLOCKSIZE/4 -1) )
  1088. {
  1089. bw->bptind++;
  1090. - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
  1091. - b = (uint32*)get_blk(fs, b[bw->bpind]);
  1092. - b = (uint32*)get_blk(fs, b[bw->bpdind]);
  1093. + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
  1094. + b = get_blkmap(fs, b[bw->bpind], &bmi2);
  1095. + b = get_blkmap(fs, b[bw->bpdind], &bmi3);
  1096. bkref = &b[bw->bptind];
  1097. if(extend) // allocate data block
  1098. *bkref = hole ? 0 : alloc_blk(fs,nod);
  1099. @@ -1140,13 +1716,13 @@
  1100. bw->bnum++;
  1101. bw->bptind = 0;
  1102. bw->bpdind++;
  1103. - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
  1104. - b = (uint32*)get_blk(fs, b[bw->bpind]);
  1105. + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
  1106. + b = get_blkmap(fs, b[bw->bpind], &bmi2);
  1107. if(extend) // allocate single indirect block
  1108. b[bw->bpdind] = alloc_blk(fs,nod);
  1109. if(reduce) // free indirect block
  1110. free_blk(fs, b[bw->bpind]);
  1111. - b = (uint32*)get_blk(fs, b[bw->bpdind]);
  1112. + b = get_blkmap(fs, b[bw->bpdind], &bmi3);
  1113. bkref = &b[bw->bptind];
  1114. if(extend) // allocate first data block
  1115. *bkref = hole ? 0 : alloc_blk(fs,nod);
  1116. @@ -1163,17 +1739,17 @@
  1117. bw->bpdind = 0;
  1118. bw->bptind = 0;
  1119. bw->bpind++;
  1120. - b = (uint32*)get_blk(fs, get_nod(fs, nod)->i_block[bw->bpdir]);
  1121. + b = get_blkmap(fs, iblk[bw->bpdir], &bmi1);
  1122. if(extend) // allocate double indirect block
  1123. b[bw->bpind] = alloc_blk(fs,nod);
  1124. if(reduce) // free double indirect block
  1125. free_blk(fs, b[bw->bpind]);
  1126. - b = (uint32*)get_blk(fs, b[bw->bpind]);
  1127. + b = get_blkmap(fs, b[bw->bpind], &bmi2);
  1128. if(extend) // allocate single indirect block
  1129. b[bw->bpdind] = alloc_blk(fs,nod);
  1130. if(reduce) // free indirect block
  1131. free_blk(fs, b[bw->bpind]);
  1132. - b = (uint32*)get_blk(fs, b[bw->bpdind]);
  1133. + b = get_blkmap(fs, b[bw->bpdind], &bmi3);
  1134. bkref = &b[bw->bptind];
  1135. if(extend) // allocate first block
  1136. *bkref = hole ? 0 : alloc_blk(fs,nod);
  1137. @@ -1184,56 +1760,105 @@
  1138. error_msg_and_die("file too big !");
  1139. /* End change for walking triple indirection */
  1140. - if(*bkref)
  1141. - {
  1142. + bk = *bkref;
  1143. + if (bmi3)
  1144. + put_blkmap(bmi3);
  1145. + if (bmi2)
  1146. + put_blkmap(bmi2);
  1147. + if (bmi1)
  1148. + put_blkmap(bmi1);
  1149. +
  1150. + if(bk)
  1151. + {
  1152. + blk_info *bi;
  1153. + gd_info *gi;
  1154. + uint8 *block;
  1155. bw->bnum++;
  1156. - if(!reduce && !allocated(GRP_GET_BLOCK_BITMAP(fs,*bkref), GRP_BBM_OFFSET(fs,*bkref)))
  1157. - error_msg_and_die("[block %d of inode %d is unallocated !]", *bkref, nod);
  1158. + block = GRP_GET_BLOCK_BITMAP(fs,bk,&bi,&gi);
  1159. + if(!reduce && !allocated(block, GRP_BBM_OFFSET(fs,bk)))
  1160. + error_msg_and_die("[block %d of inode %d is unallocated !]", bk, nod);
  1161. + GRP_PUT_BLOCK_BITMAP(bi, gi);
  1162. }
  1163. if(extend)
  1164. - get_nod(fs, nod)->i_blocks = bw->bnum * INOBLK;
  1165. - return *bkref;
  1166. + inod->i_blocks = bw->bnum * INOBLK;
  1167. + put_nod(ni);
  1168. + return bk;
  1169. }
  1170. -// add blocks to an inode (file/dir/etc...)
  1171. -static void
  1172. -extend_blk(filesystem *fs, uint32 nod, block b, int amount)
  1173. +typedef struct
  1174. {
  1175. - int create = amount;
  1176. - blockwalker bw, lbw;
  1177. - uint32 bk;
  1178. - init_bw(&bw);
  1179. - if(amount < 0)
  1180. - {
  1181. - uint32 i;
  1182. - for(i = 0; i < get_nod(fs, nod)->i_blocks / INOBLK + amount; i++)
  1183. - walk_bw(fs, nod, &bw, 0, 0);
  1184. - while(walk_bw(fs, nod, &bw, &create, 0) != WALK_END)
  1185. + blockwalker bw;
  1186. + uint32 nod;
  1187. + nod_info *ni;
  1188. + inode *inod;
  1189. +} inode_pos;
  1190. +#define INODE_POS_TRUNCATE 0
  1191. +#define INODE_POS_EXTEND 1
  1192. +
  1193. +// Call this to set up an ipos structure for future use with
  1194. +// extend_inode_blk to append blocks to the given inode. If
  1195. +// op is INODE_POS_TRUNCATE, the inode is truncated to zero size.
  1196. +// If op is INODE_POS_EXTEND, the position is moved to the end
  1197. +// of the inode's data blocks.
  1198. +// Call inode_pos_finish when done with the inode_pos structure.
  1199. +static void
  1200. +inode_pos_init(filesystem *fs, inode_pos *ipos, uint32 nod, int op,
  1201. + blockwalker *endbw)
  1202. +{
  1203. + blockwalker lbw;
  1204. +
  1205. + init_bw(&ipos->bw);
  1206. + ipos->nod = nod;
  1207. + ipos->inod = get_nod(fs, nod, &ipos->ni);
  1208. + if (op == INODE_POS_TRUNCATE) {
  1209. + int32 create = -1;
  1210. + while(walk_bw(fs, nod, &ipos->bw, &create, 0) != WALK_END)
  1211. /*nop*/;
  1212. - get_nod(fs, nod)->i_blocks += amount * INOBLK;
  1213. + ipos->inod->i_blocks = 0;
  1214. }
  1215. - else
  1216. +
  1217. + if (endbw)
  1218. + ipos->bw = *endbw;
  1219. + else {
  1220. + /* Seek to the end */
  1221. + init_bw(&ipos->bw);
  1222. + lbw = ipos->bw;
  1223. + while(walk_bw(fs, nod, &ipos->bw, 0, 0) != WALK_END)
  1224. + lbw = ipos->bw;
  1225. + ipos->bw = lbw;
  1226. + }
  1227. +}
  1228. +
  1229. +// Clean up the inode_pos structure.
  1230. +static void
  1231. +inode_pos_finish(filesystem *fs, inode_pos *ipos)
  1232. +{
  1233. + put_nod(ipos->ni);
  1234. +}
  1235. +
  1236. +// add blocks to an inode (file/dir/etc...) at the given position.
  1237. +// This will only work when appending to the end of an inode.
  1238. +static void
  1239. +extend_inode_blk(filesystem *fs, inode_pos *ipos, block b, int amount)
  1240. +{
  1241. + uint32 bk;
  1242. + uint32 pos;
  1243. +
  1244. + if (amount < 0)
  1245. + error_msg_and_die("extend_inode_blk: Got negative amount");
  1246. +
  1247. + for (pos = 0; amount; pos += BLOCKSIZE)
  1248. {
  1249. - lbw = bw;
  1250. - while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
  1251. - lbw = bw;
  1252. - bw = lbw;
  1253. - while(create)
  1254. - {
  1255. - int i, copyb = 0;
  1256. - if(!(fs->sb.s_reserved[200] & OP_HOLES))
  1257. - copyb = 1;
  1258. - else
  1259. - for(i = 0; i < BLOCKSIZE / 4; i++)
  1260. - if(((int32*)(b + BLOCKSIZE * (amount - create)))[i])
  1261. - {
  1262. - copyb = 1;
  1263. - break;
  1264. - }
  1265. - if((bk = walk_bw(fs, nod, &bw, &create, !copyb)) == WALK_END)
  1266. - break;
  1267. - if(copyb)
  1268. - memcpy(get_blk(fs, bk), b + BLOCKSIZE * (amount - create - 1), BLOCKSIZE);
  1269. + int hole = (fs->holes && is_blk_empty(b + pos));
  1270. +
  1271. + bk = walk_bw(fs, ipos->nod, &ipos->bw, &amount, hole);
  1272. + if (bk == WALK_END)
  1273. + error_msg_and_die("extend_inode_blk: extend failed");
  1274. + if (!hole) {
  1275. + blk_info *bi;
  1276. + uint8 *block = get_blk(fs, bk, &bi);
  1277. + memcpy(block, b + pos, BLOCKSIZE);
  1278. + put_blk(bi);
  1279. }
  1280. }
  1281. }
  1282. @@ -1242,15 +1867,17 @@
  1283. static void
  1284. add2dir(filesystem *fs, uint32 dnod, uint32 nod, const char* name)
  1285. {
  1286. - blockwalker bw;
  1287. + blockwalker bw, lbw;
  1288. uint32 bk;
  1289. - uint8 *b;
  1290. directory *d;
  1291. + dirwalker dw;
  1292. int reclen, nlen;
  1293. inode *node;
  1294. inode *pnode;
  1295. + nod_info *dni, *ni;
  1296. + inode_pos ipos;
  1297. - pnode = get_nod(fs, dnod);
  1298. + pnode = get_nod(fs, dnod, &dni);
  1299. if((pnode->i_mode & FM_IFMT) != FM_IFDIR)
  1300. error_msg_and_die("can't add '%s' to a non-directory", name);
  1301. if(!*name)
  1302. @@ -1262,52 +1889,52 @@
  1303. if(reclen > BLOCKSIZE)
  1304. error_msg_and_die("bad name '%s' (too long)", name);
  1305. init_bw(&bw);
  1306. + lbw = bw;
  1307. while((bk = walk_bw(fs, dnod, &bw, 0, 0)) != WALK_END) // for all blocks in dir
  1308. {
  1309. - b = get_blk(fs, bk);
  1310. // for all dir entries in block
  1311. - for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
  1312. + for(d = get_dir(fs, bk, &dw); d; d = next_dir(&dw))
  1313. {
  1314. // if empty dir entry, large enough, use it
  1315. if((!d->d_inode) && (d->d_rec_len >= reclen))
  1316. {
  1317. d->d_inode = nod;
  1318. - node = get_nod(fs, nod);
  1319. + node = get_nod(fs, nod, &ni);
  1320. + dir_set_name(&dw, name, nlen);
  1321. + put_dir(&dw);
  1322. node->i_links_count++;
  1323. - d->d_name_len = nlen;
  1324. - strncpy(d->d_name, name, nlen);
  1325. - return;
  1326. + put_nod(ni);
  1327. + goto out;
  1328. }
  1329. // if entry with enough room (last one?), shrink it & use it
  1330. if(d->d_rec_len >= (sizeof(directory) + rndup(d->d_name_len, 4) + reclen))
  1331. {
  1332. - reclen = d->d_rec_len;
  1333. - d->d_rec_len = sizeof(directory) + rndup(d->d_name_len, 4);
  1334. - reclen -= d->d_rec_len;
  1335. - d = (directory*) (((int8*)d) + d->d_rec_len);
  1336. - d->d_rec_len = reclen;
  1337. - d->d_inode = nod;
  1338. - node = get_nod(fs, nod);
  1339. + d = shrink_dir(&dw, nod, name, nlen);
  1340. + put_dir(&dw);
  1341. + node = get_nod(fs, nod, &ni);
  1342. node->i_links_count++;
  1343. - d->d_name_len = nlen;
  1344. - strncpy(d->d_name, name, nlen);
  1345. - return;
  1346. + put_nod(ni);
  1347. + goto out;
  1348. }
  1349. }
  1350. + put_dir(&dw);
  1351. + lbw = bw;
  1352. }
  1353. // we found no free entry in the directory, so we add a block
  1354. - if(!(b = get_workblk()))
  1355. - error_msg_and_die("get_workblk() failed.");
  1356. - d = (directory*)b;
  1357. - d->d_inode = nod;
  1358. - node = get_nod(fs, nod);
  1359. + node = get_nod(fs, nod, &ni);
  1360. + d = new_dir(fs, nod, name, nlen, &dw);
  1361. node->i_links_count++;
  1362. - d->d_rec_len = BLOCKSIZE;
  1363. - d->d_name_len = nlen;
  1364. - strncpy(d->d_name, name, nlen);
  1365. - extend_blk(fs, dnod, b, 1);
  1366. - get_nod(fs, dnod)->i_size += BLOCKSIZE;
  1367. - free_workblk(b);
  1368. + put_nod(ni);
  1369. + next_dir(&dw); // Force the data into the buffer
  1370. +
  1371. + inode_pos_init(fs, &ipos, dnod, INODE_POS_EXTEND, &lbw);
  1372. + extend_inode_blk(fs, &ipos, dir_data(&dw), 1);
  1373. + inode_pos_finish(fs, &ipos);
  1374. +
  1375. + put_dir(&dw);
  1376. + pnode->i_size += BLOCKSIZE;
  1377. +out:
  1378. + put_nod(dni);
  1379. }
  1380. // find an entry in a directory
  1381. @@ -1321,11 +1948,13 @@
  1382. while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
  1383. {
  1384. directory *d;
  1385. - uint8 *b;
  1386. - b = get_blk(fs, bk);
  1387. - for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
  1388. - if(d->d_inode && (nlen == d->d_name_len) && !strncmp(d->d_name, name, nlen))
  1389. + dirwalker dw;
  1390. + for (d = get_dir(fs, bk, &dw); d; d=next_dir(&dw))
  1391. + if(d->d_inode && (nlen == d->d_name_len) && !strncmp(dir_name(&dw), name, nlen)) {
  1392. + put_dir(&dw);
  1393. return d->d_inode;
  1394. + }
  1395. + put_dir(&dw);
  1396. }
  1397. return 0;
  1398. }
  1399. @@ -1356,47 +1985,55 @@
  1400. return nod;
  1401. }
  1402. +// chmod an inode
  1403. +void
  1404. +chmod_fs(filesystem *fs, uint32 nod, uint16 mode, uint16 uid, uint16 gid)
  1405. +{
  1406. + inode *node;
  1407. + nod_info *ni;
  1408. + node = get_nod(fs, nod, &ni);
  1409. + node->i_mode = (node->i_mode & ~FM_IMASK) | (mode & FM_IMASK);
  1410. + node->i_uid = uid;
  1411. + node->i_gid = gid;
  1412. + put_nod(ni);
  1413. +}
  1414. +
  1415. // create a simple inode
  1416. static uint32
  1417. mknod_fs(filesystem *fs, uint32 parent_nod, const char *name, uint16 mode, uint16 uid, uint16 gid, uint8 major, uint8 minor, uint32 ctime, uint32 mtime)
  1418. {
  1419. uint32 nod;
  1420. inode *node;
  1421. - if((nod = find_dir(fs, parent_nod, name)))
  1422. - {
  1423. - node = get_nod(fs, nod);
  1424. - if((node->i_mode & FM_IFMT) != (mode & FM_IFMT))
  1425. - error_msg_and_die("node '%s' already exists and isn't of the same type", name);
  1426. - node->i_mode = mode;
  1427. - }
  1428. - else
  1429. + nod_info *ni;
  1430. + gd_info *gi;
  1431. +
  1432. + nod = alloc_nod(fs);
  1433. + node = get_nod(fs, nod, &ni);
  1434. + node->i_mode = mode;
  1435. + add2dir(fs, parent_nod, nod, name);
  1436. + switch(mode & FM_IFMT)
  1437. {
  1438. - nod = alloc_nod(fs);
  1439. - node = get_nod(fs, nod);
  1440. - node->i_mode = mode;
  1441. - add2dir(fs, parent_nod, nod, name);
  1442. - switch(mode & FM_IFMT)
  1443. - {
  1444. - case FM_IFLNK:
  1445. - mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO;
  1446. - break;
  1447. - case FM_IFBLK:
  1448. - case FM_IFCHR:
  1449. - ((uint8*)get_nod(fs, nod)->i_block)[0] = minor;
  1450. - ((uint8*)get_nod(fs, nod)->i_block)[1] = major;
  1451. - break;
  1452. - case FM_IFDIR:
  1453. - add2dir(fs, nod, nod, ".");
  1454. - add2dir(fs, nod, parent_nod, "..");
  1455. - fs->gd[GRP_GROUP_OF_INODE(fs,nod)].bg_used_dirs_count++;
  1456. - break;
  1457. - }
  1458. + case FM_IFLNK:
  1459. + mode = FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO;
  1460. + break;
  1461. + case FM_IFBLK:
  1462. + case FM_IFCHR:
  1463. + ((uint8*)node->i_block)[0] = minor;
  1464. + ((uint8*)node->i_block)[1] = major;
  1465. + break;
  1466. + case FM_IFDIR:
  1467. + add2dir(fs, nod, nod, ".");
  1468. + add2dir(fs, nod, parent_nod, "..");
  1469. + get_gd(fs,GRP_GROUP_OF_INODE(fs,nod),&gi)->bg_used_dirs_count++;
  1470. + put_gd(gi);
  1471. + break;
  1472. }
  1473. node->i_uid = uid;
  1474. node->i_gid = gid;
  1475. node->i_atime = mtime;
  1476. node->i_ctime = ctime;
  1477. node->i_mtime = mtime;
  1478. + put_nod(ni);
  1479. return nod;
  1480. }
  1481. @@ -1413,33 +2050,73 @@
  1482. 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)
  1483. {
  1484. uint32 nod = mknod_fs(fs, parent_nod, name, FM_IFLNK | FM_IRWXU | FM_IRWXG | FM_IRWXO, uid, gid, 0, 0, ctime, mtime);
  1485. - extend_blk(fs, nod, 0, - (int)get_nod(fs, nod)->i_blocks / INOBLK);
  1486. - get_nod(fs, nod)->i_size = size;
  1487. - if(size <= 4 * (EXT2_TIND_BLOCK+1))
  1488. - {
  1489. - strncpy((char*)get_nod(fs, nod)->i_block, (char*)b, size);
  1490. + nod_info *ni;
  1491. + inode *node = get_nod(fs, nod, &ni);
  1492. + inode_pos ipos;
  1493. +
  1494. + inode_pos_init(fs, &ipos, nod, INODE_POS_TRUNCATE, NULL);
  1495. + node->i_size = size;
  1496. + if(size < 4 * (EXT2_TIND_BLOCK+1))
  1497. + {
  1498. + strncpy((char*)node->i_block, (char*)b, size);
  1499. + ((char*)node->i_block)[size+1] = '\0';
  1500. + inode_pos_finish(fs, &ipos);
  1501. + put_nod(ni);
  1502. return nod;
  1503. }
  1504. - extend_blk(fs, nod, b, rndup(size, BLOCKSIZE) / BLOCKSIZE);
  1505. + extend_inode_blk(fs, &ipos, b, rndup(size, BLOCKSIZE) / BLOCKSIZE);
  1506. + inode_pos_finish(fs, &ipos);
  1507. + put_nod(ni);
  1508. return nod;
  1509. }
  1510. +static void
  1511. +fs_upgrade_rev1_largefile(filesystem *fs)
  1512. +{
  1513. + fs->sb->s_rev_level = 1;
  1514. + fs->sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
  1515. + fs->sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
  1516. +}
  1517. +
  1518. +#define COPY_BLOCKS 16
  1519. +#define CB_SIZE (COPY_BLOCKS * BLOCKSIZE)
  1520. +
  1521. // make a file from a FILE*
  1522. static uint32
  1523. -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)
  1524. +mkfile_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, FILE *f, uid_t uid, gid_t gid, uint32 ctime, uint32 mtime)
  1525. {
  1526. uint8 * b;
  1527. uint32 nod = mknod_fs(fs, parent_nod, name, mode|FM_IFREG, uid, gid, 0, 0, ctime, mtime);
  1528. - extend_blk(fs, nod, 0, - (int)get_nod(fs, nod)->i_blocks / INOBLK);
  1529. - get_nod(fs, nod)->i_size = size;
  1530. - if (size) {
  1531. - if(!(b = (uint8*)calloc(rndup(size, BLOCKSIZE), 1)))
  1532. - error_msg_and_die("not enough mem to read file '%s'", name);
  1533. - if(f)
  1534. - fread(b, size, 1, f); // FIXME: ugly. use mmap() ...
  1535. - extend_blk(fs, nod, b, rndup(size, BLOCKSIZE) / BLOCKSIZE);
  1536. - free(b);
  1537. - }
  1538. + nod_info *ni;
  1539. + inode *node = get_nod(fs, nod, &ni);
  1540. + off_t size = 0;
  1541. + size_t readbytes;
  1542. + inode_pos ipos;
  1543. + int fullsize;
  1544. +
  1545. + b = malloc(CB_SIZE);
  1546. + if (!b)
  1547. + error_msg_and_die("mkfile_fs: out of memory");
  1548. + inode_pos_init(fs, &ipos, nod, INODE_POS_TRUNCATE, NULL);
  1549. + readbytes = fread(b, 1, CB_SIZE, f);
  1550. + while (readbytes) {
  1551. + fullsize = rndup(readbytes, BLOCKSIZE);
  1552. + // Fill to end of block with zeros.
  1553. + memset(b + readbytes, 0, fullsize - readbytes);
  1554. + extend_inode_blk(fs, &ipos, b, fullsize / BLOCKSIZE);
  1555. + size += readbytes;
  1556. + readbytes = fread(b, 1, CB_SIZE, f);
  1557. + }
  1558. + if (size > 0x7fffffff) {
  1559. + if (fs->sb->s_rev_level < 1)
  1560. + fs_upgrade_rev1_largefile(fs);
  1561. + fs->sb->s_feature_ro_compat |= EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
  1562. + }
  1563. + node->i_dir_acl = size >> 32;
  1564. + node->i_size = size;
  1565. + inode_pos_finish(fs, &ipos);
  1566. + put_nod(ni);
  1567. + free(b);
  1568. return nod;
  1569. }
  1570. @@ -1591,13 +2268,24 @@
  1571. dname = malloc(len + 1);
  1572. for(i = start; i < count; i++)
  1573. {
  1574. + uint32 oldnod;
  1575. SNPRINTF(dname, len, "%s%lu", name, i);
  1576. - mknod_fs(fs, nod, dname, mode, uid, gid, major, minor + (i * increment - start), ctime, mtime);
  1577. + oldnod = find_dir(fs, nod, dname);
  1578. + if(oldnod)
  1579. + chmod_fs(fs, oldnod, mode, uid, gid);
  1580. + else
  1581. + mknod_fs(fs, nod, dname, mode, uid, gid, major, minor + (i * increment - start), ctime, mtime);
  1582. }
  1583. free(dname);
  1584. }
  1585. else
  1586. - mknod_fs(fs, nod, name, mode, uid, gid, major, minor, ctime, mtime);
  1587. + {
  1588. + uint32 oldnod = find_dir(fs, nod, name);
  1589. + if(oldnod)
  1590. + chmod_fs(fs, oldnod, mode, uid, gid);
  1591. + else
  1592. + mknod_fs(fs, nod, name, mode, uid, gid, major, minor, ctime, mtime);
  1593. + }
  1594. }
  1595. }
  1596. if (line)
  1597. @@ -1643,6 +2331,10 @@
  1598. switch(st.st_mode & S_IFMT)
  1599. {
  1600. case S_IFLNK:
  1601. + if((st.st_mode & S_IFMT) == S_IFREG || st.st_size >= 4 * (EXT2_TIND_BLOCK+1))
  1602. + stats->nblocks += (st.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
  1603. + stats->ninodes++;
  1604. + break;
  1605. case S_IFREG:
  1606. if((st.st_mode & S_IFMT) == S_IFREG || st.st_size > 4 * (EXT2_TIND_BLOCK+1))
  1607. stats->nblocks += (st.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
  1608. @@ -1657,19 +2349,33 @@
  1609. if(chdir(dent->d_name) < 0)
  1610. perror_msg_and_die(dent->d_name);
  1611. add2fs_from_dir(fs, this_nod, squash_uids, squash_perms, fs_timestamp, stats);
  1612. - chdir("..");
  1613. + if (chdir("..") == -1)
  1614. + perror_msg_and_die("..");
  1615. +
  1616. break;
  1617. default:
  1618. break;
  1619. }
  1620. else
  1621. {
  1622. + if((nod = find_dir(fs, this_nod, name)))
  1623. + {
  1624. + error_msg("ignoring duplicate entry %s", name);
  1625. + if(S_ISDIR(st.st_mode)) {
  1626. + if(chdir(dent->d_name) < 0)
  1627. + perror_msg_and_die(name);
  1628. + add2fs_from_dir(fs, nod, squash_uids, squash_perms, fs_timestamp, stats);
  1629. + if (chdir("..") == -1)
  1630. + perror_msg_and_die("..");
  1631. + }
  1632. + continue;
  1633. + }
  1634. save_nod = 0;
  1635. /* Check for hardlinks */
  1636. if (!S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode) && st.st_nlink > 1) {
  1637. - int32 hdlink = is_hardlink(st.st_ino);
  1638. + int32 hdlink = is_hardlink(fs, st.st_ino);
  1639. if (hdlink >= 0) {
  1640. - add2dir(fs, this_nod, hdlinks.hdl[hdlink].dst_nod, name);
  1641. + add2dir(fs, this_nod, fs->hdlinks.hdl[hdlink].dst_nod, name);
  1642. continue;
  1643. } else {
  1644. save_nod = 1;
  1645. @@ -1697,8 +2403,12 @@
  1646. free(lnk);
  1647. break;
  1648. case S_IFREG:
  1649. - fh = xfopen(dent->d_name, "rb");
  1650. - nod = mkfile_fs(fs, this_nod, name, mode, st.st_size, fh, uid, gid, ctime, mtime);
  1651. + fh = fopen(dent->d_name, "rb");
  1652. + if (!fh) {
  1653. + error_msg("Unable to open file %s", dent->d_name);
  1654. + break;
  1655. + }
  1656. + nod = mkfile_fs(fs, this_nod, name, mode, fh, uid, gid, ctime, mtime);
  1657. fclose(fh);
  1658. break;
  1659. case S_IFDIR:
  1660. @@ -1706,199 +2416,128 @@
  1661. if(chdir(dent->d_name) < 0)
  1662. perror_msg_and_die(name);
  1663. add2fs_from_dir(fs, nod, squash_uids, squash_perms, fs_timestamp, stats);
  1664. - chdir("..");
  1665. + if (chdir("..") == -1)
  1666. + perror_msg_and_die("..");
  1667. break;
  1668. default:
  1669. error_msg("ignoring entry %s", name);
  1670. }
  1671. if (save_nod) {
  1672. - if (hdlinks.count == hdlink_cnt) {
  1673. - if ((hdlinks.hdl =
  1674. - realloc (hdlinks.hdl, (hdlink_cnt + HDLINK_CNT) *
  1675. + if (fs->hdlinks.count == fs->hdlink_cnt) {
  1676. + if ((fs->hdlinks.hdl =
  1677. + realloc (fs->hdlinks.hdl, (fs->hdlink_cnt + HDLINK_CNT) *
  1678. sizeof (struct hdlink_s))) == NULL) {
  1679. error_msg_and_die("Not enough memory");
  1680. }
  1681. - hdlink_cnt += HDLINK_CNT;
  1682. + fs->hdlink_cnt += HDLINK_CNT;
  1683. }
  1684. - hdlinks.hdl[hdlinks.count].src_inode = st.st_ino;
  1685. - hdlinks.hdl[hdlinks.count].dst_nod = nod;
  1686. - hdlinks.count++;
  1687. + fs->hdlinks.hdl[fs->hdlinks.count].src_inode = st.st_ino;
  1688. + fs->hdlinks.hdl[fs->hdlinks.count].dst_nod = nod;
  1689. + fs->hdlinks.count++;
  1690. }
  1691. }
  1692. }
  1693. closedir(dh);
  1694. }
  1695. -// endianness swap of x-indirect blocks
  1696. +// Copy size blocks from src to dst, putting holes in the output
  1697. +// file (if possible) if the input block is all zeros.
  1698. +// Copy size blocks from src to dst, putting holes in the output
  1699. +// file (if possible) if the input block is all zeros.
  1700. static void
  1701. -swap_goodblocks(filesystem *fs, inode *nod)
  1702. +copy_file(filesystem *fs, FILE *dst, FILE *src, size_t size)
  1703. {
  1704. - uint32 i,j;
  1705. - int done=0;
  1706. - uint32 *b,*b2;
  1707. + uint8 *b;
  1708. - uint32 nblk = nod->i_blocks / INOBLK;
  1709. - if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
  1710. - for(i = 0; i <= EXT2_TIND_BLOCK; i++)
  1711. - nod->i_block[i] = swab32(nod->i_block[i]);
  1712. - if(nblk <= EXT2_IND_BLOCK)
  1713. - return;
  1714. - swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK]));
  1715. - if(nblk <= EXT2_DIND_BLOCK + BLOCKSIZE/4)
  1716. - return;
  1717. - /* Currently this will fail b'cos the number of blocks as stored
  1718. - in i_blocks also includes the indirection blocks (see
  1719. - walk_bw). But this function assumes that i_blocks only
  1720. - stores the count of data blocks ( Actually according to
  1721. - "Understanding the Linux Kernel" (Table 17-3 p502 1st Ed)
  1722. - i_blocks IS supposed to store the count of data blocks). so
  1723. - with a file of size 268K nblk would be 269.The above check
  1724. - will be false even though double indirection hasn't been
  1725. - started.This is benign as 0 means block 0 which has been
  1726. - zeroed out and therefore points back to itself from any offset
  1727. - */
  1728. - // FIXME: I have fixed that, but I have the feeling the rest of
  1729. - // ths function needs to be fixed for the same reasons - Xav
  1730. - assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
  1731. - for(i = 0; i < BLOCKSIZE/4; i++)
  1732. - if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + (BLOCKSIZE/4)*i )
  1733. - swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
  1734. - swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]));
  1735. - if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
  1736. - return;
  1737. - /* Adding support for triple indirection */
  1738. - b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
  1739. - for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
  1740. - b2 = (uint32*)get_blk(fs,b[i]);
  1741. - for(j=0; j<BLOCKSIZE/4;j++) {
  1742. - if (nblk > ( EXT2_IND_BLOCK + BLOCKSIZE/4 +
  1743. - (BLOCKSIZE/4)*(BLOCKSIZE/4) +
  1744. - i*(BLOCKSIZE/4)*(BLOCKSIZE/4) +
  1745. - j*(BLOCKSIZE/4)) )
  1746. - swap_block(get_blk(fs,b2[j]));
  1747. - else {
  1748. - done = 1;
  1749. - break;
  1750. - }
  1751. + b = malloc(BLOCKSIZE);
  1752. + if (!b)
  1753. + error_msg_and_die("copy_file: out of memory");
  1754. + if (fseek(src, 0, SEEK_SET))
  1755. + perror_msg_and_die("fseek");
  1756. + if (ftruncate(fileno(dst), 0))
  1757. + perror_msg_and_die("copy_file: ftruncate");
  1758. + while (size > 0) {
  1759. + if (fread(b, BLOCKSIZE, 1, src) != 1)
  1760. + perror_msg_and_die("copy failed on read");
  1761. + if ((dst != stdout) && fs->holes && is_blk_empty(b)) {
  1762. + /* Empty block, just skip it */
  1763. + if (fseek(dst, BLOCKSIZE, SEEK_CUR))
  1764. + perror_msg_and_die("fseek");
  1765. + } else {
  1766. + if (fwrite(b, BLOCKSIZE, 1, dst) != 1)
  1767. + perror_msg_and_die("copy failed on write");
  1768. }
  1769. - swap_block((uint8 *)b2);
  1770. + size--;
  1771. }
  1772. - swap_block((uint8 *)b);
  1773. - return;
  1774. + free(b);
  1775. }
  1776. -static void
  1777. -swap_badblocks(filesystem *fs, inode *nod)
  1778. +// Allocate a new filesystem structure, allocate internal memory,
  1779. +// and initialize the contents.
  1780. +static filesystem *
  1781. +alloc_fs(int swapit, char *fname, uint32 nbblocks, FILE *srcfile)
  1782. {
  1783. - uint32 i,j;
  1784. - int done=0;
  1785. - uint32 *b,*b2;
  1786. + filesystem *fs;
  1787. + struct stat srcstat, dststat;
  1788. - uint32 nblk = nod->i_blocks / INOBLK;
  1789. - if((nod->i_size && !nblk) || ((nod->i_mode & FM_IFBLK) == FM_IFBLK) || ((nod->i_mode & FM_IFCHR) == FM_IFCHR))
  1790. - for(i = 0; i <= EXT2_TIND_BLOCK; i++)
  1791. - nod->i_block[i] = swab32(nod->i_block[i]);
  1792. - if(nblk <= EXT2_IND_BLOCK)
  1793. - return;
  1794. - swap_block(get_blk(fs, nod->i_block[EXT2_IND_BLOCK]));
  1795. - if(nblk <= EXT2_DIND_BLOCK + BLOCKSIZE/4)
  1796. - return;
  1797. - /* See comment in swap_goodblocks */
  1798. - assert(nod->i_block[EXT2_DIND_BLOCK] != 0);
  1799. - swap_block(get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]));
  1800. - for(i = 0; i < BLOCKSIZE/4; i++)
  1801. - if(nblk > EXT2_IND_BLOCK + BLOCKSIZE/4 + (BLOCKSIZE/4)*i )
  1802. - swap_block(get_blk(fs, ((uint32*)get_blk(fs, nod->i_block[EXT2_DIND_BLOCK]))[i]));
  1803. - if(nblk <= EXT2_IND_BLOCK + BLOCKSIZE/4 + BLOCKSIZE/4 * BLOCKSIZE/4)
  1804. - return;
  1805. - /* Adding support for triple indirection */
  1806. - b = (uint32*)get_blk(fs,nod->i_block[EXT2_TIND_BLOCK]);
  1807. - swap_block((uint8 *)b);
  1808. - for(i=0;i < BLOCKSIZE/4 && !done ; i++) {
  1809. - b2 = (uint32*)get_blk(fs,b[i]);
  1810. - swap_block((uint8 *)b2);
  1811. - for(j=0; j<BLOCKSIZE/4;j++) {
  1812. - if (nblk > ( EXT2_IND_BLOCK + BLOCKSIZE/4 +
  1813. - (BLOCKSIZE/4)*(BLOCKSIZE/4) +
  1814. - i*(BLOCKSIZE/4)*(BLOCKSIZE/4) +
  1815. - j*(BLOCKSIZE/4)) )
  1816. - swap_block(get_blk(fs,b2[j]));
  1817. - else {
  1818. - done = 1;
  1819. - break;
  1820. - }
  1821. - }
  1822. - }
  1823. - return;
  1824. -}
  1825. + fs = malloc(sizeof(*fs));
  1826. + if (!fs)
  1827. + error_msg_and_die("not enough memory for filesystem");
  1828. + memset(fs, 0, sizeof(*fs));
  1829. + fs->swapit = swapit;
  1830. + cache_init(&fs->blks, MAX_FREE_CACHE_BLOCKS, blk_elem_val, blk_freed);
  1831. + cache_init(&fs->gds, MAX_FREE_CACHE_GDS, gd_elem_val, gd_freed);
  1832. + cache_init(&fs->blkmaps, MAX_FREE_CACHE_BLOCKMAPS,
  1833. + blkmap_elem_val, blkmap_freed);
  1834. + cache_init(&fs->inodes, MAX_FREE_CACHE_INODES,
  1835. + inode_elem_val, inode_freed);
  1836. + fs->hdlink_cnt = HDLINK_CNT;
  1837. + fs->hdlinks.hdl = calloc(sizeof(struct hdlink_s), fs->hdlink_cnt);
  1838. + if (!fs->hdlinks.hdl)
  1839. + error_msg_and_die("Not enough memory");
  1840. + fs->hdlinks.count = 0 ;
  1841. -// endianness swap of the whole filesystem
  1842. -static void
  1843. -swap_goodfs(filesystem *fs)
  1844. -{
  1845. - uint32 i;
  1846. - for(i = 1; i < fs->sb.s_inodes_count; i++)
  1847. - {
  1848. - inode *nod = get_nod(fs, i);
  1849. - if(nod->i_mode & FM_IFDIR)
  1850. - {
  1851. - blockwalker bw;
  1852. - uint32 bk;
  1853. - init_bw(&bw);
  1854. - while((bk = walk_bw(fs, i, &bw, 0, 0)) != WALK_END)
  1855. - {
  1856. - directory *d;
  1857. - uint8 *b;
  1858. - b = get_blk(fs, bk);
  1859. - for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + swab16(d->d_rec_len)))
  1860. - swap_dir(d);
  1861. - }
  1862. - }
  1863. - swap_goodblocks(fs, nod);
  1864. - swap_nod(nod);
  1865. - }
  1866. - for(i=0;i<GRP_NBGROUPS(fs);i++)
  1867. - swap_gd(&(fs->gd[i]));
  1868. - swap_sb(&fs->sb);
  1869. + if (strcmp(fname, "-") == 0)
  1870. + fs->f = tmpfile();
  1871. + else if (srcfile) {
  1872. + if (fstat(fileno(srcfile), &srcstat))
  1873. + perror_msg_and_die("fstat srcfile");
  1874. + if (stat(fname, &dststat) == 0
  1875. + && srcstat.st_ino == dststat.st_ino
  1876. + && srcstat.st_dev == dststat.st_dev)
  1877. + {
  1878. + // source and destination are the same file, don't
  1879. + // truncate or copy, just use the file.
  1880. + fs->f = fopen(fname, "r+b");
  1881. + } else {
  1882. + fs->f = fopen(fname, "w+b");
  1883. + if (fs->f)
  1884. + copy_file(fs, fs->f, srcfile, nbblocks);
  1885. + }
  1886. + } else
  1887. + fs->f = fopen(fname, "w+b");
  1888. + if (!fs->f)
  1889. + perror_msg_and_die("opening %s", fname);
  1890. + return fs;
  1891. }
  1892. +/* Make sure the output file is the right size */
  1893. static void
  1894. -swap_badfs(filesystem *fs)
  1895. +set_file_size(filesystem *fs)
  1896. {
  1897. - uint32 i;
  1898. - swap_sb(&fs->sb);
  1899. - for(i=0;i<GRP_NBGROUPS(fs);i++)
  1900. - swap_gd(&(fs->gd[i]));
  1901. - for(i = 1; i < fs->sb.s_inodes_count; i++)
  1902. - {
  1903. - inode *nod = get_nod(fs, i);
  1904. - swap_nod(nod);
  1905. - swap_badblocks(fs, nod);
  1906. - if(nod->i_mode & FM_IFDIR)
  1907. - {
  1908. - blockwalker bw;
  1909. - uint32 bk;
  1910. - init_bw(&bw);
  1911. - while((bk = walk_bw(fs, i, &bw, 0, 0)) != WALK_END)
  1912. - {
  1913. - directory *d;
  1914. - uint8 *b;
  1915. - b = get_blk(fs, bk);
  1916. - for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
  1917. - swap_dir(d);
  1918. - }
  1919. - }
  1920. - }
  1921. + if (ftruncate(fileno(fs->f),
  1922. + ((off_t) fs->sb->s_blocks_count) * BLOCKSIZE))
  1923. + perror_msg_and_die("set_file_size: ftruncate");
  1924. }
  1925. // initialize an empty filesystem
  1926. static filesystem *
  1927. -init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes, uint32 fs_timestamp)
  1928. +init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes,
  1929. + uint32 fs_timestamp, uint32 creator_os, int swapit, char *fname)
  1930. {
  1931. uint32 i;
  1932. filesystem *fs;
  1933. - directory *d;
  1934. - uint8 * b;
  1935. + dirwalker dw;
  1936. uint32 nod, first_block;
  1937. uint32 nbgroups,nbinodes_per_group,overhead_per_group,free_blocks,
  1938. free_blocks_per_group,nbblocks_per_group,min_nbgroups;
  1939. @@ -1906,6 +2545,11 @@
  1940. uint32 j;
  1941. uint8 *bbm,*ibm;
  1942. inode *itab0;
  1943. + blk_info *bi;
  1944. + nod_info *ni;
  1945. + groupdescriptor *gd;
  1946. + gd_info *gi;
  1947. + inode_pos ipos;
  1948. if(nbresrvd < 0)
  1949. error_msg_and_die("reserved blocks value is invalid. Note: options have changed, see --help or the man page.");
  1950. @@ -1919,10 +2563,14 @@
  1951. */
  1952. min_nbgroups = (nbinodes + INODES_PER_GROUP - 1) / INODES_PER_GROUP;
  1953. + /* On filesystems with 1k block size, the bootloader area uses a full
  1954. + * block. For 2048 and up, the superblock can be fitted into block 0.
  1955. + */
  1956. + first_block = (BLOCKSIZE == 1024);
  1957. +
  1958. /* nbblocks is the total number of blocks in the filesystem.
  1959. * a block group can have no more than 8192 blocks.
  1960. */
  1961. - first_block = (BLOCKSIZE == 1024);
  1962. nbgroups = (nbblocks - first_block + BLOCKS_PER_GROUP - 1) / BLOCKS_PER_GROUP;
  1963. if(nbgroups < min_nbgroups) nbgroups = min_nbgroups;
  1964. nbblocks_per_group = rndup((nbblocks - first_block + nbgroups - 1)/nbgroups, 8);
  1965. @@ -1934,51 +2582,59 @@
  1966. gdsz = rndup(nbgroups*sizeof(groupdescriptor),BLOCKSIZE)/BLOCKSIZE;
  1967. itblsz = nbinodes_per_group * sizeof(inode)/BLOCKSIZE;
  1968. overhead_per_group = 3 /*sb,bbm,ibm*/ + gdsz + itblsz;
  1969. - if((uint32)nbblocks - 1 < overhead_per_group * nbgroups)
  1970. - error_msg_and_die("too much overhead, try fewer inodes or more blocks. Note: options have changed, see --help or the man page.");
  1971. - free_blocks = nbblocks - overhead_per_group*nbgroups - 1 /*boot block*/;
  1972. + free_blocks = nbblocks - overhead_per_group*nbgroups - first_block;
  1973. free_blocks_per_group = nbblocks_per_group - overhead_per_group;
  1974. + if(free_blocks < 0)
  1975. + error_msg_and_die("too much overhead, try fewer inodes or more blocks. Note: options have changed, see --help or the man page.");
  1976. - if(!(fs = (filesystem*)calloc(nbblocks, BLOCKSIZE)))
  1977. - error_msg_and_die("not enough memory for filesystem");
  1978. + fs = alloc_fs(swapit, fname, nbblocks, NULL);
  1979. + fs->sb = calloc(1, SUPERBLOCK_SIZE);
  1980. + if (!fs->sb)
  1981. + error_msg_and_die("error allocating header memory");
  1982. // create the superblock for an empty filesystem
  1983. - fs->sb.s_inodes_count = nbinodes_per_group * nbgroups;
  1984. - fs->sb.s_blocks_count = nbblocks;
  1985. - fs->sb.s_r_blocks_count = nbresrvd;
  1986. - fs->sb.s_free_blocks_count = free_blocks;
  1987. - fs->sb.s_free_inodes_count = fs->sb.s_inodes_count - EXT2_FIRST_INO + 1;
  1988. - fs->sb.s_first_data_block = first_block;
  1989. - fs->sb.s_log_block_size = BLOCKSIZE >> 11;
  1990. - fs->sb.s_log_frag_size = BLOCKSIZE >> 11;
  1991. - fs->sb.s_blocks_per_group = nbblocks_per_group;
  1992. - fs->sb.s_frags_per_group = nbblocks_per_group;
  1993. - fs->sb.s_inodes_per_group = nbinodes_per_group;
  1994. - fs->sb.s_wtime = fs_timestamp;
  1995. - fs->sb.s_magic = EXT2_MAGIC_NUMBER;
  1996. - fs->sb.s_lastcheck = fs_timestamp;
  1997. + fs->sb->s_inodes_count = nbinodes_per_group * nbgroups;
  1998. + fs->sb->s_blocks_count = nbblocks;
  1999. + fs->sb->s_r_blocks_count = nbresrvd;
  2000. + fs->sb->s_free_blocks_count = free_blocks;
  2001. + fs->sb->s_free_inodes_count = fs->sb->s_inodes_count - EXT2_FIRST_INO + 1;
  2002. + fs->sb->s_first_data_block = first_block;
  2003. + fs->sb->s_log_block_size = BLOCKSIZE >> 11;
  2004. + fs->sb->s_log_frag_size = BLOCKSIZE >> 11;
  2005. + fs->sb->s_blocks_per_group = nbblocks_per_group;
  2006. + fs->sb->s_frags_per_group = nbblocks_per_group;
  2007. + fs->sb->s_inodes_per_group = nbinodes_per_group;
  2008. + fs->sb->s_wtime = fs_timestamp;
  2009. + fs->sb->s_magic = EXT2_MAGIC_NUMBER;
  2010. + fs->sb->s_lastcheck = fs_timestamp;
  2011. + fs->sb->s_creator_os = creator_os;
  2012. +
  2013. + set_file_size(fs);
  2014. // set up groupdescriptors
  2015. - for(i=0, bbmpos=gdsz+2, ibmpos=bbmpos+1, itblpos=ibmpos+1;
  2016. + for(i=0, bbmpos=first_block+1+gdsz, ibmpos=bbmpos+1, itblpos=ibmpos+1;
  2017. i<nbgroups;
  2018. i++, bbmpos+=nbblocks_per_group, ibmpos+=nbblocks_per_group, itblpos+=nbblocks_per_group)
  2019. {
  2020. + gd = get_gd(fs, i, &gi);
  2021. +
  2022. if(free_blocks > free_blocks_per_group) {
  2023. - fs->gd[i].bg_free_blocks_count = free_blocks_per_group;
  2024. + gd->bg_free_blocks_count = free_blocks_per_group;
  2025. free_blocks -= free_blocks_per_group;
  2026. } else {
  2027. - fs->gd[i].bg_free_blocks_count = free_blocks;
  2028. + gd->bg_free_blocks_count = free_blocks;
  2029. free_blocks = 0; // this is the last block group
  2030. }
  2031. if(i)
  2032. - fs->gd[i].bg_free_inodes_count = nbinodes_per_group;
  2033. + gd->bg_free_inodes_count = nbinodes_per_group;
  2034. else
  2035. - fs->gd[i].bg_free_inodes_count = nbinodes_per_group -
  2036. + gd->bg_free_inodes_count = nbinodes_per_group -
  2037. EXT2_FIRST_INO + 2;
  2038. - fs->gd[i].bg_used_dirs_count = 0;
  2039. - fs->gd[i].bg_block_bitmap = bbmpos;
  2040. - fs->gd[i].bg_inode_bitmap = ibmpos;
  2041. - fs->gd[i].bg_inode_table = itblpos;
  2042. + gd->bg_used_dirs_count = 0;
  2043. + gd->bg_block_bitmap = bbmpos;
  2044. + gd->bg_inode_bitmap = ibmpos;
  2045. + gd->bg_inode_table = itblpos;
  2046. + put_gd(gi);
  2047. }
  2048. /* Mark non-filesystem blocks and inodes as allocated */
  2049. @@ -1984,110 +2640,143 @@
  2050. /* Mark non-filesystem blocks and inodes as allocated */
  2051. /* Mark system blocks and inodes as allocated */
  2052. for(i = 0; i<nbgroups;i++) {
  2053. -
  2054. /* Block bitmap */
  2055. - bbm = get_blk(fs,fs->gd[i].bg_block_bitmap);
  2056. + gd = get_gd(fs, i, &gi);
  2057. + bbm = GRP_GET_GROUP_BBM(fs, gd, &bi);
  2058. //non-filesystem blocks
  2059. - for(j = fs->gd[i].bg_free_blocks_count
  2060. + for(j = gd->bg_free_blocks_count
  2061. + overhead_per_group + 1; j <= BLOCKSIZE * 8; j++)
  2062. allocate(bbm, j);
  2063. //system blocks
  2064. for(j = 1; j <= overhead_per_group; j++)
  2065. allocate(bbm, j);
  2066. -
  2067. + GRP_PUT_GROUP_BBM(bi);
  2068. +
  2069. /* Inode bitmap */
  2070. - ibm = get_blk(fs,fs->gd[i].bg_inode_bitmap);
  2071. + ibm = GRP_GET_GROUP_IBM(fs, gd, &bi);
  2072. //non-filesystem inodes
  2073. - for(j = fs->sb.s_inodes_per_group+1; j <= BLOCKSIZE * 8; j++)
  2074. + for(j = fs->sb->s_inodes_per_group+1; j <= BLOCKSIZE * 8; j++)
  2075. allocate(ibm, j);
  2076. //system inodes
  2077. if(i == 0)
  2078. for(j = 1; j < EXT2_FIRST_INO; j++)
  2079. allocate(ibm, j);
  2080. + GRP_PUT_GROUP_IBM(bi);
  2081. + put_gd(gi);
  2082. }
  2083. // make root inode and directory
  2084. /* We have groups now. Add the root filesystem in group 0 */
  2085. /* Also increment the directory count for group 0 */
  2086. - fs->gd[0].bg_free_inodes_count--;
  2087. - fs->gd[0].bg_used_dirs_count = 1;
  2088. - itab0 = (inode *)get_blk(fs,fs->gd[0].bg_inode_table);
  2089. - itab0[EXT2_ROOT_INO-1].i_mode = FM_IFDIR | FM_IRWXU | FM_IRGRP | FM_IROTH | FM_IXGRP | FM_IXOTH;
  2090. - itab0[EXT2_ROOT_INO-1].i_ctime = fs_timestamp;
  2091. - itab0[EXT2_ROOT_INO-1].i_mtime = fs_timestamp;
  2092. - itab0[EXT2_ROOT_INO-1].i_atime = fs_timestamp;
  2093. - itab0[EXT2_ROOT_INO-1].i_size = BLOCKSIZE;
  2094. - itab0[EXT2_ROOT_INO-1].i_links_count = 2;
  2095. -
  2096. - if(!(b = get_workblk()))
  2097. - error_msg_and_die("get_workblk() failed.");
  2098. - d = (directory*)b;
  2099. - d->d_inode = EXT2_ROOT_INO;
  2100. - d->d_rec_len = sizeof(directory)+4;
  2101. - d->d_name_len = 1;
  2102. - strcpy(d->d_name, ".");
  2103. - d = (directory*)(b + d->d_rec_len);
  2104. - d->d_inode = EXT2_ROOT_INO;
  2105. - d->d_rec_len = BLOCKSIZE - (sizeof(directory)+4);
  2106. - d->d_name_len = 2;
  2107. - strcpy(d->d_name, "..");
  2108. - extend_blk(fs, EXT2_ROOT_INO, b, 1);
  2109. + gd = get_gd(fs, 0, &gi);
  2110. + gd->bg_free_inodes_count--;
  2111. + gd->bg_used_dirs_count = 1;
  2112. + put_gd(gi);
  2113. + itab0 = get_nod(fs, EXT2_ROOT_INO, &ni);
  2114. + itab0->i_mode = FM_IFDIR | FM_IRWXU | FM_IRGRP | FM_IROTH | FM_IXGRP | FM_IXOTH;
  2115. + itab0->i_ctime = fs_timestamp;
  2116. + itab0->i_mtime = fs_timestamp;
  2117. + itab0->i_atime = fs_timestamp;
  2118. + itab0->i_size = BLOCKSIZE;
  2119. + itab0->i_links_count = 2;
  2120. + put_nod(ni);
  2121. +
  2122. + new_dir(fs, EXT2_ROOT_INO, ".", 1, &dw);
  2123. + shrink_dir(&dw, EXT2_ROOT_INO, "..", 2);
  2124. + next_dir(&dw); // Force the data into the buffer
  2125. + inode_pos_init(fs, &ipos, EXT2_ROOT_INO, INODE_POS_EXTEND, NULL);
  2126. + extend_inode_blk(fs, &ipos, dir_data(&dw), 1);
  2127. + inode_pos_finish(fs, &ipos);
  2128. + put_dir(&dw);
  2129. - // make lost+found directory and reserve blocks
  2130. - if(fs->sb.s_r_blocks_count)
  2131. + // make lost+found directory
  2132. + if(fs->sb->s_r_blocks_count)
  2133. {
  2134. - nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", FM_IRWXU, 0, 0, fs_timestamp, fs_timestamp);
  2135. + inode *node;
  2136. + uint8 *b;
  2137. +
  2138. + nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", FM_IRWXU,
  2139. + 0, 0, fs_timestamp, fs_timestamp);
  2140. + b = get_workblk();
  2141. memset(b, 0, BLOCKSIZE);
  2142. ((directory*)b)->d_rec_len = BLOCKSIZE;
  2143. - /* We run into problems with e2fsck if directory lost+found grows
  2144. - * bigger than this. Need to find out why this happens - sundar
  2145. - */
  2146. - if (fs->sb.s_r_blocks_count > fs->sb.s_blocks_count * MAX_RESERVED_BLOCKS )
  2147. - fs->sb.s_r_blocks_count = fs->sb.s_blocks_count * MAX_RESERVED_BLOCKS;
  2148. - for(i = 1; i < fs->sb.s_r_blocks_count; i++)
  2149. - extend_blk(fs, nod, b, 1);
  2150. - get_nod(fs, nod)->i_size = fs->sb.s_r_blocks_count * BLOCKSIZE;
  2151. + inode_pos_init(fs, &ipos, nod, INODE_POS_EXTEND, NULL);
  2152. + // It is always 16 blocks to start out with
  2153. + for(i = 1; i < 16; i++)
  2154. + extend_inode_blk(fs, &ipos, b, 1);
  2155. + inode_pos_finish(fs, &ipos);
  2156. + free_workblk(b);
  2157. + node = get_nod(fs, nod, &ni);
  2158. + node->i_size = 16 * BLOCKSIZE;
  2159. + put_nod(ni);
  2160. }
  2161. - free_workblk(b);
  2162. // administrative info
  2163. - fs->sb.s_state = 1;
  2164. - fs->sb.s_max_mnt_count = 20;
  2165. + fs->sb->s_state = 1;
  2166. + fs->sb->s_max_mnt_count = 20;
  2167. // options for me
  2168. - if(holes)
  2169. - fs->sb.s_reserved[200] |= OP_HOLES;
  2170. + fs->holes = holes;
  2171. return fs;
  2172. }
  2173. // loads a filesystem from disk
  2174. static filesystem *
  2175. -load_fs(FILE * fh, int swapit)
  2176. +load_fs(FILE *fh, int swapit, char *fname)
  2177. {
  2178. - size_t fssize;
  2179. + off_t fssize;
  2180. filesystem *fs;
  2181. - if((fseek(fh, 0, SEEK_END) < 0) || ((ssize_t)(fssize = ftell(fh)) == -1))
  2182. +
  2183. + if((fseek(fh, 0, SEEK_END) < 0) || ((fssize = ftello(fh)) == -1))
  2184. perror_msg_and_die("input filesystem image");
  2185. rewind(fh);
  2186. - fssize = (fssize + BLOCKSIZE - 1) / BLOCKSIZE;
  2187. + if ((fssize % BLOCKSIZE) != 0)
  2188. + error_msg_and_die("Input file not a multiple of block size");
  2189. + fssize /= BLOCKSIZE;
  2190. if(fssize < 16) // totally arbitrary
  2191. error_msg_and_die("too small filesystem");
  2192. - if(!(fs = (filesystem*)calloc(fssize, BLOCKSIZE)))
  2193. - error_msg_and_die("not enough memory for filesystem");
  2194. - if(fread(fs, BLOCKSIZE, fssize, fh) != fssize)
  2195. - perror_msg_and_die("input filesystem image");
  2196. + fs = alloc_fs(swapit, fname, fssize, fh);
  2197. +
  2198. + /* Read and check the superblock, then read the superblock
  2199. + * and all the group descriptors */
  2200. + fs->sb = malloc(SUPERBLOCK_SIZE);
  2201. + if (!fs->sb)
  2202. + error_msg_and_die("error allocating header memory");
  2203. + if (fseek(fs->f, SUPERBLOCK_OFFSET, SEEK_SET))
  2204. + perror_msg_and_die("fseek");
  2205. + if (fread(fs->sb, SUPERBLOCK_SIZE, 1, fs->f) != 1)
  2206. + perror_msg_and_die("fread filesystem image superblock");
  2207. if(swapit)
  2208. - swap_badfs(fs);
  2209. - if(fs->sb.s_rev_level || (fs->sb.s_magic != EXT2_MAGIC_NUMBER))
  2210. + swap_sb(fs->sb);
  2211. +
  2212. + if((fs->sb->s_rev_level > 1) || (fs->sb->s_magic != EXT2_MAGIC_NUMBER))
  2213. error_msg_and_die("not a suitable ext2 filesystem");
  2214. + if (fs->sb->s_rev_level > 0) {
  2215. + if (fs->sb->s_first_ino != EXT2_GOOD_OLD_FIRST_INO)
  2216. + error_msg_and_die("First inode incompatible");
  2217. + if (fs->sb->s_inode_size != EXT2_GOOD_OLD_INODE_SIZE)
  2218. + error_msg_and_die("inode size incompatible");
  2219. + if (fs->sb->s_feature_compat)
  2220. + error_msg_and_die("Unsupported compat features");
  2221. + if (fs->sb->s_feature_incompat)
  2222. + error_msg_and_die("Unsupported incompat features");
  2223. + if (fs->sb->s_feature_ro_compat
  2224. + & ~EXT2_FEATURE_RO_COMPAT_LARGE_FILE)
  2225. + error_msg_and_die("Unsupported ro compat features");
  2226. + }
  2227. +
  2228. + set_file_size(fs);
  2229. return fs;
  2230. }
  2231. static void
  2232. free_fs(filesystem *fs)
  2233. {
  2234. + free(fs->hdlinks.hdl);
  2235. + fclose(fs->f);
  2236. + free(fs->sb);
  2237. free(fs);
  2238. }
  2239. @@ -2123,16 +2812,23 @@
  2240. {
  2241. blockwalker bw;
  2242. uint32 bk;
  2243. - int32 fsize = get_nod(fs, nod)->i_size;
  2244. + nod_info *ni;
  2245. + inode *node = get_nod(fs, nod, &ni);
  2246. + int32 fsize = node->i_size;
  2247. + blk_info *bi;
  2248. +
  2249. init_bw(&bw);
  2250. while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
  2251. {
  2252. if(fsize <= 0)
  2253. error_msg_and_die("wrong size while saving inode %d", nod);
  2254. - if(fwrite(get_blk(fs, bk), (fsize > BLOCKSIZE) ? BLOCKSIZE : fsize, 1, f) != 1)
  2255. + if(fwrite(get_blk(fs, bk, &bi),
  2256. + (fsize > BLOCKSIZE) ? BLOCKSIZE : fsize, 1, f) != 1)
  2257. error_msg_and_die("error while saving inode %d", nod);
  2258. + put_blk(bi);
  2259. fsize -= BLOCKSIZE;
  2260. }
  2261. + put_nod(ni);
  2262. }
  2263. @@ -2141,8 +2837,11 @@
  2264. print_dev(filesystem *fs, uint32 nod)
  2265. {
  2266. int minor, major;
  2267. - minor = ((uint8*)get_nod(fs, nod)->i_block)[0];
  2268. - major = ((uint8*)get_nod(fs, nod)->i_block)[1];
  2269. + nod_info *ni;
  2270. + inode *node = get_nod(fs, nod, &ni);
  2271. + minor = ((uint8*)node->i_block)[0];
  2272. + major = ((uint8*)node->i_block)[1];
  2273. + put_nod(ni);
  2274. printf("major: %d, minor: %d\n", major, minor);
  2275. }
  2276. @@ -2157,17 +2856,15 @@
  2277. while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END)
  2278. {
  2279. directory *d;
  2280. - uint8 *b;
  2281. - b = get_blk(fs, bk);
  2282. - for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len))
  2283. + dirwalker dw;
  2284. + for (d = get_dir(fs, bk, &dw); d; d = next_dir(&dw))
  2285. if(d->d_inode)
  2286. {
  2287. - int i;
  2288. printf("entry '");
  2289. - for(i = 0; i < d->d_name_len; i++)
  2290. - putchar(d->d_name[i]);
  2291. + fwrite(dir_name(&dw), 1, d->d_name_len, stdout);
  2292. printf("' (inode %d): rec_len: %d (name_len: %d)\n", d->d_inode, d->d_rec_len, d->d_name_len);
  2293. }
  2294. + put_dir(&dw);
  2295. }
  2296. }
  2297. @@ -2175,14 +2872,18 @@
  2298. static void
  2299. print_link(filesystem *fs, uint32 nod)
  2300. {
  2301. - if(!get_nod(fs, nod)->i_blocks)
  2302. - printf("links to '%s'\n", (char*)get_nod(fs, nod)->i_block);
  2303. + nod_info *ni;
  2304. + inode *node = get_nod(fs, nod, &ni);
  2305. +
  2306. + if(!node->i_blocks)
  2307. + printf("links to '%s'\n", (char*)node->i_block);
  2308. else
  2309. {
  2310. printf("links to '");
  2311. write_blocks(fs, nod, stdout);
  2312. printf("'\n");
  2313. }
  2314. + put_nod(ni);
  2315. }
  2316. // make a ls-like printout of permissions
  2317. @@ -2251,8 +2952,13 @@
  2318. {
  2319. char *s;
  2320. char perms[11];
  2321. - if(!get_nod(fs, nod)->i_mode)
  2322. - return;
  2323. + nod_info *ni;
  2324. + inode *node = get_nod(fs, nod, &ni);
  2325. + blk_info *bi;
  2326. + gd_info *gi;
  2327. +
  2328. + if(!node->i_mode)
  2329. + goto out;
  2330. switch(nod)
  2331. {
  2332. case EXT2_BAD_INO:
  2333. @@ -2274,15 +2980,18 @@
  2334. default:
  2335. s = (nod >= EXT2_FIRST_INO) ? "normal" : "unknown reserved";
  2336. }
  2337. - printf("inode %d (%s, %d links): ", nod, s, get_nod(fs, nod)->i_links_count);
  2338. - if(!allocated(GRP_GET_INODE_BITMAP(fs,nod), GRP_IBM_OFFSET(fs,nod)))
  2339. + printf("inode %d (%s, %d links): ", nod, s, node->i_links_count);
  2340. + if(!allocated(GRP_GET_INODE_BITMAP(fs,nod,&bi,&gi), GRP_IBM_OFFSET(fs,nod)))
  2341. {
  2342. + GRP_PUT_INODE_BITMAP(bi,gi);
  2343. printf("unallocated\n");
  2344. - return;
  2345. + goto out;
  2346. }
  2347. - make_perms(get_nod(fs, nod)->i_mode, perms);
  2348. - 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));
  2349. - switch(get_nod(fs, nod)->i_mode & FM_IFMT)
  2350. + GRP_PUT_INODE_BITMAP(bi,gi);
  2351. + make_perms(node->i_mode, perms);
  2352. + printf("%s, size: %d byte%s (%d block%s)\n", perms,
  2353. + plural(node->i_size), plural(node->i_blocks / INOBLK));
  2354. + switch(node->i_mode & FM_IFMT)
  2355. {
  2356. case FM_IFSOCK:
  2357. list_blocks(fs, nod);
  2358. @@ -2310,6 +3019,8 @@
  2359. list_blocks(fs, nod);
  2360. }
  2361. printf("Done with inode %d\n",nod);
  2362. +out:
  2363. + put_nod(ni);
  2364. }
  2365. // describes various fields in a filesystem
  2366. @@ -2317,49 +3028,65 @@
  2367. print_fs(filesystem *fs)
  2368. {
  2369. uint32 i;
  2370. + blk_info *bi;
  2371. + groupdescriptor *gd;
  2372. + gd_info *gi;
  2373. uint8 *ibm;
  2374. printf("%d blocks (%d free, %d reserved), first data block: %d\n",
  2375. - fs->sb.s_blocks_count, fs->sb.s_free_blocks_count,
  2376. - fs->sb.s_r_blocks_count, fs->sb.s_first_data_block);
  2377. - printf("%d inodes (%d free)\n", fs->sb.s_inodes_count,
  2378. - fs->sb.s_free_inodes_count);
  2379. + fs->sb->s_blocks_count, fs->sb->s_free_blocks_count,
  2380. + fs->sb->s_r_blocks_count, fs->sb->s_first_data_block);
  2381. + printf("%d inodes (%d free)\n", fs->sb->s_inodes_count,
  2382. + fs->sb->s_free_inodes_count);
  2383. printf("block size = %d, frag size = %d\n",
  2384. - fs->sb.s_log_block_size ? (fs->sb.s_log_block_size << 11) : 1024,
  2385. - fs->sb.s_log_frag_size ? (fs->sb.s_log_frag_size << 11) : 1024);
  2386. + fs->sb->s_log_block_size ? (fs->sb->s_log_block_size << 11) : 1024,
  2387. + fs->sb->s_log_frag_size ? (fs->sb->s_log_frag_size << 11) : 1024);
  2388. printf("number of groups: %d\n",GRP_NBGROUPS(fs));
  2389. printf("%d blocks per group,%d frags per group,%d inodes per group\n",
  2390. - fs->sb.s_blocks_per_group, fs->sb.s_frags_per_group,
  2391. - fs->sb.s_inodes_per_group);
  2392. + fs->sb->s_blocks_per_group, fs->sb->s_frags_per_group,
  2393. + fs->sb->s_inodes_per_group);
  2394. printf("Size of inode table: %d blocks\n",
  2395. - (int)(fs->sb.s_inodes_per_group * sizeof(inode) / BLOCKSIZE));
  2396. + (int)(fs->sb->s_inodes_per_group * sizeof(inode) / BLOCKSIZE));
  2397. for (i = 0; i < GRP_NBGROUPS(fs); i++) {
  2398. printf("Group No: %d\n", i+1);
  2399. + gd = get_gd(fs, i, &gi);
  2400. printf("block bitmap: block %d,inode bitmap: block %d, inode table: block %d\n",
  2401. - fs->gd[i].bg_block_bitmap, fs->gd[i].bg_inode_bitmap,
  2402. - fs->gd[i].bg_inode_table);
  2403. + gd->bg_block_bitmap,
  2404. + gd->bg_inode_bitmap,
  2405. + gd->bg_inode_table);
  2406. printf("block bitmap allocation:\n");
  2407. - print_bm(GRP_GET_GROUP_BBM(fs, i),fs->sb.s_blocks_per_group);
  2408. + print_bm(GRP_GET_GROUP_BBM(fs, gd, &bi),fs->sb->s_blocks_per_group);
  2409. + GRP_PUT_GROUP_BBM(bi);
  2410. printf("inode bitmap allocation:\n");
  2411. - ibm = GRP_GET_GROUP_IBM(fs, i);
  2412. - print_bm(ibm, fs->sb.s_inodes_per_group);
  2413. - for (i = 1; i <= fs->sb.s_inodes_per_group; i++)
  2414. + ibm = GRP_GET_GROUP_IBM(fs, gd, &bi);
  2415. + print_bm(ibm, fs->sb->s_inodes_per_group);
  2416. + for (i = 1; i <= fs->sb->s_inodes_per_group; i++)
  2417. if (allocated(ibm, i))
  2418. print_inode(fs, i);
  2419. + GRP_PUT_GROUP_IBM(bi);
  2420. + put_gd(gi);
  2421. }
  2422. }
  2423. static void
  2424. -dump_fs(filesystem *fs, FILE * fh, int swapit)
  2425. +finish_fs(filesystem *fs)
  2426. {
  2427. - uint32 nbblocks = fs->sb.s_blocks_count;
  2428. - fs->sb.s_reserved[200] = 0;
  2429. - if(swapit)
  2430. - swap_goodfs(fs);
  2431. - if(fwrite(fs, BLOCKSIZE, nbblocks, fh) < nbblocks)
  2432. - perror_msg_and_die("output filesystem image");
  2433. - if(swapit)
  2434. - swap_badfs(fs);
  2435. + if (cache_flush(&fs->inodes))
  2436. + error_msg_and_die("entry mismatch on inode cache flush");
  2437. + if (cache_flush(&fs->blkmaps))
  2438. + error_msg_and_die("entry mismatch on blockmap cache flush");
  2439. + if (cache_flush(&fs->gds))
  2440. + error_msg_and_die("entry mismatch on gd cache flush");
  2441. + if (cache_flush(&fs->blks))
  2442. + error_msg_and_die("entry mismatch on block cache flush");
  2443. + if(fs->swapit)
  2444. + swap_sb(fs->sb);
  2445. + if (fseek(fs->f, SUPERBLOCK_OFFSET, SEEK_SET))
  2446. + perror_msg_and_die("fseek");
  2447. + if(fwrite(fs->sb, SUPERBLOCK_SIZE, 1, fs->f) != 1)
  2448. + perror_msg_and_die("output filesystem superblock");
  2449. + if(fs->swapit)
  2450. + swap_sb(fs->sb);
  2451. }
  2452. static void
  2453. @@ -2419,10 +3146,12 @@
  2454. " -x, --starting-image <image>\n"
  2455. " -d, --root <directory>\n"
  2456. " -D, --devtable <file>\n"
  2457. + " -B, --block-size <bytes>\n"
  2458. " -b, --size-in-blocks <blocks>\n"
  2459. " -i, --bytes-per-inode <bytes per inode>\n"
  2460. " -N, --number-of-inodes <number of inodes>\n"
  2461. " -m, --reserved-percentage <percentage of blocks to reserve>\n"
  2462. + " -o, --creator-os <os> 'linux' (default), 'hurd', 'freebsd' or number.\n"
  2463. " -g, --block-map <path> Generate a block map file for this path.\n"
  2464. " -e, --fill-value <value> Fill unallocated blocks with value.\n"
  2465. " -z, --allow-holes Allow files with holes.\n"
  2466. @@ -2444,15 +3173,34 @@
  2467. extern char* optarg;
  2468. extern int optind, opterr, optopt;
  2469. +// parse the value for -o <os>
  2470. +int
  2471. +lookup_creator_os(const char *name)
  2472. +{
  2473. + if (isdigit (*name))
  2474. + return atoi(name);
  2475. + else if (strcasecmp(name, "linux") == 0)
  2476. + return EXT2_OS_LINUX;
  2477. + else if (strcasecmp(name, "GNU") == 0 || strcasecmp(name, "hurd") == 0)
  2478. + return EXT2_OS_HURD;
  2479. + else if (strcasecmp(name, "freebsd") == 0)
  2480. + return EXT2_OS_FREEBSD;
  2481. + else if (strcasecmp(name, "lites") == 0)
  2482. + return EXT2_OS_LITES;
  2483. + else
  2484. + return EXT2_OS_LINUX;
  2485. +}
  2486. +
  2487. int
  2488. main(int argc, char **argv)
  2489. {
  2490. - int nbblocks = -1;
  2491. + long long nbblocks = -1;
  2492. int nbinodes = -1;
  2493. int nbresrvd = -1;
  2494. float bytes_per_inode = -1;
  2495. float reserved_frac = -1;
  2496. int fs_timestamp = -1;
  2497. + int creator_os = CREATOR_OS;
  2498. char * fsout = "-";
  2499. char * fsin = 0;
  2500. char * dopt[MAX_DOPT];
  2501. @@ -2466,6 +3214,7 @@
  2502. int squash_perms = 0;
  2503. uint16 endian = 1;
  2504. int bigendian = !*(char*)&endian;
  2505. + char *volumelabel = NULL;
  2506. filesystem *fs;
  2507. int i;
  2508. int c;
  2509. @@ -2476,13 +3225,16 @@
  2510. { "starting-image", required_argument, NULL, 'x' },
  2511. { "root", required_argument, NULL, 'd' },
  2512. { "devtable", required_argument, NULL, 'D' },
  2513. + { "block-size", required_argument, NULL, 'B' },
  2514. { "size-in-blocks", required_argument, NULL, 'b' },
  2515. { "bytes-per-inode", required_argument, NULL, 'i' },
  2516. { "number-of-inodes", required_argument, NULL, 'N' },
  2517. + { "volume-label", required_argument, NULL, 'L' },
  2518. { "reserved-percentage", required_argument, NULL, 'm' },
  2519. + { "creator-os", required_argument, NULL, 'o' },
  2520. { "block-map", required_argument, NULL, 'g' },
  2521. { "fill-value", required_argument, NULL, 'e' },
  2522. - { "allow-holes", no_argument, NULL, 'z' },
  2523. + { "allow-holes", no_argument, NULL, 'z' },
  2524. { "faketime", no_argument, NULL, 'f' },
  2525. { "squash", no_argument, NULL, 'q' },
  2526. { "squash-uids", no_argument, NULL, 'U' },
  2527. @@ -2495,11 +3247,11 @@
  2528. app_name = argv[0];
  2529. - while((c = getopt_long(argc, argv, "x:d:D:b:i:N:m:g:e:zfqUPhVv", longopts, NULL)) != EOF) {
  2530. + while((c = getopt_long(argc, argv, "x:d:D:B:b:i:N:L:m:o:g:e:zfqUPhVv", longopts, NULL)) != EOF) {
  2531. #else
  2532. app_name = argv[0];
  2533. - while((c = getopt(argc, argv, "x:d:D:b:i:N:m:g:e:zfqUPhVv")) != EOF) {
  2534. + while((c = getopt(argc, argv, "x:d:D:B:b:i:N:L:m:o:g:e:zfqUPhVv")) != EOF) {
  2535. #endif /* HAVE_GETOPT_LONG */
  2536. switch(c)
  2537. {
  2538. @@ -2510,6 +3262,9 @@
  2539. case 'D':
  2540. dopt[didx++] = optarg;
  2541. break;
  2542. + case 'B':
  2543. + blocksize = SI_atof(optarg);
  2544. + break;
  2545. case 'b':
  2546. nbblocks = SI_atof(optarg);
  2547. break;
  2548. @@ -2519,9 +3274,15 @@
  2549. case 'N':
  2550. nbinodes = SI_atof(optarg);
  2551. break;
  2552. + case 'L':
  2553. + volumelabel = optarg;
  2554. + break;
  2555. case 'm':
  2556. reserved_frac = SI_atof(optarg) / 100;
  2557. break;
  2558. + case 'o':
  2559. + creator_os = lookup_creator_os(optarg);
  2560. + break;
  2561. case 'g':
  2562. gopt[gidx++] = optarg;
  2563. break;
  2564. @@ -2565,21 +3326,21 @@
  2565. error_msg_and_die("Not enough arguments. Try --help or else see the man page.");
  2566. fsout = argv[optind];
  2567. - hdlinks.hdl = (struct hdlink_s *)malloc(hdlink_cnt * sizeof(struct hdlink_s));
  2568. - if (!hdlinks.hdl)
  2569. - error_msg_and_die("Not enough memory");
  2570. - hdlinks.count = 0 ;
  2571. + if(blocksize != 1024 && blocksize != 2048 && blocksize != 4096)
  2572. + error_msg_and_die("Valid block sizes: 1024, 2048 or 4096.");
  2573. + if(creator_os < 0)
  2574. + error_msg_and_die("Creator OS unknown.");
  2575. if(fsin)
  2576. {
  2577. if(strcmp(fsin, "-"))
  2578. {
  2579. FILE * fh = xfopen(fsin, "rb");
  2580. - fs = load_fs(fh, bigendian);
  2581. + fs = load_fs(fh, bigendian, fsout);
  2582. fclose(fh);
  2583. }
  2584. else
  2585. - fs = load_fs(stdin, bigendian);
  2586. + fs = load_fs(stdin, bigendian, fsout);
  2587. }
  2588. else
  2589. {
  2590. @@ -2609,16 +3370,29 @@
  2591. }
  2592. if(fs_timestamp == -1)
  2593. fs_timestamp = time(NULL);
  2594. - fs = init_fs(nbblocks, nbinodes, nbresrvd, holes, fs_timestamp);
  2595. + fs = init_fs(nbblocks, nbinodes, nbresrvd, holes,
  2596. + fs_timestamp, creator_os, bigendian, fsout);
  2597. }
  2598. + if (volumelabel != NULL)
  2599. + strncpy((char *)fs->sb->s_volume_name, volumelabel,
  2600. + sizeof(fs->sb->s_volume_name));
  2601. populate_fs(fs, dopt, didx, squash_uids, squash_perms, fs_timestamp, NULL);
  2602. if(emptyval) {
  2603. uint32 b;
  2604. - for(b = 1; b < fs->sb.s_blocks_count; b++)
  2605. - if(!allocated(GRP_GET_BLOCK_BITMAP(fs,b),GRP_BBM_OFFSET(fs,b)))
  2606. - memset(get_blk(fs, b), emptyval, BLOCKSIZE);
  2607. + for(b = 1; b < fs->sb->s_blocks_count; b++) {
  2608. + blk_info *bi;
  2609. + gd_info *gi;
  2610. + if(!allocated(GRP_GET_BLOCK_BITMAP(fs,b,&bi,&gi),
  2611. + GRP_BBM_OFFSET(fs,b))) {
  2612. + blk_info *bi2;
  2613. + memset(get_blk(fs, b, &bi2), emptyval,
  2614. + BLOCKSIZE);
  2615. + put_blk(bi2);
  2616. + }
  2617. + GRP_PUT_BLOCK_BITMAP(bi,gi);
  2618. + }
  2619. }
  2620. if(verbose)
  2621. print_fs(fs);
  2622. @@ -2628,24 +3402,22 @@
  2623. char fname[MAX_FILENAME];
  2624. char *p;
  2625. FILE *fh;
  2626. + nod_info *ni;
  2627. if(!(nod = find_path(fs, EXT2_ROOT_INO, gopt[i])))
  2628. error_msg_and_die("path %s not found in filesystem", gopt[i]);
  2629. while((p = strchr(gopt[i], '/')))
  2630. *p = '_';
  2631. SNPRINTF(fname, MAX_FILENAME-1, "%s.blk", gopt[i]);
  2632. fh = xfopen(fname, "wb");
  2633. - fprintf(fh, "%d:", get_nod(fs, nod)->i_size);
  2634. + fprintf(fh, "%d:", get_nod(fs, nod, &ni)->i_size);
  2635. + put_nod(ni);
  2636. flist_blocks(fs, nod, fh);
  2637. fclose(fh);
  2638. }
  2639. - if(strcmp(fsout, "-"))
  2640. - {
  2641. - FILE * fh = xfopen(fsout, "wb");
  2642. - dump_fs(fs, fh, bigendian);
  2643. - fclose(fh);
  2644. - }
  2645. - else
  2646. - dump_fs(fs, stdout, bigendian);
  2647. + finish_fs(fs);
  2648. + if(strcmp(fsout, "-") == 0)
  2649. + copy_file(fs, stdout, fs->f, fs->sb->s_blocks_count);
  2650. +
  2651. free_fs(fs);
  2652. return 0;
  2653. }
  2654. Index: genext2fs-1.4.1/cache.h
  2655. ===================================================================
  2656. --- /dev/null
  2657. +++ genext2fs-1.4.1/cache.h
  2658. @@ -0,0 +1,128 @@
  2659. +#ifndef __CACHE_H__
  2660. +#define __CACHE_H__
  2661. +
  2662. +#include "list.h"
  2663. +
  2664. +#define CACHE_LISTS 256
  2665. +
  2666. +typedef struct
  2667. +{
  2668. + list_elem link;
  2669. + list_elem lru_link;
  2670. +} cache_link;
  2671. +
  2672. +typedef struct
  2673. +{
  2674. + /* LRU list holds unused items */
  2675. + unsigned int lru_entries;
  2676. + list_elem lru_list;
  2677. + unsigned int max_free_entries;
  2678. +
  2679. + unsigned int entries;
  2680. + list_elem lists[CACHE_LISTS];
  2681. + unsigned int (*elem_val)(cache_link *elem);
  2682. + void (*freed)(cache_link *elem);
  2683. +} listcache;
  2684. +
  2685. +static inline void
  2686. +cache_add(listcache *c, cache_link *elem)
  2687. +{
  2688. + unsigned int hash = c->elem_val(elem) % CACHE_LISTS;
  2689. + int delcount = c->lru_entries - c->max_free_entries;
  2690. +
  2691. + if (delcount > 0) {
  2692. + /* Delete some unused items. */
  2693. + list_elem *lru, *next;
  2694. + cache_link *l;
  2695. + list_for_each_elem_safe(&c->lru_list, lru, next) {
  2696. + l = container_of(lru, cache_link, lru_link);
  2697. + list_del(lru);
  2698. + list_del(&l->link);
  2699. + c->entries--;
  2700. + c->lru_entries--;
  2701. + c->freed(l);
  2702. + delcount--;
  2703. + if (delcount <= 0)
  2704. + break;
  2705. + }
  2706. + }
  2707. +
  2708. + c->entries++;
  2709. + list_item_init(&elem->lru_link); /* Mark it not in the LRU list */
  2710. + list_add_after(&c->lists[hash], &elem->link);
  2711. +}
  2712. +
  2713. +static inline void
  2714. +cache_item_set_unused(listcache *c, cache_link *elem)
  2715. +{
  2716. + list_add_before(&c->lru_list, &elem->lru_link);
  2717. + c->lru_entries++;
  2718. +}
  2719. +
  2720. +static inline cache_link *
  2721. +cache_find(listcache *c, unsigned int val)
  2722. +{
  2723. + unsigned int hash = val % CACHE_LISTS;
  2724. + list_elem *elem;
  2725. +
  2726. + list_for_each_elem(&c->lists[hash], elem) {
  2727. + cache_link *l = container_of(elem, cache_link, link);
  2728. + if (c->elem_val(l) == val) {
  2729. + if (!list_empty(&l->lru_link)) {
  2730. + /* It's in the unused list, remove it. */
  2731. + list_del(&l->lru_link);
  2732. + list_item_init(&l->lru_link);
  2733. + c->lru_entries--;
  2734. + }
  2735. + return l;
  2736. + }
  2737. + }
  2738. + return NULL;
  2739. +}
  2740. +
  2741. +static inline int
  2742. +cache_flush(listcache *c)
  2743. +{
  2744. + list_elem *elem, *next;
  2745. + cache_link *l;
  2746. + int i;
  2747. +
  2748. + list_for_each_elem_safe(&c->lru_list, elem, next) {
  2749. + l = container_of(elem, cache_link, lru_link);
  2750. + list_del(elem);
  2751. + list_del(&l->link);
  2752. + c->entries--;
  2753. + c->lru_entries--;
  2754. + c->freed(l);
  2755. + }
  2756. +
  2757. + for (i = 0; i < CACHE_LISTS; i++) {
  2758. + list_for_each_elem_safe(&c->lists[i], elem, next) {
  2759. + l = container_of(elem, cache_link, link);
  2760. + list_del(&l->link);
  2761. + c->entries--;
  2762. + c->freed(l);
  2763. + }
  2764. + }
  2765. +
  2766. + return c->entries || c->lru_entries;
  2767. +}
  2768. +
  2769. +static inline void
  2770. +cache_init(listcache *c, unsigned int max_free_entries,
  2771. + unsigned int (*elem_val)(cache_link *elem),
  2772. + void (*freed)(cache_link *elem))
  2773. +{
  2774. + int i;
  2775. +
  2776. + c->entries = 0;
  2777. + c->lru_entries = 0;
  2778. + c->max_free_entries = max_free_entries;
  2779. + list_init(&c->lru_list);
  2780. + for (i = 0; i < CACHE_LISTS; i++)
  2781. + list_init(&c->lists[i]);
  2782. + c->elem_val = elem_val;
  2783. + c->freed = freed;
  2784. +}
  2785. +
  2786. +#endif /* __CACHE_H__ */
  2787. Index: genext2fs-1.4.1/list.h
  2788. ===================================================================
  2789. --- /dev/null
  2790. +++ genext2fs-1.4.1/list.h
  2791. @@ -0,0 +1,78 @@
  2792. +#ifndef __LIST_H__
  2793. +#define __LIST_H__
  2794. +
  2795. +#if STDC_HEADERS
  2796. +# include <stdlib.h>
  2797. +# include <stddef.h>
  2798. +#else
  2799. +# if HAVE_STDLIB_H
  2800. +# include <stdlib.h>
  2801. +# endif
  2802. +# if HAVE_STDDEF_H
  2803. +# include <stddef.h>
  2804. +# endif
  2805. +#endif
  2806. +
  2807. +#ifndef offsetof
  2808. +#define offsetof(st, m) \
  2809. + ((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))
  2810. +#endif
  2811. +
  2812. +#define container_of(ptr, type, member) ({ \
  2813. + const typeof( ((type *)0)->member ) *__mptr = (ptr); \
  2814. + (type *)( (char *)__mptr - offsetof(type,member) );})
  2815. +
  2816. +typedef struct list_elem
  2817. +{
  2818. + struct list_elem *next;
  2819. + struct list_elem *prev;
  2820. +} list_elem;
  2821. +
  2822. +static inline void list_init(list_elem *list)
  2823. +{
  2824. + list->next = list;
  2825. + list->prev = list;
  2826. +}
  2827. +
  2828. +static inline void list_add_after(list_elem *pos, list_elem *elem)
  2829. +{
  2830. + elem->next = pos->next;
  2831. + elem->prev = pos;
  2832. + pos->next->prev = elem;
  2833. + pos->next = elem;
  2834. +}
  2835. +
  2836. +static inline void list_add_before(list_elem *pos, list_elem *elem)
  2837. +{
  2838. + elem->prev = pos->prev;
  2839. + elem->next = pos;
  2840. + pos->prev->next = elem;
  2841. + pos->prev = elem;
  2842. +}
  2843. +
  2844. +static inline void list_del(list_elem *elem)
  2845. +{
  2846. + elem->next->prev = elem->prev;
  2847. + elem->prev->next = elem->next;
  2848. +}
  2849. +
  2850. +static inline void list_item_init(list_elem *elem)
  2851. +{
  2852. + elem->next = elem;
  2853. + elem->prev = elem;
  2854. +}
  2855. +
  2856. +static inline int list_empty(list_elem *elem)
  2857. +{
  2858. + return elem->next == elem;
  2859. +}
  2860. +
  2861. +#define list_for_each_elem(list, curr) \
  2862. + for ((curr) = (list)->next; (curr) != (list); (curr) = (curr)->next)
  2863. +
  2864. +#define list_for_each_elem_safe(list, curr, next) \
  2865. + for ((curr) = (list)->next, (next) = (curr)->next; \
  2866. + (curr) != (list); \
  2867. + (curr) = (next), (next) = (curr)->next)
  2868. +
  2869. +#endif /* __LIST_H__ */