fat_write.c 25 KB

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