fat_write.c 25 KB

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