fat_write.c 26 KB

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