fat_write.c 26 KB

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