fat_write.c 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * fat_write.c
  4. *
  5. * R/W (V)FAT 12/16/32 filesystem implementation by Donggeun Kim
  6. */
  7. #include <common.h>
  8. #include <command.h>
  9. #include <config.h>
  10. #include <fat.h>
  11. #include <asm/byteorder.h>
  12. #include <part.h>
  13. #include <linux/ctype.h>
  14. #include <div64.h>
  15. #include <linux/math64.h>
  16. #include "fat.c"
  17. static void uppercase(char *str, int len)
  18. {
  19. int i;
  20. for (i = 0; i < len; i++) {
  21. *str = toupper(*str);
  22. str++;
  23. }
  24. }
  25. static int total_sector;
  26. static int disk_write(__u32 block, __u32 nr_blocks, void *buf)
  27. {
  28. ulong ret;
  29. if (!cur_dev)
  30. return -1;
  31. if (cur_part_info.start + block + nr_blocks >
  32. cur_part_info.start + total_sector) {
  33. printf("error: overflow occurs\n");
  34. return -1;
  35. }
  36. ret = blk_dwrite(cur_dev, cur_part_info.start + block, nr_blocks, buf);
  37. if (nr_blocks && ret == 0)
  38. return -1;
  39. return ret;
  40. }
  41. /*
  42. * Set short name in directory entry
  43. */
  44. static void set_name(dir_entry *dirent, const char *filename)
  45. {
  46. char s_name[VFAT_MAXLEN_BYTES];
  47. char *period;
  48. int period_location, len, i, ext_num;
  49. if (filename == NULL)
  50. return;
  51. len = strlen(filename);
  52. if (len == 0)
  53. return;
  54. strcpy(s_name, filename);
  55. uppercase(s_name, len);
  56. period = strchr(s_name, '.');
  57. if (period == NULL) {
  58. period_location = len;
  59. ext_num = 0;
  60. } else {
  61. period_location = period - s_name;
  62. ext_num = len - period_location - 1;
  63. }
  64. /* Pad spaces when the length of file name is shorter than eight */
  65. if (period_location < 8) {
  66. memcpy(dirent->name, s_name, period_location);
  67. for (i = period_location; i < 8; i++)
  68. dirent->name[i] = ' ';
  69. } else if (period_location == 8) {
  70. memcpy(dirent->name, s_name, period_location);
  71. } else {
  72. memcpy(dirent->name, s_name, 6);
  73. dirent->name[6] = '~';
  74. dirent->name[7] = '1';
  75. }
  76. if (ext_num < 3) {
  77. memcpy(dirent->ext, s_name + period_location + 1, ext_num);
  78. for (i = ext_num; i < 3; i++)
  79. dirent->ext[i] = ' ';
  80. } else
  81. memcpy(dirent->ext, s_name + period_location + 1, 3);
  82. debug("name : %s\n", dirent->name);
  83. debug("ext : %s\n", dirent->ext);
  84. }
  85. /*
  86. * Write fat buffer into block device
  87. */
  88. static int flush_dirty_fat_buffer(fsdata *mydata)
  89. {
  90. int getsize = FATBUFBLOCKS;
  91. __u32 fatlength = mydata->fatlength;
  92. __u8 *bufptr = mydata->fatbuf;
  93. __u32 startblock = mydata->fatbufnum * FATBUFBLOCKS;
  94. debug("debug: evicting %d, dirty: %d\n", mydata->fatbufnum,
  95. (int)mydata->fat_dirty);
  96. if ((!mydata->fat_dirty) || (mydata->fatbufnum == -1))
  97. return 0;
  98. /* Cap length if fatlength is not a multiple of FATBUFBLOCKS */
  99. if (startblock + getsize > fatlength)
  100. getsize = fatlength - startblock;
  101. startblock += mydata->fat_sect;
  102. /* Write FAT buf */
  103. if (disk_write(startblock, getsize, bufptr) < 0) {
  104. debug("error: writing FAT blocks\n");
  105. return -1;
  106. }
  107. if (mydata->fats == 2) {
  108. /* Update corresponding second FAT blocks */
  109. startblock += mydata->fatlength;
  110. if (disk_write(startblock, getsize, bufptr) < 0) {
  111. debug("error: writing second FAT blocks\n");
  112. return -1;
  113. }
  114. }
  115. mydata->fat_dirty = 0;
  116. return 0;
  117. }
  118. /*
  119. * Set the file name information from 'name' into 'slotptr',
  120. */
  121. static int str2slot(dir_slot *slotptr, const char *name, int *idx)
  122. {
  123. int j, end_idx = 0;
  124. for (j = 0; j <= 8; j += 2) {
  125. if (name[*idx] == 0x00) {
  126. slotptr->name0_4[j] = 0;
  127. slotptr->name0_4[j + 1] = 0;
  128. end_idx++;
  129. goto name0_4;
  130. }
  131. slotptr->name0_4[j] = name[*idx];
  132. (*idx)++;
  133. end_idx++;
  134. }
  135. for (j = 0; j <= 10; j += 2) {
  136. if (name[*idx] == 0x00) {
  137. slotptr->name5_10[j] = 0;
  138. slotptr->name5_10[j + 1] = 0;
  139. end_idx++;
  140. goto name5_10;
  141. }
  142. slotptr->name5_10[j] = name[*idx];
  143. (*idx)++;
  144. end_idx++;
  145. }
  146. for (j = 0; j <= 2; j += 2) {
  147. if (name[*idx] == 0x00) {
  148. slotptr->name11_12[j] = 0;
  149. slotptr->name11_12[j + 1] = 0;
  150. end_idx++;
  151. goto name11_12;
  152. }
  153. slotptr->name11_12[j] = name[*idx];
  154. (*idx)++;
  155. end_idx++;
  156. }
  157. if (name[*idx] == 0x00)
  158. return 1;
  159. return 0;
  160. /* Not used characters are filled with 0xff 0xff */
  161. name0_4:
  162. for (; end_idx < 5; end_idx++) {
  163. slotptr->name0_4[end_idx * 2] = 0xff;
  164. slotptr->name0_4[end_idx * 2 + 1] = 0xff;
  165. }
  166. end_idx = 5;
  167. name5_10:
  168. end_idx -= 5;
  169. for (; end_idx < 6; end_idx++) {
  170. slotptr->name5_10[end_idx * 2] = 0xff;
  171. slotptr->name5_10[end_idx * 2 + 1] = 0xff;
  172. }
  173. end_idx = 11;
  174. name11_12:
  175. end_idx -= 11;
  176. for (; end_idx < 2; end_idx++) {
  177. slotptr->name11_12[end_idx * 2] = 0xff;
  178. slotptr->name11_12[end_idx * 2 + 1] = 0xff;
  179. }
  180. return 1;
  181. }
  182. static int flush_dir_table(fat_itr *itr);
  183. /*
  184. * Fill dir_slot entries with appropriate name, id, and attr
  185. * 'itr' will point to a next entry
  186. */
  187. static int
  188. fill_dir_slot(fat_itr *itr, const char *l_name)
  189. {
  190. __u8 temp_dir_slot_buffer[MAX_LFN_SLOT * sizeof(dir_slot)];
  191. dir_slot *slotptr = (dir_slot *)temp_dir_slot_buffer;
  192. __u8 counter = 0, checksum;
  193. int idx = 0, ret;
  194. /* Get short file name checksum value */
  195. checksum = mkcksum(itr->dent->name, itr->dent->ext);
  196. do {
  197. memset(slotptr, 0x00, sizeof(dir_slot));
  198. ret = str2slot(slotptr, l_name, &idx);
  199. slotptr->id = ++counter;
  200. slotptr->attr = ATTR_VFAT;
  201. slotptr->alias_checksum = checksum;
  202. slotptr++;
  203. } while (ret == 0);
  204. slotptr--;
  205. slotptr->id |= LAST_LONG_ENTRY_MASK;
  206. while (counter >= 1) {
  207. memcpy(itr->dent, slotptr, sizeof(dir_slot));
  208. slotptr--;
  209. counter--;
  210. if (!fat_itr_next(itr))
  211. if (!itr->dent && !itr->is_root && flush_dir_table(itr))
  212. return -1;
  213. }
  214. if (!itr->dent && !itr->is_root)
  215. /*
  216. * don't care return value here because we have already
  217. * finished completing an entry with name, only ending up
  218. * no more entry left
  219. */
  220. flush_dir_table(itr);
  221. return 0;
  222. }
  223. /*
  224. * Set the entry at index 'entry' in a FAT (12/16/32) table.
  225. */
  226. static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value)
  227. {
  228. __u32 bufnum, offset, off16;
  229. __u16 val1, val2;
  230. switch (mydata->fatsize) {
  231. case 32:
  232. bufnum = entry / FAT32BUFSIZE;
  233. offset = entry - bufnum * FAT32BUFSIZE;
  234. break;
  235. case 16:
  236. bufnum = entry / FAT16BUFSIZE;
  237. offset = entry - bufnum * FAT16BUFSIZE;
  238. break;
  239. case 12:
  240. bufnum = entry / FAT12BUFSIZE;
  241. offset = entry - bufnum * FAT12BUFSIZE;
  242. break;
  243. default:
  244. /* Unsupported FAT size */
  245. return -1;
  246. }
  247. /* Read a new block of FAT entries into the cache. */
  248. if (bufnum != mydata->fatbufnum) {
  249. int getsize = FATBUFBLOCKS;
  250. __u8 *bufptr = mydata->fatbuf;
  251. __u32 fatlength = mydata->fatlength;
  252. __u32 startblock = bufnum * FATBUFBLOCKS;
  253. /* Cap length if fatlength is not a multiple of FATBUFBLOCKS */
  254. if (startblock + getsize > fatlength)
  255. getsize = fatlength - startblock;
  256. if (flush_dirty_fat_buffer(mydata) < 0)
  257. return -1;
  258. startblock += mydata->fat_sect;
  259. if (disk_read(startblock, getsize, bufptr) < 0) {
  260. debug("Error reading FAT blocks\n");
  261. return -1;
  262. }
  263. mydata->fatbufnum = bufnum;
  264. }
  265. /* Mark as dirty */
  266. mydata->fat_dirty = 1;
  267. /* Set the actual entry */
  268. switch (mydata->fatsize) {
  269. case 32:
  270. ((__u32 *) mydata->fatbuf)[offset] = cpu_to_le32(entry_value);
  271. break;
  272. case 16:
  273. ((__u16 *) mydata->fatbuf)[offset] = cpu_to_le16(entry_value);
  274. break;
  275. case 12:
  276. off16 = (offset * 3) / 4;
  277. switch (offset & 0x3) {
  278. case 0:
  279. val1 = cpu_to_le16(entry_value) & 0xfff;
  280. ((__u16 *)mydata->fatbuf)[off16] &= ~0xfff;
  281. ((__u16 *)mydata->fatbuf)[off16] |= val1;
  282. break;
  283. case 1:
  284. val1 = cpu_to_le16(entry_value) & 0xf;
  285. val2 = (cpu_to_le16(entry_value) >> 4) & 0xff;
  286. ((__u16 *)mydata->fatbuf)[off16] &= ~0xf000;
  287. ((__u16 *)mydata->fatbuf)[off16] |= (val1 << 12);
  288. ((__u16 *)mydata->fatbuf)[off16 + 1] &= ~0xff;
  289. ((__u16 *)mydata->fatbuf)[off16 + 1] |= val2;
  290. break;
  291. case 2:
  292. val1 = cpu_to_le16(entry_value) & 0xff;
  293. val2 = (cpu_to_le16(entry_value) >> 8) & 0xf;
  294. ((__u16 *)mydata->fatbuf)[off16] &= ~0xff00;
  295. ((__u16 *)mydata->fatbuf)[off16] |= (val1 << 8);
  296. ((__u16 *)mydata->fatbuf)[off16 + 1] &= ~0xf;
  297. ((__u16 *)mydata->fatbuf)[off16 + 1] |= val2;
  298. break;
  299. case 3:
  300. val1 = cpu_to_le16(entry_value) & 0xfff;
  301. ((__u16 *)mydata->fatbuf)[off16] &= ~0xfff0;
  302. ((__u16 *)mydata->fatbuf)[off16] |= (val1 << 4);
  303. break;
  304. default:
  305. break;
  306. }
  307. break;
  308. default:
  309. return -1;
  310. }
  311. return 0;
  312. }
  313. /*
  314. * Determine the next free cluster after 'entry' in a FAT (12/16/32) table
  315. * and link it to 'entry'. EOC marker is not set on returned entry.
  316. */
  317. static __u32 determine_fatent(fsdata *mydata, __u32 entry)
  318. {
  319. __u32 next_fat, next_entry = entry + 1;
  320. while (1) {
  321. next_fat = get_fatent(mydata, next_entry);
  322. if (next_fat == 0) {
  323. /* found free entry, link to entry */
  324. set_fatent_value(mydata, entry, next_entry);
  325. break;
  326. }
  327. next_entry++;
  328. }
  329. debug("FAT%d: entry: %08x, entry_value: %04x\n",
  330. mydata->fatsize, entry, next_entry);
  331. return next_entry;
  332. }
  333. /*
  334. * Write at most 'size' bytes from 'buffer' into the specified cluster.
  335. * Return 0 on success, -1 otherwise.
  336. */
  337. static int
  338. set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer,
  339. unsigned long size)
  340. {
  341. __u32 idx = 0;
  342. __u32 startsect;
  343. int ret;
  344. if (clustnum > 0)
  345. startsect = clust_to_sect(mydata, clustnum);
  346. else
  347. startsect = mydata->rootdir_sect;
  348. debug("clustnum: %d, startsect: %d\n", clustnum, startsect);
  349. if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) {
  350. ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
  351. printf("FAT: Misaligned buffer address (%p)\n", buffer);
  352. while (size >= mydata->sect_size) {
  353. memcpy(tmpbuf, buffer, mydata->sect_size);
  354. ret = disk_write(startsect++, 1, tmpbuf);
  355. if (ret != 1) {
  356. debug("Error writing data (got %d)\n", ret);
  357. return -1;
  358. }
  359. buffer += mydata->sect_size;
  360. size -= mydata->sect_size;
  361. }
  362. } else if (size >= mydata->sect_size) {
  363. idx = size / mydata->sect_size;
  364. ret = disk_write(startsect, idx, buffer);
  365. if (ret != idx) {
  366. debug("Error writing data (got %d)\n", ret);
  367. return -1;
  368. }
  369. startsect += idx;
  370. idx *= mydata->sect_size;
  371. buffer += idx;
  372. size -= idx;
  373. }
  374. if (size) {
  375. ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
  376. memcpy(tmpbuf, buffer, size);
  377. ret = disk_write(startsect, 1, tmpbuf);
  378. if (ret != 1) {
  379. debug("Error writing data (got %d)\n", ret);
  380. return -1;
  381. }
  382. }
  383. return 0;
  384. }
  385. static __u8 tmpbuf_cluster[MAX_CLUSTSIZE] __aligned(ARCH_DMA_MINALIGN);
  386. /*
  387. * Read and modify data on existing and consecutive cluster blocks
  388. */
  389. static int
  390. get_set_cluster(fsdata *mydata, __u32 clustnum, loff_t pos, __u8 *buffer,
  391. loff_t size, loff_t *gotsize)
  392. {
  393. unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
  394. __u32 startsect;
  395. loff_t wsize;
  396. int clustcount, i, ret;
  397. *gotsize = 0;
  398. if (!size)
  399. return 0;
  400. assert(pos < bytesperclust);
  401. startsect = clust_to_sect(mydata, clustnum);
  402. debug("clustnum: %d, startsect: %d, pos: %lld\n",
  403. clustnum, startsect, pos);
  404. /* partial write at beginning */
  405. if (pos) {
  406. wsize = min(bytesperclust - pos, size);
  407. ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
  408. if (ret != mydata->clust_size) {
  409. debug("Error reading data (got %d)\n", ret);
  410. return -1;
  411. }
  412. memcpy(tmpbuf_cluster + pos, buffer, wsize);
  413. ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);
  414. if (ret != mydata->clust_size) {
  415. debug("Error writing data (got %d)\n", ret);
  416. return -1;
  417. }
  418. size -= wsize;
  419. buffer += wsize;
  420. *gotsize += wsize;
  421. startsect += mydata->clust_size;
  422. if (!size)
  423. return 0;
  424. }
  425. /* full-cluster write */
  426. if (size >= bytesperclust) {
  427. clustcount = lldiv(size, bytesperclust);
  428. if (!((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1))) {
  429. wsize = clustcount * bytesperclust;
  430. ret = disk_write(startsect,
  431. clustcount * mydata->clust_size,
  432. buffer);
  433. if (ret != clustcount * mydata->clust_size) {
  434. debug("Error writing data (got %d)\n", ret);
  435. return -1;
  436. }
  437. size -= wsize;
  438. buffer += wsize;
  439. *gotsize += wsize;
  440. startsect += clustcount * mydata->clust_size;
  441. } else {
  442. for (i = 0; i < clustcount; i++) {
  443. memcpy(tmpbuf_cluster, buffer, bytesperclust);
  444. ret = disk_write(startsect,
  445. mydata->clust_size,
  446. tmpbuf_cluster);
  447. if (ret != mydata->clust_size) {
  448. debug("Error writing data (got %d)\n",
  449. ret);
  450. return -1;
  451. }
  452. size -= bytesperclust;
  453. buffer += bytesperclust;
  454. *gotsize += bytesperclust;
  455. startsect += mydata->clust_size;
  456. }
  457. }
  458. }
  459. /* partial write at end */
  460. if (size) {
  461. wsize = size;
  462. ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
  463. if (ret != mydata->clust_size) {
  464. debug("Error reading data (got %d)\n", ret);
  465. return -1;
  466. }
  467. memcpy(tmpbuf_cluster, buffer, wsize);
  468. ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);
  469. if (ret != mydata->clust_size) {
  470. debug("Error writing data (got %d)\n", ret);
  471. return -1;
  472. }
  473. size -= wsize;
  474. buffer += wsize;
  475. *gotsize += wsize;
  476. }
  477. assert(!size);
  478. return 0;
  479. }
  480. /*
  481. * Find the first empty cluster
  482. */
  483. static int find_empty_cluster(fsdata *mydata)
  484. {
  485. __u32 fat_val, entry = 3;
  486. while (1) {
  487. fat_val = get_fatent(mydata, entry);
  488. if (fat_val == 0)
  489. break;
  490. entry++;
  491. }
  492. return entry;
  493. }
  494. /*
  495. * Write directory entries in itr's buffer to block device
  496. */
  497. static int flush_dir_table(fat_itr *itr)
  498. {
  499. fsdata *mydata = itr->fsdata;
  500. int dir_newclust = 0;
  501. unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
  502. if (set_cluster(mydata, itr->clust, itr->block, bytesperclust) != 0) {
  503. printf("error: writing directory entry\n");
  504. return -1;
  505. }
  506. dir_newclust = find_empty_cluster(mydata);
  507. set_fatent_value(mydata, itr->clust, dir_newclust);
  508. if (mydata->fatsize == 32)
  509. set_fatent_value(mydata, dir_newclust, 0xffffff8);
  510. else if (mydata->fatsize == 16)
  511. set_fatent_value(mydata, dir_newclust, 0xfff8);
  512. else if (mydata->fatsize == 12)
  513. set_fatent_value(mydata, dir_newclust, 0xff8);
  514. itr->clust = dir_newclust;
  515. itr->next_clust = dir_newclust;
  516. if (flush_dirty_fat_buffer(mydata) < 0)
  517. return -1;
  518. memset(itr->block, 0x00, bytesperclust);
  519. itr->dent = (dir_entry *)itr->block;
  520. itr->last_cluster = 1;
  521. itr->remaining = bytesperclust / sizeof(dir_entry) - 1;
  522. return 0;
  523. }
  524. /*
  525. * Set empty cluster from 'entry' to the end of a file
  526. */
  527. static int clear_fatent(fsdata *mydata, __u32 entry)
  528. {
  529. __u32 fat_val;
  530. while (!CHECK_CLUST(entry, mydata->fatsize)) {
  531. fat_val = get_fatent(mydata, entry);
  532. if (fat_val != 0)
  533. set_fatent_value(mydata, entry, 0);
  534. else
  535. break;
  536. entry = fat_val;
  537. }
  538. /* Flush fat buffer */
  539. if (flush_dirty_fat_buffer(mydata) < 0)
  540. return -1;
  541. return 0;
  542. }
  543. /*
  544. * Set start cluster in directory entry
  545. */
  546. static void set_start_cluster(const fsdata *mydata, dir_entry *dentptr,
  547. __u32 start_cluster)
  548. {
  549. if (mydata->fatsize == 32)
  550. dentptr->starthi =
  551. cpu_to_le16((start_cluster & 0xffff0000) >> 16);
  552. dentptr->start = cpu_to_le16(start_cluster & 0xffff);
  553. }
  554. /*
  555. * Check whether adding a file makes the file system to
  556. * exceed the size of the block device
  557. * Return -1 when overflow occurs, otherwise return 0
  558. */
  559. static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size)
  560. {
  561. __u32 startsect, sect_num, offset;
  562. if (clustnum > 0)
  563. startsect = clust_to_sect(mydata, clustnum);
  564. else
  565. startsect = mydata->rootdir_sect;
  566. sect_num = div_u64_rem(size, mydata->sect_size, &offset);
  567. if (offset != 0)
  568. sect_num++;
  569. if (startsect + sect_num > total_sector)
  570. return -1;
  571. return 0;
  572. }
  573. /*
  574. * Write at most 'maxsize' bytes from 'buffer' into
  575. * the file associated with 'dentptr'
  576. * Update the number of bytes written in *gotsize and return 0
  577. * or return -1 on fatal errors.
  578. */
  579. static int
  580. set_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, __u8 *buffer,
  581. loff_t maxsize, loff_t *gotsize)
  582. {
  583. loff_t filesize;
  584. unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
  585. __u32 curclust = START(dentptr);
  586. __u32 endclust = 0, newclust = 0;
  587. loff_t cur_pos, offset, actsize, wsize;
  588. *gotsize = 0;
  589. filesize = pos + maxsize;
  590. debug("%llu bytes\n", filesize);
  591. if (!filesize) {
  592. if (!curclust)
  593. return 0;
  594. if (!CHECK_CLUST(curclust, mydata->fatsize) ||
  595. IS_LAST_CLUST(curclust, mydata->fatsize)) {
  596. clear_fatent(mydata, curclust);
  597. set_start_cluster(mydata, dentptr, 0);
  598. return 0;
  599. }
  600. debug("curclust: 0x%x\n", curclust);
  601. debug("Invalid FAT entry\n");
  602. return -1;
  603. }
  604. if (!curclust) {
  605. assert(pos == 0);
  606. goto set_clusters;
  607. }
  608. /* go to cluster at pos */
  609. cur_pos = bytesperclust;
  610. while (1) {
  611. if (pos <= cur_pos)
  612. break;
  613. if (IS_LAST_CLUST(curclust, mydata->fatsize))
  614. break;
  615. newclust = get_fatent(mydata, curclust);
  616. if (!IS_LAST_CLUST(newclust, mydata->fatsize) &&
  617. CHECK_CLUST(newclust, mydata->fatsize)) {
  618. debug("curclust: 0x%x\n", curclust);
  619. debug("Invalid FAT entry\n");
  620. return -1;
  621. }
  622. cur_pos += bytesperclust;
  623. curclust = newclust;
  624. }
  625. if (IS_LAST_CLUST(curclust, mydata->fatsize)) {
  626. assert(pos == cur_pos);
  627. goto set_clusters;
  628. }
  629. assert(pos < cur_pos);
  630. cur_pos -= bytesperclust;
  631. /* overwrite */
  632. assert(IS_LAST_CLUST(curclust, mydata->fatsize) ||
  633. !CHECK_CLUST(curclust, mydata->fatsize));
  634. while (1) {
  635. /* search for allocated consecutive clusters */
  636. actsize = bytesperclust;
  637. endclust = curclust;
  638. while (1) {
  639. if (filesize <= (cur_pos + actsize))
  640. break;
  641. newclust = get_fatent(mydata, endclust);
  642. if (IS_LAST_CLUST(newclust, mydata->fatsize))
  643. break;
  644. if (CHECK_CLUST(newclust, mydata->fatsize)) {
  645. debug("curclust: 0x%x\n", curclust);
  646. debug("Invalid FAT entry\n");
  647. return -1;
  648. }
  649. actsize += bytesperclust;
  650. endclust = newclust;
  651. }
  652. /* overwrite to <curclust..endclust> */
  653. if (pos < cur_pos)
  654. offset = 0;
  655. else
  656. offset = pos - cur_pos;
  657. wsize = min(cur_pos + actsize, filesize) - pos;
  658. if (get_set_cluster(mydata, curclust, offset,
  659. buffer, wsize, &actsize)) {
  660. printf("Error get-and-setting cluster\n");
  661. return -1;
  662. }
  663. buffer += wsize;
  664. *gotsize += wsize;
  665. cur_pos += offset + wsize;
  666. if (filesize <= cur_pos)
  667. break;
  668. /* CHECK: newclust = get_fatent(mydata, endclust); */
  669. if (IS_LAST_CLUST(newclust, mydata->fatsize))
  670. /* no more clusters */
  671. break;
  672. curclust = newclust;
  673. }
  674. if (filesize <= cur_pos) {
  675. /* no more write */
  676. newclust = get_fatent(mydata, endclust);
  677. if (!IS_LAST_CLUST(newclust, mydata->fatsize)) {
  678. /* truncate the rest */
  679. clear_fatent(mydata, newclust);
  680. /* Mark end of file in FAT */
  681. if (mydata->fatsize == 12)
  682. newclust = 0xfff;
  683. else if (mydata->fatsize == 16)
  684. newclust = 0xffff;
  685. else if (mydata->fatsize == 32)
  686. newclust = 0xfffffff;
  687. set_fatent_value(mydata, endclust, newclust);
  688. }
  689. return 0;
  690. }
  691. curclust = endclust;
  692. filesize -= cur_pos;
  693. assert(!(cur_pos % bytesperclust));
  694. set_clusters:
  695. /* allocate and write */
  696. assert(!pos);
  697. /* Assure that curclust is valid */
  698. if (!curclust) {
  699. curclust = find_empty_cluster(mydata);
  700. set_start_cluster(mydata, dentptr, curclust);
  701. } else {
  702. newclust = get_fatent(mydata, curclust);
  703. if (IS_LAST_CLUST(newclust, mydata->fatsize)) {
  704. newclust = determine_fatent(mydata, curclust);
  705. set_fatent_value(mydata, curclust, newclust);
  706. curclust = newclust;
  707. } else {
  708. debug("error: something wrong\n");
  709. return -1;
  710. }
  711. }
  712. /* TODO: already partially written */
  713. if (check_overflow(mydata, curclust, filesize)) {
  714. printf("Error: no space left: %llu\n", filesize);
  715. return -1;
  716. }
  717. actsize = bytesperclust;
  718. endclust = curclust;
  719. do {
  720. /* search for consecutive clusters */
  721. while (actsize < filesize) {
  722. newclust = determine_fatent(mydata, endclust);
  723. if ((newclust - 1) != endclust)
  724. /* write to <curclust..endclust> */
  725. goto getit;
  726. if (CHECK_CLUST(newclust, mydata->fatsize)) {
  727. debug("newclust: 0x%x\n", newclust);
  728. debug("Invalid FAT entry\n");
  729. return 0;
  730. }
  731. endclust = newclust;
  732. actsize += bytesperclust;
  733. }
  734. /* set remaining bytes */
  735. actsize = filesize;
  736. if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
  737. debug("error: writing cluster\n");
  738. return -1;
  739. }
  740. *gotsize += actsize;
  741. /* Mark end of file in FAT */
  742. if (mydata->fatsize == 12)
  743. newclust = 0xfff;
  744. else if (mydata->fatsize == 16)
  745. newclust = 0xffff;
  746. else if (mydata->fatsize == 32)
  747. newclust = 0xfffffff;
  748. set_fatent_value(mydata, endclust, newclust);
  749. return 0;
  750. getit:
  751. if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
  752. debug("error: writing cluster\n");
  753. return -1;
  754. }
  755. *gotsize += actsize;
  756. filesize -= actsize;
  757. buffer += actsize;
  758. if (CHECK_CLUST(newclust, mydata->fatsize)) {
  759. debug("newclust: 0x%x\n", newclust);
  760. debug("Invalid FAT entry\n");
  761. return 0;
  762. }
  763. actsize = bytesperclust;
  764. curclust = endclust = newclust;
  765. } while (1);
  766. return 0;
  767. }
  768. /*
  769. * Fill dir_entry
  770. */
  771. static void fill_dentry(fsdata *mydata, dir_entry *dentptr,
  772. const char *filename, __u32 start_cluster, __u32 size, __u8 attr)
  773. {
  774. set_start_cluster(mydata, dentptr, start_cluster);
  775. dentptr->size = cpu_to_le32(size);
  776. dentptr->attr = attr;
  777. set_name(dentptr, filename);
  778. }
  779. /*
  780. * Find a directory entry based on filename or start cluster number
  781. * If the directory entry is not found,
  782. * the new position for writing a directory entry will be returned
  783. */
  784. static dir_entry *find_directory_entry(fat_itr *itr, char *filename)
  785. {
  786. int match = 0;
  787. while (fat_itr_next(itr)) {
  788. /* check both long and short name: */
  789. if (!strcasecmp(filename, itr->name))
  790. match = 1;
  791. else if (itr->name != itr->s_name &&
  792. !strcasecmp(filename, itr->s_name))
  793. match = 1;
  794. if (!match)
  795. continue;
  796. if (itr->dent->name[0] == '\0')
  797. return NULL;
  798. else
  799. return itr->dent;
  800. }
  801. if (!itr->dent && !itr->is_root && flush_dir_table(itr))
  802. /* indicate that allocating dent failed */
  803. itr->dent = NULL;
  804. return NULL;
  805. }
  806. static int split_filename(char *filename, char **dirname, char **basename)
  807. {
  808. char *p, *last_slash, *last_slash_cont;
  809. again:
  810. p = filename;
  811. last_slash = NULL;
  812. last_slash_cont = NULL;
  813. while (*p) {
  814. if (ISDIRDELIM(*p)) {
  815. last_slash = p;
  816. last_slash_cont = p;
  817. /* continuous slashes */
  818. while (ISDIRDELIM(*p))
  819. last_slash_cont = p++;
  820. if (!*p)
  821. break;
  822. }
  823. p++;
  824. }
  825. if (last_slash) {
  826. if (last_slash_cont == (filename + strlen(filename) - 1)) {
  827. /* remove trailing slashes */
  828. *last_slash = '\0';
  829. goto again;
  830. }
  831. if (last_slash == filename) {
  832. /* avoid ""(null) directory */
  833. *dirname = "/";
  834. } else {
  835. *last_slash = '\0';
  836. *dirname = filename;
  837. }
  838. *last_slash_cont = '\0';
  839. *basename = last_slash_cont + 1;
  840. } else {
  841. *dirname = "/"; /* root by default */
  842. *basename = filename;
  843. }
  844. return 0;
  845. }
  846. static int normalize_longname(char *l_filename, const char *filename)
  847. {
  848. const char *p, legal[] = "!#$%&\'()-.@^`_{}~";
  849. char c;
  850. int name_len;
  851. /* Check that the filename is valid */
  852. for (p = filename; p < filename + strlen(filename); p++) {
  853. c = *p;
  854. if (('0' <= c) && (c <= '9'))
  855. continue;
  856. if (('A' <= c) && (c <= 'Z'))
  857. continue;
  858. if (('a' <= c) && (c <= 'z'))
  859. continue;
  860. if (strchr(legal, c))
  861. continue;
  862. /* extended code */
  863. if ((0x80 <= c) && (c <= 0xff))
  864. continue;
  865. return -1;
  866. }
  867. /* Normalize it */
  868. name_len = strlen(filename);
  869. if (name_len >= VFAT_MAXLEN_BYTES)
  870. /* should return an error? */
  871. name_len = VFAT_MAXLEN_BYTES - 1;
  872. memcpy(l_filename, filename, name_len);
  873. l_filename[name_len] = 0; /* terminate the string */
  874. downcase(l_filename, INT_MAX);
  875. return 0;
  876. }
  877. int file_fat_write_at(const char *filename, loff_t pos, void *buffer,
  878. loff_t size, loff_t *actwrite)
  879. {
  880. dir_entry *retdent;
  881. fsdata datablock = { .fatbuf = NULL, };
  882. fsdata *mydata = &datablock;
  883. fat_itr *itr = NULL;
  884. int ret = -1;
  885. char *filename_copy, *parent, *basename;
  886. char l_filename[VFAT_MAXLEN_BYTES];
  887. debug("writing %s\n", filename);
  888. filename_copy = strdup(filename);
  889. if (!filename_copy)
  890. return -ENOMEM;
  891. split_filename(filename_copy, &parent, &basename);
  892. if (!strlen(basename)) {
  893. ret = -EINVAL;
  894. goto exit;
  895. }
  896. filename = basename;
  897. if (normalize_longname(l_filename, filename)) {
  898. printf("FAT: illegal filename (%s)\n", filename);
  899. ret = -EINVAL;
  900. goto exit;
  901. }
  902. itr = malloc_cache_aligned(sizeof(fat_itr));
  903. if (!itr) {
  904. ret = -ENOMEM;
  905. goto exit;
  906. }
  907. ret = fat_itr_root(itr, &datablock);
  908. if (ret)
  909. goto exit;
  910. total_sector = datablock.total_sect;
  911. ret = fat_itr_resolve(itr, parent, TYPE_DIR);
  912. if (ret) {
  913. printf("%s: doesn't exist (%d)\n", parent, ret);
  914. goto exit;
  915. }
  916. retdent = find_directory_entry(itr, l_filename);
  917. if (retdent) {
  918. if (fat_itr_isdir(itr)) {
  919. ret = -EISDIR;
  920. goto exit;
  921. }
  922. /* A file exists */
  923. if (pos == -1)
  924. /* Append to the end */
  925. pos = FAT2CPU32(retdent->size);
  926. if (pos > retdent->size) {
  927. /* No hole allowed */
  928. ret = -EINVAL;
  929. goto exit;
  930. }
  931. /* Update file size in a directory entry */
  932. retdent->size = cpu_to_le32(pos + size);
  933. } else {
  934. /* Create a new file */
  935. if (itr->is_root) {
  936. /* root dir cannot have "." or ".." */
  937. if (!strcmp(l_filename, ".") ||
  938. !strcmp(l_filename, "..")) {
  939. ret = -EINVAL;
  940. goto exit;
  941. }
  942. }
  943. if (!itr->dent) {
  944. printf("Error: allocating new dir entry\n");
  945. ret = -EIO;
  946. goto exit;
  947. }
  948. if (pos) {
  949. /* No hole allowed */
  950. ret = -EINVAL;
  951. goto exit;
  952. }
  953. memset(itr->dent, 0, sizeof(*itr->dent));
  954. /* Set short name to set alias checksum field in dir_slot */
  955. set_name(itr->dent, filename);
  956. if (fill_dir_slot(itr, filename)) {
  957. ret = -EIO;
  958. goto exit;
  959. }
  960. /* Set attribute as archive for regular file */
  961. fill_dentry(itr->fsdata, itr->dent, filename, 0, size, 0x20);
  962. retdent = itr->dent;
  963. }
  964. ret = set_contents(mydata, retdent, pos, buffer, size, actwrite);
  965. if (ret < 0) {
  966. printf("Error: writing contents\n");
  967. ret = -EIO;
  968. goto exit;
  969. }
  970. debug("attempt to write 0x%llx bytes\n", *actwrite);
  971. /* Flush fat buffer */
  972. ret = flush_dirty_fat_buffer(mydata);
  973. if (ret) {
  974. printf("Error: flush fat buffer\n");
  975. ret = -EIO;
  976. goto exit;
  977. }
  978. /* Write directory table to device */
  979. ret = set_cluster(mydata, itr->clust, itr->block,
  980. mydata->clust_size * mydata->sect_size);
  981. if (ret) {
  982. printf("Error: writing directory entry\n");
  983. ret = -EIO;
  984. }
  985. exit:
  986. free(filename_copy);
  987. free(mydata->fatbuf);
  988. free(itr);
  989. return ret;
  990. }
  991. int file_fat_write(const char *filename, void *buffer, loff_t offset,
  992. loff_t maxsize, loff_t *actwrite)
  993. {
  994. return file_fat_write_at(filename, offset, buffer, maxsize, actwrite);
  995. }
  996. static int fat_dir_entries(fat_itr *itr)
  997. {
  998. fat_itr *dirs;
  999. fsdata fsdata = { .fatbuf = NULL, }, *mydata = &fsdata;
  1000. /* for FATBUFSIZE */
  1001. int count;
  1002. dirs = malloc_cache_aligned(sizeof(fat_itr));
  1003. if (!dirs) {
  1004. debug("Error: allocating memory\n");
  1005. count = -ENOMEM;
  1006. goto exit;
  1007. }
  1008. /* duplicate fsdata */
  1009. fat_itr_child(dirs, itr);
  1010. fsdata = *dirs->fsdata;
  1011. /* allocate local fat buffer */
  1012. fsdata.fatbuf = malloc_cache_aligned(FATBUFSIZE);
  1013. if (!fsdata.fatbuf) {
  1014. debug("Error: allocating memory\n");
  1015. count = -ENOMEM;
  1016. goto exit;
  1017. }
  1018. fsdata.fatbufnum = -1;
  1019. dirs->fsdata = &fsdata;
  1020. for (count = 0; fat_itr_next(dirs); count++)
  1021. ;
  1022. exit:
  1023. free(fsdata.fatbuf);
  1024. free(dirs);
  1025. return count;
  1026. }
  1027. static int delete_dentry(fat_itr *itr)
  1028. {
  1029. fsdata *mydata = itr->fsdata;
  1030. dir_entry *dentptr = itr->dent;
  1031. /* free cluster blocks */
  1032. clear_fatent(mydata, START(dentptr));
  1033. if (flush_dirty_fat_buffer(mydata) < 0) {
  1034. printf("Error: flush fat buffer\n");
  1035. return -EIO;
  1036. }
  1037. /*
  1038. * update a directory entry
  1039. * TODO:
  1040. * - long file name support
  1041. * - find and mark the "new" first invalid entry as name[0]=0x00
  1042. */
  1043. memset(dentptr, 0, sizeof(*dentptr));
  1044. dentptr->name[0] = 0xe5;
  1045. if (set_cluster(mydata, itr->clust, itr->block,
  1046. mydata->clust_size * mydata->sect_size) != 0) {
  1047. printf("error: writing directory entry\n");
  1048. return -EIO;
  1049. }
  1050. return 0;
  1051. }
  1052. int fat_unlink(const char *filename)
  1053. {
  1054. fsdata fsdata = { .fatbuf = NULL, };
  1055. fat_itr *itr = NULL;
  1056. int n_entries, ret;
  1057. char *filename_copy, *dirname, *basename;
  1058. filename_copy = strdup(filename);
  1059. split_filename(filename_copy, &dirname, &basename);
  1060. if (!strcmp(dirname, "/") && !strcmp(basename, "")) {
  1061. printf("Error: cannot remove root\n");
  1062. ret = -EINVAL;
  1063. goto exit;
  1064. }
  1065. itr = malloc_cache_aligned(sizeof(fat_itr));
  1066. if (!itr) {
  1067. printf("Error: allocating memory\n");
  1068. return -ENOMEM;
  1069. }
  1070. ret = fat_itr_root(itr, &fsdata);
  1071. if (ret)
  1072. goto exit;
  1073. total_sector = fsdata.total_sect;
  1074. ret = fat_itr_resolve(itr, dirname, TYPE_DIR);
  1075. if (ret) {
  1076. printf("%s: doesn't exist (%d)\n", dirname, ret);
  1077. ret = -ENOENT;
  1078. goto exit;
  1079. }
  1080. if (!find_directory_entry(itr, basename)) {
  1081. printf("%s: doesn't exist\n", basename);
  1082. ret = -ENOENT;
  1083. goto exit;
  1084. }
  1085. if (fat_itr_isdir(itr)) {
  1086. n_entries = fat_dir_entries(itr);
  1087. if (n_entries < 0) {
  1088. ret = n_entries;
  1089. goto exit;
  1090. }
  1091. if (n_entries > 2) {
  1092. printf("Error: directory is not empty: %d\n",
  1093. n_entries);
  1094. ret = -EINVAL;
  1095. goto exit;
  1096. }
  1097. }
  1098. ret = delete_dentry(itr);
  1099. exit:
  1100. free(fsdata.fatbuf);
  1101. free(itr);
  1102. free(filename_copy);
  1103. return ret;
  1104. }
  1105. int fat_mkdir(const char *new_dirname)
  1106. {
  1107. dir_entry *retdent;
  1108. fsdata datablock = { .fatbuf = NULL, };
  1109. fsdata *mydata = &datablock;
  1110. fat_itr *itr = NULL;
  1111. char *dirname_copy, *parent, *dirname;
  1112. char l_dirname[VFAT_MAXLEN_BYTES];
  1113. int ret = -1;
  1114. loff_t actwrite;
  1115. unsigned int bytesperclust;
  1116. dir_entry *dotdent = NULL;
  1117. dirname_copy = strdup(new_dirname);
  1118. if (!dirname_copy)
  1119. goto exit;
  1120. split_filename(dirname_copy, &parent, &dirname);
  1121. if (!strlen(dirname)) {
  1122. ret = -EINVAL;
  1123. goto exit;
  1124. }
  1125. if (normalize_longname(l_dirname, dirname)) {
  1126. printf("FAT: illegal filename (%s)\n", dirname);
  1127. ret = -EINVAL;
  1128. goto exit;
  1129. }
  1130. itr = malloc_cache_aligned(sizeof(fat_itr));
  1131. if (!itr) {
  1132. ret = -ENOMEM;
  1133. goto exit;
  1134. }
  1135. ret = fat_itr_root(itr, &datablock);
  1136. if (ret)
  1137. goto exit;
  1138. total_sector = datablock.total_sect;
  1139. ret = fat_itr_resolve(itr, parent, TYPE_DIR);
  1140. if (ret) {
  1141. printf("%s: doesn't exist (%d)\n", parent, ret);
  1142. goto exit;
  1143. }
  1144. retdent = find_directory_entry(itr, l_dirname);
  1145. if (retdent) {
  1146. printf("%s: already exists\n", l_dirname);
  1147. ret = -EEXIST;
  1148. goto exit;
  1149. } else {
  1150. if (itr->is_root) {
  1151. /* root dir cannot have "." or ".." */
  1152. if (!strcmp(l_dirname, ".") ||
  1153. !strcmp(l_dirname, "..")) {
  1154. ret = -EINVAL;
  1155. goto exit;
  1156. }
  1157. }
  1158. if (!itr->dent) {
  1159. printf("Error: allocating new dir entry\n");
  1160. ret = -EIO;
  1161. goto exit;
  1162. }
  1163. memset(itr->dent, 0, sizeof(*itr->dent));
  1164. /* Set short name to set alias checksum field in dir_slot */
  1165. set_name(itr->dent, dirname);
  1166. fill_dir_slot(itr, dirname);
  1167. /* Set attribute as archive for regular file */
  1168. fill_dentry(itr->fsdata, itr->dent, dirname, 0, 0,
  1169. ATTR_DIR | ATTR_ARCH);
  1170. retdent = itr->dent;
  1171. }
  1172. /* Default entries */
  1173. bytesperclust = mydata->clust_size * mydata->sect_size;
  1174. dotdent = malloc_cache_aligned(bytesperclust);
  1175. if (!dotdent) {
  1176. ret = -ENOMEM;
  1177. goto exit;
  1178. }
  1179. memset(dotdent, 0, bytesperclust);
  1180. memcpy(dotdent[0].name, ". ", 8);
  1181. memcpy(dotdent[0].ext, " ", 3);
  1182. dotdent[0].attr = ATTR_DIR | ATTR_ARCH;
  1183. memcpy(dotdent[1].name, ".. ", 8);
  1184. memcpy(dotdent[1].ext, " ", 3);
  1185. dotdent[1].attr = ATTR_DIR | ATTR_ARCH;
  1186. set_start_cluster(mydata, &dotdent[1], itr->start_clust);
  1187. ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent,
  1188. bytesperclust, &actwrite);
  1189. if (ret < 0) {
  1190. printf("Error: writing contents\n");
  1191. goto exit;
  1192. }
  1193. /* Write twice for "." */
  1194. set_start_cluster(mydata, &dotdent[0], START(retdent));
  1195. ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent,
  1196. bytesperclust, &actwrite);
  1197. if (ret < 0) {
  1198. printf("Error: writing contents\n");
  1199. goto exit;
  1200. }
  1201. /* Flush fat buffer */
  1202. ret = flush_dirty_fat_buffer(mydata);
  1203. if (ret) {
  1204. printf("Error: flush fat buffer\n");
  1205. goto exit;
  1206. }
  1207. /* Write directory table to device */
  1208. ret = set_cluster(mydata, itr->clust, itr->block,
  1209. mydata->clust_size * mydata->sect_size);
  1210. if (ret)
  1211. printf("Error: writing directory entry\n");
  1212. exit:
  1213. free(dirname_copy);
  1214. free(mydata->fatbuf);
  1215. free(itr);
  1216. free(dotdent);
  1217. return ret;
  1218. }