fat_write.c 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150
  1. /*
  2. * fat_write.c
  3. *
  4. * R/W (V)FAT 12/16/32 filesystem implementation by Donggeun Kim
  5. *
  6. * SPDX-License-Identifier: GPL-2.0+
  7. */
  8. #include <common.h>
  9. #include <command.h>
  10. #include <config.h>
  11. #include <fat.h>
  12. #include <asm/byteorder.h>
  13. #include <part.h>
  14. #include <linux/ctype.h>
  15. #include <div64.h>
  16. #include <linux/math64.h>
  17. #include "fat.c"
  18. static void uppercase(char *str, int len)
  19. {
  20. int i;
  21. for (i = 0; i < len; i++) {
  22. *str = toupper(*str);
  23. str++;
  24. }
  25. }
  26. static int total_sector;
  27. static int disk_write(__u32 block, __u32 nr_blocks, void *buf)
  28. {
  29. ulong ret;
  30. if (!cur_dev)
  31. return -1;
  32. if (cur_part_info.start + block + nr_blocks >
  33. cur_part_info.start + total_sector) {
  34. printf("error: overflow occurs\n");
  35. return -1;
  36. }
  37. ret = blk_dwrite(cur_dev, cur_part_info.start + block, nr_blocks, buf);
  38. if (nr_blocks && ret == 0)
  39. return -1;
  40. return ret;
  41. }
  42. /*
  43. * Set short name in directory entry
  44. */
  45. static void set_name(dir_entry *dirent, const char *filename)
  46. {
  47. char s_name[VFAT_MAXLEN_BYTES];
  48. char *period;
  49. int period_location, len, i, ext_num;
  50. if (filename == NULL)
  51. return;
  52. len = strlen(filename);
  53. if (len == 0)
  54. return;
  55. strcpy(s_name, filename);
  56. uppercase(s_name, len);
  57. period = strchr(s_name, '.');
  58. if (period == NULL) {
  59. period_location = len;
  60. ext_num = 0;
  61. } else {
  62. period_location = period - s_name;
  63. ext_num = len - period_location - 1;
  64. }
  65. /* Pad spaces when the length of file name is shorter than eight */
  66. if (period_location < 8) {
  67. memcpy(dirent->name, s_name, period_location);
  68. for (i = period_location; i < 8; i++)
  69. dirent->name[i] = ' ';
  70. } else if (period_location == 8) {
  71. memcpy(dirent->name, s_name, period_location);
  72. } else {
  73. memcpy(dirent->name, s_name, 6);
  74. dirent->name[6] = '~';
  75. dirent->name[7] = '1';
  76. }
  77. if (ext_num < 3) {
  78. memcpy(dirent->ext, s_name + period_location + 1, ext_num);
  79. for (i = ext_num; i < 3; i++)
  80. dirent->ext[i] = ' ';
  81. } else
  82. memcpy(dirent->ext, s_name + period_location + 1, 3);
  83. debug("name : %s\n", dirent->name);
  84. debug("ext : %s\n", dirent->ext);
  85. }
  86. static __u8 num_of_fats;
  87. /*
  88. * Write fat buffer into block device
  89. */
  90. static int flush_dirty_fat_buffer(fsdata *mydata)
  91. {
  92. int getsize = FATBUFBLOCKS;
  93. __u32 fatlength = mydata->fatlength;
  94. __u8 *bufptr = mydata->fatbuf;
  95. __u32 startblock = mydata->fatbufnum * FATBUFBLOCKS;
  96. debug("debug: evicting %d, dirty: %d\n", mydata->fatbufnum,
  97. (int)mydata->fat_dirty);
  98. if ((!mydata->fat_dirty) || (mydata->fatbufnum == -1))
  99. return 0;
  100. startblock += mydata->fat_sect;
  101. if (getsize > fatlength)
  102. getsize = fatlength;
  103. /* Write FAT buf */
  104. if (disk_write(startblock, getsize, bufptr) < 0) {
  105. debug("error: writing FAT blocks\n");
  106. return -1;
  107. }
  108. if (num_of_fats == 2) {
  109. /* Update corresponding second FAT blocks */
  110. startblock += mydata->fatlength;
  111. if (disk_write(startblock, getsize, bufptr) < 0) {
  112. debug("error: writing second FAT blocks\n");
  113. return -1;
  114. }
  115. }
  116. mydata->fat_dirty = 0;
  117. return 0;
  118. }
  119. /*
  120. * Get the entry at index 'entry' in a FAT (12/16/32) table.
  121. * On failure 0x00 is returned.
  122. * When bufnum is changed, write back the previous fatbuf to the disk.
  123. */
  124. static __u32 get_fatent_value(fsdata *mydata, __u32 entry)
  125. {
  126. __u32 bufnum;
  127. __u32 off16, offset;
  128. __u32 ret = 0x00;
  129. __u16 val1, val2;
  130. if (CHECK_CLUST(entry, mydata->fatsize)) {
  131. printf("Error: Invalid FAT entry: 0x%08x\n", entry);
  132. return ret;
  133. }
  134. switch (mydata->fatsize) {
  135. case 32:
  136. bufnum = entry / FAT32BUFSIZE;
  137. offset = entry - bufnum * FAT32BUFSIZE;
  138. break;
  139. case 16:
  140. bufnum = entry / FAT16BUFSIZE;
  141. offset = entry - bufnum * FAT16BUFSIZE;
  142. break;
  143. case 12:
  144. bufnum = entry / FAT12BUFSIZE;
  145. offset = entry - bufnum * FAT12BUFSIZE;
  146. break;
  147. default:
  148. /* Unsupported FAT size */
  149. return ret;
  150. }
  151. debug("FAT%d: entry: 0x%04x = %d, offset: 0x%04x = %d\n",
  152. mydata->fatsize, entry, entry, offset, offset);
  153. /* Read a new block of FAT entries into the cache. */
  154. if (bufnum != mydata->fatbufnum) {
  155. int getsize = FATBUFBLOCKS;
  156. __u8 *bufptr = mydata->fatbuf;
  157. __u32 fatlength = mydata->fatlength;
  158. __u32 startblock = bufnum * FATBUFBLOCKS;
  159. if (getsize > fatlength)
  160. getsize = fatlength;
  161. startblock += mydata->fat_sect; /* Offset from start of disk */
  162. /* Write back the fatbuf to the disk */
  163. if (flush_dirty_fat_buffer(mydata) < 0)
  164. return -1;
  165. if (disk_read(startblock, getsize, bufptr) < 0) {
  166. debug("Error reading FAT blocks\n");
  167. return ret;
  168. }
  169. mydata->fatbufnum = bufnum;
  170. }
  171. /* Get the actual entry from the table */
  172. switch (mydata->fatsize) {
  173. case 32:
  174. ret = FAT2CPU32(((__u32 *) mydata->fatbuf)[offset]);
  175. break;
  176. case 16:
  177. ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[offset]);
  178. break;
  179. case 12:
  180. off16 = (offset * 3) / 4;
  181. switch (offset & 0x3) {
  182. case 0:
  183. ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[off16]);
  184. ret &= 0xfff;
  185. break;
  186. case 1:
  187. val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]);
  188. val1 &= 0xf000;
  189. val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]);
  190. val2 &= 0x00ff;
  191. ret = (val2 << 4) | (val1 >> 12);
  192. break;
  193. case 2:
  194. val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]);
  195. val1 &= 0xff00;
  196. val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]);
  197. val2 &= 0x000f;
  198. ret = (val2 << 8) | (val1 >> 8);
  199. break;
  200. case 3:
  201. ret = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]);
  202. ret = (ret & 0xfff0) >> 4;
  203. break;
  204. default:
  205. break;
  206. }
  207. break;
  208. }
  209. debug("FAT%d: ret: %08x, entry: %08x, offset: %04x\n",
  210. mydata->fatsize, ret, entry, offset);
  211. return ret;
  212. }
  213. /*
  214. * Set the file name information from 'name' into 'slotptr',
  215. */
  216. static int str2slot(dir_slot *slotptr, const char *name, int *idx)
  217. {
  218. int j, end_idx = 0;
  219. for (j = 0; j <= 8; j += 2) {
  220. if (name[*idx] == 0x00) {
  221. slotptr->name0_4[j] = 0;
  222. slotptr->name0_4[j + 1] = 0;
  223. end_idx++;
  224. goto name0_4;
  225. }
  226. slotptr->name0_4[j] = name[*idx];
  227. (*idx)++;
  228. end_idx++;
  229. }
  230. for (j = 0; j <= 10; j += 2) {
  231. if (name[*idx] == 0x00) {
  232. slotptr->name5_10[j] = 0;
  233. slotptr->name5_10[j + 1] = 0;
  234. end_idx++;
  235. goto name5_10;
  236. }
  237. slotptr->name5_10[j] = name[*idx];
  238. (*idx)++;
  239. end_idx++;
  240. }
  241. for (j = 0; j <= 2; j += 2) {
  242. if (name[*idx] == 0x00) {
  243. slotptr->name11_12[j] = 0;
  244. slotptr->name11_12[j + 1] = 0;
  245. end_idx++;
  246. goto name11_12;
  247. }
  248. slotptr->name11_12[j] = name[*idx];
  249. (*idx)++;
  250. end_idx++;
  251. }
  252. if (name[*idx] == 0x00)
  253. return 1;
  254. return 0;
  255. /* Not used characters are filled with 0xff 0xff */
  256. name0_4:
  257. for (; end_idx < 5; end_idx++) {
  258. slotptr->name0_4[end_idx * 2] = 0xff;
  259. slotptr->name0_4[end_idx * 2 + 1] = 0xff;
  260. }
  261. end_idx = 5;
  262. name5_10:
  263. end_idx -= 5;
  264. for (; end_idx < 6; end_idx++) {
  265. slotptr->name5_10[end_idx * 2] = 0xff;
  266. slotptr->name5_10[end_idx * 2 + 1] = 0xff;
  267. }
  268. end_idx = 11;
  269. name11_12:
  270. end_idx -= 11;
  271. for (; end_idx < 2; end_idx++) {
  272. slotptr->name11_12[end_idx * 2] = 0xff;
  273. slotptr->name11_12[end_idx * 2 + 1] = 0xff;
  274. }
  275. return 1;
  276. }
  277. static int is_next_clust(fsdata *mydata, dir_entry *dentptr);
  278. static void flush_dir_table(fsdata *mydata, dir_entry **dentptr);
  279. /*
  280. * Fill dir_slot entries with appropriate name, id, and attr
  281. * The real directory entry is returned by 'dentptr'
  282. */
  283. static void
  284. fill_dir_slot(fsdata *mydata, dir_entry **dentptr, const char *l_name)
  285. {
  286. dir_slot *slotptr = (dir_slot *)get_contents_vfatname_block;
  287. __u8 counter = 0, checksum;
  288. int idx = 0, ret;
  289. /* Get short file name checksum value */
  290. checksum = mkcksum((*dentptr)->name, (*dentptr)->ext);
  291. do {
  292. memset(slotptr, 0x00, sizeof(dir_slot));
  293. ret = str2slot(slotptr, l_name, &idx);
  294. slotptr->id = ++counter;
  295. slotptr->attr = ATTR_VFAT;
  296. slotptr->alias_checksum = checksum;
  297. slotptr++;
  298. } while (ret == 0);
  299. slotptr--;
  300. slotptr->id |= LAST_LONG_ENTRY_MASK;
  301. while (counter >= 1) {
  302. if (is_next_clust(mydata, *dentptr)) {
  303. /* A new cluster is allocated for directory table */
  304. flush_dir_table(mydata, dentptr);
  305. }
  306. memcpy(*dentptr, slotptr, sizeof(dir_slot));
  307. (*dentptr)++;
  308. slotptr--;
  309. counter--;
  310. }
  311. if (is_next_clust(mydata, *dentptr)) {
  312. /* A new cluster is allocated for directory table */
  313. flush_dir_table(mydata, dentptr);
  314. }
  315. }
  316. static __u32 dir_curclust;
  317. /*
  318. * Extract the full long filename starting at 'retdent' (which is really
  319. * a slot) into 'l_name'. If successful also copy the real directory entry
  320. * into 'retdent'
  321. * If additional adjacent cluster for directory entries is read into memory,
  322. * then 'get_contents_vfatname_block' is copied into 'get_dentfromdir_block' and
  323. * the location of the real directory entry is returned by 'retdent'
  324. * Return 0 on success, -1 otherwise.
  325. */
  326. static int
  327. get_long_file_name(fsdata *mydata, int curclust, __u8 *cluster,
  328. dir_entry **retdent, char *l_name)
  329. {
  330. dir_entry *realdent;
  331. dir_slot *slotptr = (dir_slot *)(*retdent);
  332. dir_slot *slotptr2 = NULL;
  333. __u8 *buflimit = cluster + mydata->sect_size * ((curclust == 0) ?
  334. PREFETCH_BLOCKS :
  335. mydata->clust_size);
  336. __u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff;
  337. int idx = 0, cur_position = 0;
  338. if (counter > VFAT_MAXSEQ) {
  339. debug("Error: VFAT name is too long\n");
  340. return -1;
  341. }
  342. while ((__u8 *)slotptr < buflimit) {
  343. if (counter == 0)
  344. break;
  345. if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter)
  346. return -1;
  347. slotptr++;
  348. counter--;
  349. }
  350. if ((__u8 *)slotptr >= buflimit) {
  351. if (curclust == 0)
  352. return -1;
  353. curclust = get_fatent_value(mydata, dir_curclust);
  354. if (CHECK_CLUST(curclust, mydata->fatsize)) {
  355. debug("curclust: 0x%x\n", curclust);
  356. printf("Invalid FAT entry\n");
  357. return -1;
  358. }
  359. dir_curclust = curclust;
  360. if (get_cluster(mydata, curclust, get_contents_vfatname_block,
  361. mydata->clust_size * mydata->sect_size) != 0) {
  362. debug("Error: reading directory block\n");
  363. return -1;
  364. }
  365. slotptr2 = (dir_slot *)get_contents_vfatname_block;
  366. while (counter > 0) {
  367. if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK)
  368. & 0xff) != counter)
  369. return -1;
  370. slotptr2++;
  371. counter--;
  372. }
  373. /* Save the real directory entry */
  374. realdent = (dir_entry *)slotptr2;
  375. while ((__u8 *)slotptr2 > get_contents_vfatname_block) {
  376. slotptr2--;
  377. slot2str(slotptr2, l_name, &idx);
  378. }
  379. } else {
  380. /* Save the real directory entry */
  381. realdent = (dir_entry *)slotptr;
  382. }
  383. do {
  384. slotptr--;
  385. if (slot2str(slotptr, l_name, &idx))
  386. break;
  387. } while (!(slotptr->id & LAST_LONG_ENTRY_MASK));
  388. l_name[idx] = '\0';
  389. if (*l_name == DELETED_FLAG)
  390. *l_name = '\0';
  391. else if (*l_name == aRING)
  392. *l_name = DELETED_FLAG;
  393. downcase(l_name);
  394. /* Return the real directory entry */
  395. *retdent = realdent;
  396. if (slotptr2) {
  397. memcpy(get_dentfromdir_block, get_contents_vfatname_block,
  398. mydata->clust_size * mydata->sect_size);
  399. cur_position = (__u8 *)realdent - get_contents_vfatname_block;
  400. *retdent = (dir_entry *) &get_dentfromdir_block[cur_position];
  401. }
  402. return 0;
  403. }
  404. /*
  405. * Set the entry at index 'entry' in a FAT (16/32) table.
  406. */
  407. static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value)
  408. {
  409. __u32 bufnum, offset;
  410. switch (mydata->fatsize) {
  411. case 32:
  412. bufnum = entry / FAT32BUFSIZE;
  413. offset = entry - bufnum * FAT32BUFSIZE;
  414. break;
  415. case 16:
  416. bufnum = entry / FAT16BUFSIZE;
  417. offset = entry - bufnum * FAT16BUFSIZE;
  418. break;
  419. default:
  420. /* Unsupported FAT size */
  421. return -1;
  422. }
  423. /* Read a new block of FAT entries into the cache. */
  424. if (bufnum != mydata->fatbufnum) {
  425. int getsize = FATBUFBLOCKS;
  426. __u8 *bufptr = mydata->fatbuf;
  427. __u32 fatlength = mydata->fatlength;
  428. __u32 startblock = bufnum * FATBUFBLOCKS;
  429. fatlength *= mydata->sect_size;
  430. startblock += mydata->fat_sect;
  431. if (getsize > fatlength)
  432. getsize = fatlength;
  433. if (flush_dirty_fat_buffer(mydata) < 0)
  434. return -1;
  435. if (disk_read(startblock, getsize, bufptr) < 0) {
  436. debug("Error reading FAT blocks\n");
  437. return -1;
  438. }
  439. mydata->fatbufnum = bufnum;
  440. }
  441. /* Mark as dirty */
  442. mydata->fat_dirty = 1;
  443. /* Set the actual entry */
  444. switch (mydata->fatsize) {
  445. case 32:
  446. ((__u32 *) mydata->fatbuf)[offset] = cpu_to_le32(entry_value);
  447. break;
  448. case 16:
  449. ((__u16 *) mydata->fatbuf)[offset] = cpu_to_le16(entry_value);
  450. break;
  451. default:
  452. return -1;
  453. }
  454. return 0;
  455. }
  456. /*
  457. * Determine the next free cluster after 'entry' in a FAT (16/32) table
  458. * and link it to 'entry'. EOC marker is not set on returned entry.
  459. */
  460. static __u32 determine_fatent(fsdata *mydata, __u32 entry)
  461. {
  462. __u32 next_fat, next_entry = entry + 1;
  463. while (1) {
  464. next_fat = get_fatent_value(mydata, next_entry);
  465. if (next_fat == 0) {
  466. /* found free entry, link to entry */
  467. set_fatent_value(mydata, entry, next_entry);
  468. break;
  469. }
  470. next_entry++;
  471. }
  472. debug("FAT%d: entry: %08x, entry_value: %04x\n",
  473. mydata->fatsize, entry, next_entry);
  474. return next_entry;
  475. }
  476. /*
  477. * Write at most 'size' bytes from 'buffer' into the specified cluster.
  478. * Return 0 on success, -1 otherwise.
  479. */
  480. static int
  481. set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer,
  482. unsigned long size)
  483. {
  484. __u32 idx = 0;
  485. __u32 startsect;
  486. int ret;
  487. if (clustnum > 0)
  488. startsect = mydata->data_begin +
  489. clustnum * mydata->clust_size;
  490. else
  491. startsect = mydata->rootdir_sect;
  492. debug("clustnum: %d, startsect: %d\n", clustnum, startsect);
  493. if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) {
  494. ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
  495. printf("FAT: Misaligned buffer address (%p)\n", buffer);
  496. while (size >= mydata->sect_size) {
  497. memcpy(tmpbuf, buffer, mydata->sect_size);
  498. ret = disk_write(startsect++, 1, tmpbuf);
  499. if (ret != 1) {
  500. debug("Error writing data (got %d)\n", ret);
  501. return -1;
  502. }
  503. buffer += mydata->sect_size;
  504. size -= mydata->sect_size;
  505. }
  506. } else if (size >= mydata->sect_size) {
  507. idx = size / mydata->sect_size;
  508. ret = disk_write(startsect, idx, buffer);
  509. if (ret != idx) {
  510. debug("Error writing data (got %d)\n", ret);
  511. return -1;
  512. }
  513. startsect += idx;
  514. idx *= mydata->sect_size;
  515. buffer += idx;
  516. size -= idx;
  517. }
  518. if (size) {
  519. ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
  520. memcpy(tmpbuf, buffer, size);
  521. ret = disk_write(startsect, 1, tmpbuf);
  522. if (ret != 1) {
  523. debug("Error writing data (got %d)\n", ret);
  524. return -1;
  525. }
  526. }
  527. return 0;
  528. }
  529. /*
  530. * Find the first empty cluster
  531. */
  532. static int find_empty_cluster(fsdata *mydata)
  533. {
  534. __u32 fat_val, entry = 3;
  535. while (1) {
  536. fat_val = get_fatent_value(mydata, entry);
  537. if (fat_val == 0)
  538. break;
  539. entry++;
  540. }
  541. return entry;
  542. }
  543. /*
  544. * Write directory entries in 'get_dentfromdir_block' to block device
  545. */
  546. static void flush_dir_table(fsdata *mydata, dir_entry **dentptr)
  547. {
  548. int dir_newclust = 0;
  549. if (set_cluster(mydata, dir_curclust,
  550. get_dentfromdir_block,
  551. mydata->clust_size * mydata->sect_size) != 0) {
  552. printf("error: wrinting directory entry\n");
  553. return;
  554. }
  555. dir_newclust = find_empty_cluster(mydata);
  556. set_fatent_value(mydata, dir_curclust, dir_newclust);
  557. if (mydata->fatsize == 32)
  558. set_fatent_value(mydata, dir_newclust, 0xffffff8);
  559. else if (mydata->fatsize == 16)
  560. set_fatent_value(mydata, dir_newclust, 0xfff8);
  561. dir_curclust = dir_newclust;
  562. if (flush_dirty_fat_buffer(mydata) < 0)
  563. return;
  564. memset(get_dentfromdir_block, 0x00,
  565. mydata->clust_size * mydata->sect_size);
  566. *dentptr = (dir_entry *) get_dentfromdir_block;
  567. }
  568. /*
  569. * Set empty cluster from 'entry' to the end of a file
  570. */
  571. static int clear_fatent(fsdata *mydata, __u32 entry)
  572. {
  573. __u32 fat_val;
  574. while (1) {
  575. fat_val = get_fatent_value(mydata, entry);
  576. if (fat_val != 0)
  577. set_fatent_value(mydata, entry, 0);
  578. else
  579. break;
  580. if (fat_val == 0xfffffff || fat_val == 0xffff)
  581. break;
  582. entry = fat_val;
  583. }
  584. /* Flush fat buffer */
  585. if (flush_dirty_fat_buffer(mydata) < 0)
  586. return -1;
  587. return 0;
  588. }
  589. /*
  590. * Write at most 'maxsize' bytes from 'buffer' into
  591. * the file associated with 'dentptr'
  592. * Update the number of bytes written in *gotsize and return 0
  593. * or return -1 on fatal errors.
  594. */
  595. static int
  596. set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
  597. loff_t maxsize, loff_t *gotsize)
  598. {
  599. loff_t filesize = FAT2CPU32(dentptr->size);
  600. unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
  601. __u32 curclust = START(dentptr);
  602. __u32 endclust = 0, newclust = 0;
  603. loff_t actsize;
  604. *gotsize = 0;
  605. debug("Filesize: %llu bytes\n", filesize);
  606. if (maxsize > 0 && filesize > maxsize)
  607. filesize = maxsize;
  608. debug("%llu bytes\n", filesize);
  609. if (!curclust) {
  610. if (filesize) {
  611. debug("error: nonempty clusterless file!\n");
  612. return -1;
  613. }
  614. return 0;
  615. }
  616. actsize = bytesperclust;
  617. endclust = curclust;
  618. do {
  619. /* search for consecutive clusters */
  620. while (actsize < filesize) {
  621. newclust = determine_fatent(mydata, endclust);
  622. if ((newclust - 1) != endclust)
  623. goto getit;
  624. if (CHECK_CLUST(newclust, mydata->fatsize)) {
  625. debug("newclust: 0x%x\n", newclust);
  626. debug("Invalid FAT entry\n");
  627. return 0;
  628. }
  629. endclust = newclust;
  630. actsize += bytesperclust;
  631. }
  632. /* set remaining bytes */
  633. actsize = filesize;
  634. if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
  635. debug("error: writing cluster\n");
  636. return -1;
  637. }
  638. *gotsize += actsize;
  639. /* Mark end of file in FAT */
  640. if (mydata->fatsize == 16)
  641. newclust = 0xffff;
  642. else if (mydata->fatsize == 32)
  643. newclust = 0xfffffff;
  644. set_fatent_value(mydata, endclust, newclust);
  645. return 0;
  646. getit:
  647. if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
  648. debug("error: writing cluster\n");
  649. return -1;
  650. }
  651. *gotsize += actsize;
  652. filesize -= actsize;
  653. buffer += actsize;
  654. if (CHECK_CLUST(newclust, mydata->fatsize)) {
  655. debug("newclust: 0x%x\n", newclust);
  656. debug("Invalid FAT entry\n");
  657. return 0;
  658. }
  659. actsize = bytesperclust;
  660. curclust = endclust = newclust;
  661. } while (1);
  662. }
  663. /*
  664. * Set start cluster in directory entry
  665. */
  666. static void set_start_cluster(const fsdata *mydata, dir_entry *dentptr,
  667. __u32 start_cluster)
  668. {
  669. if (mydata->fatsize == 32)
  670. dentptr->starthi =
  671. cpu_to_le16((start_cluster & 0xffff0000) >> 16);
  672. dentptr->start = cpu_to_le16(start_cluster & 0xffff);
  673. }
  674. /*
  675. * Fill dir_entry
  676. */
  677. static void fill_dentry(fsdata *mydata, dir_entry *dentptr,
  678. const char *filename, __u32 start_cluster, __u32 size, __u8 attr)
  679. {
  680. set_start_cluster(mydata, dentptr, start_cluster);
  681. dentptr->size = cpu_to_le32(size);
  682. dentptr->attr = attr;
  683. set_name(dentptr, filename);
  684. }
  685. /*
  686. * Check whether adding a file makes the file system to
  687. * exceed the size of the block device
  688. * Return -1 when overflow occurs, otherwise return 0
  689. */
  690. static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size)
  691. {
  692. __u32 startsect, sect_num, offset;
  693. if (clustnum > 0) {
  694. startsect = mydata->data_begin +
  695. clustnum * mydata->clust_size;
  696. } else {
  697. startsect = mydata->rootdir_sect;
  698. }
  699. sect_num = div_u64_rem(size, mydata->sect_size, &offset);
  700. if (offset != 0)
  701. sect_num++;
  702. if (startsect + sect_num > cur_part_info.start + total_sector)
  703. return -1;
  704. return 0;
  705. }
  706. /*
  707. * Check if adding several entries exceed one cluster boundary
  708. */
  709. static int is_next_clust(fsdata *mydata, dir_entry *dentptr)
  710. {
  711. int cur_position;
  712. cur_position = (__u8 *)dentptr - get_dentfromdir_block;
  713. if (cur_position >= mydata->clust_size * mydata->sect_size)
  714. return 1;
  715. else
  716. return 0;
  717. }
  718. static dir_entry *empty_dentptr;
  719. /*
  720. * Find a directory entry based on filename or start cluster number
  721. * If the directory entry is not found,
  722. * the new position for writing a directory entry will be returned
  723. */
  724. static dir_entry *find_directory_entry(fsdata *mydata, int startsect,
  725. char *filename, dir_entry *retdent, __u32 start)
  726. {
  727. __u32 curclust = (startsect - mydata->data_begin) / mydata->clust_size;
  728. debug("get_dentfromdir: %s\n", filename);
  729. while (1) {
  730. dir_entry *dentptr;
  731. int i;
  732. if (get_cluster(mydata, curclust, get_dentfromdir_block,
  733. mydata->clust_size * mydata->sect_size) != 0) {
  734. printf("Error: reading directory block\n");
  735. return NULL;
  736. }
  737. dentptr = (dir_entry *)get_dentfromdir_block;
  738. dir_curclust = curclust;
  739. for (i = 0; i < DIRENTSPERCLUST; i++) {
  740. char s_name[14], l_name[VFAT_MAXLEN_BYTES];
  741. l_name[0] = '\0';
  742. if (dentptr->name[0] == DELETED_FLAG) {
  743. dentptr++;
  744. if (is_next_clust(mydata, dentptr))
  745. break;
  746. continue;
  747. }
  748. if ((dentptr->attr & ATTR_VOLUME)) {
  749. if (vfat_enabled &&
  750. (dentptr->attr & ATTR_VFAT) &&
  751. (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) {
  752. get_long_file_name(mydata, curclust,
  753. get_dentfromdir_block,
  754. &dentptr, l_name);
  755. debug("vfatname: |%s|\n", l_name);
  756. } else {
  757. /* Volume label or VFAT entry */
  758. dentptr++;
  759. if (is_next_clust(mydata, dentptr))
  760. break;
  761. continue;
  762. }
  763. }
  764. if (dentptr->name[0] == 0) {
  765. debug("Dentname == NULL - %d\n", i);
  766. empty_dentptr = dentptr;
  767. return NULL;
  768. }
  769. get_name(dentptr, s_name);
  770. if (strcmp(filename, s_name)
  771. && strcmp(filename, l_name)) {
  772. debug("Mismatch: |%s|%s|\n",
  773. s_name, l_name);
  774. dentptr++;
  775. if (is_next_clust(mydata, dentptr))
  776. break;
  777. continue;
  778. }
  779. memcpy(retdent, dentptr, sizeof(dir_entry));
  780. debug("DentName: %s", s_name);
  781. debug(", start: 0x%x", START(dentptr));
  782. debug(", size: 0x%x %s\n",
  783. FAT2CPU32(dentptr->size),
  784. (dentptr->attr & ATTR_DIR) ?
  785. "(DIR)" : "");
  786. return dentptr;
  787. }
  788. /*
  789. * In FAT16/12, the root dir is locate before data area, shows
  790. * in following:
  791. * -------------------------------------------------------------
  792. * | Boot | FAT1 & 2 | Root dir | Data (start from cluster #2) |
  793. * -------------------------------------------------------------
  794. *
  795. * As a result if curclust is in Root dir, it is a negative
  796. * number or 0, 1.
  797. *
  798. */
  799. if (mydata->fatsize != 32 && (int)curclust <= 1) {
  800. /* Current clust is in root dir, set to next clust */
  801. curclust++;
  802. if ((int)curclust <= 1)
  803. continue; /* continue to find */
  804. /* Reach the end of root dir */
  805. empty_dentptr = dentptr;
  806. return NULL;
  807. }
  808. curclust = get_fatent_value(mydata, dir_curclust);
  809. if (IS_LAST_CLUST(curclust, mydata->fatsize)) {
  810. empty_dentptr = dentptr;
  811. return NULL;
  812. }
  813. if (CHECK_CLUST(curclust, mydata->fatsize)) {
  814. debug("curclust: 0x%x\n", curclust);
  815. debug("Invalid FAT entry\n");
  816. return NULL;
  817. }
  818. }
  819. return NULL;
  820. }
  821. static int do_fat_write(const char *filename, void *buffer, loff_t size,
  822. loff_t *actwrite)
  823. {
  824. dir_entry *dentptr, *retdent;
  825. __u32 startsect;
  826. __u32 start_cluster;
  827. boot_sector bs;
  828. volume_info volinfo;
  829. fsdata datablock;
  830. fsdata *mydata = &datablock;
  831. int cursect;
  832. int ret = -1, name_len;
  833. char l_filename[VFAT_MAXLEN_BYTES];
  834. *actwrite = size;
  835. dir_curclust = 0;
  836. if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) {
  837. debug("error: reading boot sector\n");
  838. return -1;
  839. }
  840. total_sector = bs.total_sect;
  841. if (total_sector == 0)
  842. total_sector = (int)cur_part_info.size; /* cast of lbaint_t */
  843. if (mydata->fatsize == 32)
  844. mydata->fatlength = bs.fat32_length;
  845. else
  846. mydata->fatlength = bs.fat_length;
  847. mydata->fat_sect = bs.reserved;
  848. cursect = mydata->rootdir_sect
  849. = mydata->fat_sect + mydata->fatlength * bs.fats;
  850. num_of_fats = bs.fats;
  851. mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0];
  852. mydata->clust_size = bs.cluster_size;
  853. if (mydata->fatsize == 32) {
  854. mydata->data_begin = mydata->rootdir_sect -
  855. (mydata->clust_size * 2);
  856. } else {
  857. int rootdir_size;
  858. rootdir_size = ((bs.dir_entries[1] * (int)256 +
  859. bs.dir_entries[0]) *
  860. sizeof(dir_entry)) /
  861. mydata->sect_size;
  862. mydata->data_begin = mydata->rootdir_sect +
  863. rootdir_size -
  864. (mydata->clust_size * 2);
  865. }
  866. mydata->fatbufnum = -1;
  867. mydata->fat_dirty = 0;
  868. mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE);
  869. if (mydata->fatbuf == NULL) {
  870. debug("Error: allocating memory\n");
  871. return -1;
  872. }
  873. if (disk_read(cursect,
  874. (mydata->fatsize == 32) ?
  875. (mydata->clust_size) :
  876. PREFETCH_BLOCKS, do_fat_read_at_block) < 0) {
  877. debug("Error: reading rootdir block\n");
  878. goto exit;
  879. }
  880. dentptr = (dir_entry *) do_fat_read_at_block;
  881. name_len = strlen(filename);
  882. if (name_len >= VFAT_MAXLEN_BYTES)
  883. name_len = VFAT_MAXLEN_BYTES - 1;
  884. memcpy(l_filename, filename, name_len);
  885. l_filename[name_len] = 0; /* terminate the string */
  886. downcase(l_filename);
  887. startsect = mydata->rootdir_sect;
  888. retdent = find_directory_entry(mydata, startsect,
  889. l_filename, dentptr, 0);
  890. if (retdent) {
  891. /* Update file size and start_cluster in a directory entry */
  892. retdent->size = cpu_to_le32(size);
  893. start_cluster = START(retdent);
  894. if (start_cluster) {
  895. if (size) {
  896. ret = check_overflow(mydata, start_cluster,
  897. size);
  898. if (ret) {
  899. printf("Error: %llu overflow\n", size);
  900. goto exit;
  901. }
  902. }
  903. ret = clear_fatent(mydata, start_cluster);
  904. if (ret) {
  905. printf("Error: clearing FAT entries\n");
  906. goto exit;
  907. }
  908. if (!size)
  909. set_start_cluster(mydata, retdent, 0);
  910. } else if (size) {
  911. ret = start_cluster = find_empty_cluster(mydata);
  912. if (ret < 0) {
  913. printf("Error: finding empty cluster\n");
  914. goto exit;
  915. }
  916. ret = check_overflow(mydata, start_cluster, size);
  917. if (ret) {
  918. printf("Error: %llu overflow\n", size);
  919. goto exit;
  920. }
  921. set_start_cluster(mydata, retdent, start_cluster);
  922. }
  923. } else {
  924. /* Set short name to set alias checksum field in dir_slot */
  925. set_name(empty_dentptr, filename);
  926. fill_dir_slot(mydata, &empty_dentptr, filename);
  927. if (size) {
  928. ret = start_cluster = find_empty_cluster(mydata);
  929. if (ret < 0) {
  930. printf("Error: finding empty cluster\n");
  931. goto exit;
  932. }
  933. ret = check_overflow(mydata, start_cluster, size);
  934. if (ret) {
  935. printf("Error: %llu overflow\n", size);
  936. goto exit;
  937. }
  938. } else {
  939. start_cluster = 0;
  940. }
  941. /* Set attribute as archieve for regular file */
  942. fill_dentry(mydata, empty_dentptr, filename,
  943. start_cluster, size, 0x20);
  944. retdent = empty_dentptr;
  945. }
  946. ret = set_contents(mydata, retdent, buffer, size, actwrite);
  947. if (ret < 0) {
  948. printf("Error: writing contents\n");
  949. goto exit;
  950. }
  951. debug("attempt to write 0x%llx bytes\n", *actwrite);
  952. /* Flush fat buffer */
  953. ret = flush_dirty_fat_buffer(mydata);
  954. if (ret) {
  955. printf("Error: flush fat buffer\n");
  956. goto exit;
  957. }
  958. /* Write directory table to device */
  959. ret = set_cluster(mydata, dir_curclust, get_dentfromdir_block,
  960. mydata->clust_size * mydata->sect_size);
  961. if (ret)
  962. printf("Error: writing directory entry\n");
  963. exit:
  964. free(mydata->fatbuf);
  965. return ret;
  966. }
  967. int file_fat_write(const char *filename, void *buffer, loff_t offset,
  968. loff_t maxsize, loff_t *actwrite)
  969. {
  970. if (offset != 0) {
  971. printf("Error: non zero offset is currently not supported.\n");
  972. return -1;
  973. }
  974. printf("writing %s\n", filename);
  975. return do_fat_write(filename, buffer, maxsize, actwrite);
  976. }