fat_write.c 25 KB

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