fat_write.c 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773
  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 <div64.h>
  11. #include <fat.h>
  12. #include <log.h>
  13. #include <malloc.h>
  14. #include <part.h>
  15. #include <rand.h>
  16. #include <asm/byteorder.h>
  17. #include <asm/cache.h>
  18. #include <linux/ctype.h>
  19. #include <linux/math64.h>
  20. #include "fat.c"
  21. static dir_entry *find_directory_entry(fat_itr *itr, char *filename);
  22. static int new_dir_table(fat_itr *itr);
  23. /* Characters that may only be used in long file names */
  24. static const char LONG_ONLY_CHARS[] = "+,;=[]";
  25. /* Combined size of the name and ext fields in the directory entry */
  26. #define SHORT_NAME_SIZE 11
  27. /**
  28. * str2fat() - convert string to valid FAT name characters
  29. *
  30. * Stop when reaching end of @src or a period.
  31. * Ignore spaces.
  32. * Replace characters that may only be used in long names by underscores.
  33. * Convert lower case characters to upper case.
  34. *
  35. * To avoid assumptions about the code page we do not use characters
  36. * above 0x7f for the short name.
  37. *
  38. * @dest: destination buffer
  39. * @src: source buffer
  40. * @length: size of destination buffer
  41. * Return: number of bytes in destination buffer
  42. */
  43. static int str2fat(char *dest, char *src, int length)
  44. {
  45. int i;
  46. for (i = 0; i < length; ++src) {
  47. char c = *src;
  48. if (!c || c == '.')
  49. break;
  50. if (c == ' ')
  51. continue;
  52. if (strchr(LONG_ONLY_CHARS, c) || c > 0x7f)
  53. c = '_';
  54. else if (c >= 'a' && c <= 'z')
  55. c &= 0xdf;
  56. dest[i] = c;
  57. ++i;
  58. }
  59. return i;
  60. }
  61. /**
  62. * fat_move_to_cluster() - position to first directory entry in cluster
  63. *
  64. * @itr: directory iterator
  65. * @cluster cluster
  66. * Return: 0 for success, -EIO on error
  67. */
  68. static int fat_move_to_cluster(fat_itr *itr, unsigned int cluster)
  69. {
  70. unsigned int nbytes;
  71. /* position to the start of the directory */
  72. itr->next_clust = cluster;
  73. itr->last_cluster = 0;
  74. if (!fat_next_cluster(itr, &nbytes))
  75. return -EIO;
  76. itr->dent = (dir_entry *)itr->block;
  77. itr->remaining = nbytes / sizeof(dir_entry) - 1;
  78. return 0;
  79. }
  80. /**
  81. * set_name() - set short name in directory entry
  82. *
  83. * The function determines if the @filename is a valid short name.
  84. * In this case no long name is needed.
  85. *
  86. * If a long name is needed, a short name is constructed.
  87. *
  88. * @itr: directory iterator
  89. * @filename: long file name
  90. * @shortname: buffer of 11 bytes to receive chosen short name and extension
  91. * Return: number of directory entries needed, negative on error
  92. */
  93. static int set_name(fat_itr *itr, const char *filename, char *shortname)
  94. {
  95. char *period;
  96. char *pos;
  97. int period_location;
  98. char buf[13];
  99. int i;
  100. int ret;
  101. struct nameext dirent;
  102. if (!filename)
  103. return -EIO;
  104. /* Initialize buffer */
  105. memset(&dirent, ' ', sizeof(dirent));
  106. /* Convert filename to upper case short name */
  107. period = strrchr(filename, '.');
  108. pos = (char *)filename;
  109. if (*pos == '.') {
  110. pos = period + 1;
  111. period = 0;
  112. }
  113. if (period)
  114. str2fat(dirent.ext, period + 1, sizeof(dirent.ext));
  115. period_location = str2fat(dirent.name, pos, sizeof(dirent.name));
  116. if (period_location < 0)
  117. return period_location;
  118. if (*dirent.name == ' ')
  119. *dirent.name = '_';
  120. /* 0xe5 signals a deleted directory entry. Replace it by 0x05. */
  121. if (*dirent.name == 0xe5)
  122. *dirent.name = 0x05;
  123. /* If filename and short name are the same, quit. */
  124. sprintf(buf, "%.*s.%.3s", period_location, dirent.name, dirent.ext);
  125. if (!strcmp(buf, filename)) {
  126. ret = 1;
  127. goto out;
  128. }
  129. /* Construct an indexed short name */
  130. for (i = 1; i < 0x200000; ++i) {
  131. int suffix_len;
  132. int suffix_start;
  133. int j;
  134. /* To speed up the search use random numbers */
  135. if (i < 10) {
  136. j = i;
  137. } else {
  138. j = 30 - fls(i);
  139. j = 10 + (rand() >> j);
  140. }
  141. sprintf(buf, "~%d", j);
  142. suffix_len = strlen(buf);
  143. suffix_start = 8 - suffix_len;
  144. if (suffix_start > period_location)
  145. suffix_start = period_location;
  146. memcpy(dirent.name + suffix_start, buf, suffix_len);
  147. if (*dirent.ext != ' ')
  148. sprintf(buf, "%.*s.%.3s", suffix_start + suffix_len,
  149. dirent.name, dirent.ext);
  150. else
  151. sprintf(buf, "%.*s", suffix_start + suffix_len,
  152. dirent.name);
  153. debug("generated short name: %s\n", buf);
  154. /* Check that the short name does not exist yet. */
  155. ret = fat_move_to_cluster(itr, itr->start_clust);
  156. if (ret)
  157. return ret;
  158. if (find_directory_entry(itr, buf))
  159. continue;
  160. debug("chosen short name: %s\n", buf);
  161. /* Each long name directory entry takes 13 characters. */
  162. ret = (strlen(filename) + 25) / 13;
  163. goto out;
  164. }
  165. return -EIO;
  166. out:
  167. memcpy(shortname, &dirent, SHORT_NAME_SIZE);
  168. return ret;
  169. }
  170. static int total_sector;
  171. static int disk_write(__u32 block, __u32 nr_blocks, void *buf)
  172. {
  173. ulong ret;
  174. if (!cur_dev)
  175. return -1;
  176. if (cur_part_info.start + block + nr_blocks >
  177. cur_part_info.start + total_sector) {
  178. printf("error: overflow occurs\n");
  179. return -1;
  180. }
  181. ret = blk_dwrite(cur_dev, cur_part_info.start + block, nr_blocks, buf);
  182. if (nr_blocks && ret == 0)
  183. return -1;
  184. return ret;
  185. }
  186. /*
  187. * Write fat buffer into block device
  188. */
  189. static int flush_dirty_fat_buffer(fsdata *mydata)
  190. {
  191. int getsize = FATBUFBLOCKS;
  192. __u32 fatlength = mydata->fatlength;
  193. __u8 *bufptr = mydata->fatbuf;
  194. __u32 startblock = mydata->fatbufnum * FATBUFBLOCKS;
  195. debug("debug: evicting %d, dirty: %d\n", mydata->fatbufnum,
  196. (int)mydata->fat_dirty);
  197. if ((!mydata->fat_dirty) || (mydata->fatbufnum == -1))
  198. return 0;
  199. /* Cap length if fatlength is not a multiple of FATBUFBLOCKS */
  200. if (startblock + getsize > fatlength)
  201. getsize = fatlength - startblock;
  202. startblock += mydata->fat_sect;
  203. /* Write FAT buf */
  204. if (disk_write(startblock, getsize, bufptr) < 0) {
  205. debug("error: writing FAT blocks\n");
  206. return -1;
  207. }
  208. if (mydata->fats == 2) {
  209. /* Update corresponding second FAT blocks */
  210. startblock += mydata->fatlength;
  211. if (disk_write(startblock, getsize, bufptr) < 0) {
  212. debug("error: writing second FAT blocks\n");
  213. return -1;
  214. }
  215. }
  216. mydata->fat_dirty = 0;
  217. return 0;
  218. }
  219. /**
  220. * fat_find_empty_dentries() - find a sequence of available directory entries
  221. *
  222. * @itr: directory iterator
  223. * @count: number of directory entries to find
  224. * Return: 0 on success or negative error number
  225. */
  226. static int fat_find_empty_dentries(fat_itr *itr, int count)
  227. {
  228. unsigned int cluster;
  229. dir_entry *dent;
  230. int remaining;
  231. unsigned int n = 0;
  232. int ret;
  233. ret = fat_move_to_cluster(itr, itr->start_clust);
  234. if (ret)
  235. return ret;
  236. for (;;) {
  237. if (!itr->dent) {
  238. log_debug("Not enough directory entries available\n");
  239. return -ENOSPC;
  240. }
  241. switch (itr->dent->nameext.name[0]) {
  242. case 0x00:
  243. case DELETED_FLAG:
  244. if (!n) {
  245. /* Remember first deleted directory entry */
  246. cluster = itr->clust;
  247. dent = itr->dent;
  248. remaining = itr->remaining;
  249. }
  250. ++n;
  251. if (n == count)
  252. goto out;
  253. break;
  254. default:
  255. n = 0;
  256. break;
  257. }
  258. next_dent(itr);
  259. if (!itr->dent &&
  260. (!itr->is_root || itr->fsdata->fatsize == 32) &&
  261. new_dir_table(itr))
  262. return -ENOSPC;
  263. }
  264. out:
  265. /* Position back to first directory entry */
  266. if (itr->clust != cluster) {
  267. ret = fat_move_to_cluster(itr, cluster);
  268. if (ret)
  269. return ret;
  270. }
  271. itr->dent = dent;
  272. itr->remaining = remaining;
  273. return 0;
  274. }
  275. /*
  276. * Set the file name information from 'name' into 'slotptr',
  277. */
  278. static int str2slot(dir_slot *slotptr, const char *name, int *idx)
  279. {
  280. int j, end_idx = 0;
  281. for (j = 0; j <= 8; j += 2) {
  282. if (name[*idx] == 0x00) {
  283. slotptr->name0_4[j] = 0;
  284. slotptr->name0_4[j + 1] = 0;
  285. end_idx++;
  286. goto name0_4;
  287. }
  288. slotptr->name0_4[j] = name[*idx];
  289. (*idx)++;
  290. end_idx++;
  291. }
  292. for (j = 0; j <= 10; j += 2) {
  293. if (name[*idx] == 0x00) {
  294. slotptr->name5_10[j] = 0;
  295. slotptr->name5_10[j + 1] = 0;
  296. end_idx++;
  297. goto name5_10;
  298. }
  299. slotptr->name5_10[j] = name[*idx];
  300. (*idx)++;
  301. end_idx++;
  302. }
  303. for (j = 0; j <= 2; j += 2) {
  304. if (name[*idx] == 0x00) {
  305. slotptr->name11_12[j] = 0;
  306. slotptr->name11_12[j + 1] = 0;
  307. end_idx++;
  308. goto name11_12;
  309. }
  310. slotptr->name11_12[j] = name[*idx];
  311. (*idx)++;
  312. end_idx++;
  313. }
  314. if (name[*idx] == 0x00)
  315. return 1;
  316. return 0;
  317. /* Not used characters are filled with 0xff 0xff */
  318. name0_4:
  319. for (; end_idx < 5; end_idx++) {
  320. slotptr->name0_4[end_idx * 2] = 0xff;
  321. slotptr->name0_4[end_idx * 2 + 1] = 0xff;
  322. }
  323. end_idx = 5;
  324. name5_10:
  325. end_idx -= 5;
  326. for (; end_idx < 6; end_idx++) {
  327. slotptr->name5_10[end_idx * 2] = 0xff;
  328. slotptr->name5_10[end_idx * 2 + 1] = 0xff;
  329. }
  330. end_idx = 11;
  331. name11_12:
  332. end_idx -= 11;
  333. for (; end_idx < 2; end_idx++) {
  334. slotptr->name11_12[end_idx * 2] = 0xff;
  335. slotptr->name11_12[end_idx * 2 + 1] = 0xff;
  336. }
  337. return 1;
  338. }
  339. static int flush_dir(fat_itr *itr);
  340. /**
  341. * fill_dir_slot() - fill directory entries for long name
  342. *
  343. * @itr: directory iterator
  344. * @l_name: long name
  345. * @shortname: short name
  346. * Return: 0 for success, -errno otherwise
  347. */
  348. static int
  349. fill_dir_slot(fat_itr *itr, const char *l_name, const char *shortname)
  350. {
  351. __u8 temp_dir_slot_buffer[MAX_LFN_SLOT * sizeof(dir_slot)];
  352. dir_slot *slotptr = (dir_slot *)temp_dir_slot_buffer;
  353. __u8 counter = 0, checksum;
  354. int idx = 0, ret;
  355. /* Get short file name checksum value */
  356. checksum = mkcksum((void *)shortname);
  357. do {
  358. memset(slotptr, 0x00, sizeof(dir_slot));
  359. ret = str2slot(slotptr, l_name, &idx);
  360. slotptr->id = ++counter;
  361. slotptr->attr = ATTR_VFAT;
  362. slotptr->alias_checksum = checksum;
  363. slotptr++;
  364. } while (ret == 0);
  365. slotptr--;
  366. slotptr->id |= LAST_LONG_ENTRY_MASK;
  367. while (counter >= 1) {
  368. memcpy(itr->dent, slotptr, sizeof(dir_slot));
  369. slotptr--;
  370. counter--;
  371. if (!itr->remaining) {
  372. /* Write directory table to device */
  373. ret = flush_dir(itr);
  374. if (ret)
  375. return ret;
  376. }
  377. next_dent(itr);
  378. if (!itr->dent)
  379. return -EIO;
  380. }
  381. return 0;
  382. }
  383. /*
  384. * Set the entry at index 'entry' in a FAT (12/16/32) table.
  385. */
  386. static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value)
  387. {
  388. __u32 bufnum, offset, off16;
  389. __u16 val1, val2;
  390. switch (mydata->fatsize) {
  391. case 32:
  392. bufnum = entry / FAT32BUFSIZE;
  393. offset = entry - bufnum * FAT32BUFSIZE;
  394. break;
  395. case 16:
  396. bufnum = entry / FAT16BUFSIZE;
  397. offset = entry - bufnum * FAT16BUFSIZE;
  398. break;
  399. case 12:
  400. bufnum = entry / FAT12BUFSIZE;
  401. offset = entry - bufnum * FAT12BUFSIZE;
  402. break;
  403. default:
  404. /* Unsupported FAT size */
  405. return -1;
  406. }
  407. /* Read a new block of FAT entries into the cache. */
  408. if (bufnum != mydata->fatbufnum) {
  409. int getsize = FATBUFBLOCKS;
  410. __u8 *bufptr = mydata->fatbuf;
  411. __u32 fatlength = mydata->fatlength;
  412. __u32 startblock = bufnum * FATBUFBLOCKS;
  413. /* Cap length if fatlength is not a multiple of FATBUFBLOCKS */
  414. if (startblock + getsize > fatlength)
  415. getsize = fatlength - startblock;
  416. if (flush_dirty_fat_buffer(mydata) < 0)
  417. return -1;
  418. startblock += mydata->fat_sect;
  419. if (disk_read(startblock, getsize, bufptr) < 0) {
  420. debug("Error reading FAT blocks\n");
  421. return -1;
  422. }
  423. mydata->fatbufnum = bufnum;
  424. }
  425. /* Mark as dirty */
  426. mydata->fat_dirty = 1;
  427. /* Set the actual entry */
  428. switch (mydata->fatsize) {
  429. case 32:
  430. ((__u32 *) mydata->fatbuf)[offset] = cpu_to_le32(entry_value);
  431. break;
  432. case 16:
  433. ((__u16 *) mydata->fatbuf)[offset] = cpu_to_le16(entry_value);
  434. break;
  435. case 12:
  436. off16 = (offset * 3) / 4;
  437. switch (offset & 0x3) {
  438. case 0:
  439. val1 = cpu_to_le16(entry_value) & 0xfff;
  440. ((__u16 *)mydata->fatbuf)[off16] &= ~0xfff;
  441. ((__u16 *)mydata->fatbuf)[off16] |= val1;
  442. break;
  443. case 1:
  444. val1 = cpu_to_le16(entry_value) & 0xf;
  445. val2 = (cpu_to_le16(entry_value) >> 4) & 0xff;
  446. ((__u16 *)mydata->fatbuf)[off16] &= ~0xf000;
  447. ((__u16 *)mydata->fatbuf)[off16] |= (val1 << 12);
  448. ((__u16 *)mydata->fatbuf)[off16 + 1] &= ~0xff;
  449. ((__u16 *)mydata->fatbuf)[off16 + 1] |= val2;
  450. break;
  451. case 2:
  452. val1 = cpu_to_le16(entry_value) & 0xff;
  453. val2 = (cpu_to_le16(entry_value) >> 8) & 0xf;
  454. ((__u16 *)mydata->fatbuf)[off16] &= ~0xff00;
  455. ((__u16 *)mydata->fatbuf)[off16] |= (val1 << 8);
  456. ((__u16 *)mydata->fatbuf)[off16 + 1] &= ~0xf;
  457. ((__u16 *)mydata->fatbuf)[off16 + 1] |= val2;
  458. break;
  459. case 3:
  460. val1 = cpu_to_le16(entry_value) & 0xfff;
  461. ((__u16 *)mydata->fatbuf)[off16] &= ~0xfff0;
  462. ((__u16 *)mydata->fatbuf)[off16] |= (val1 << 4);
  463. break;
  464. default:
  465. break;
  466. }
  467. break;
  468. default:
  469. return -1;
  470. }
  471. return 0;
  472. }
  473. /*
  474. * Determine the next free cluster after 'entry' in a FAT (12/16/32) table
  475. * and link it to 'entry'. EOC marker is not set on returned entry.
  476. */
  477. static __u32 determine_fatent(fsdata *mydata, __u32 entry)
  478. {
  479. __u32 next_fat, next_entry = entry + 1;
  480. while (1) {
  481. next_fat = get_fatent(mydata, next_entry);
  482. if (next_fat == 0) {
  483. /* found free entry, link to entry */
  484. set_fatent_value(mydata, entry, next_entry);
  485. break;
  486. }
  487. next_entry++;
  488. }
  489. debug("FAT%d: entry: %08x, entry_value: %04x\n",
  490. mydata->fatsize, entry, next_entry);
  491. return next_entry;
  492. }
  493. /**
  494. * set_sectors() - write data to sectors
  495. *
  496. * Write 'size' bytes from 'buffer' into the specified sector.
  497. *
  498. * @mydata: data to be written
  499. * @startsect: sector to be written to
  500. * @buffer: data to be written
  501. * @size: bytes to be written (but not more than the size of a cluster)
  502. * Return: 0 on success, -1 otherwise
  503. */
  504. static int
  505. set_sectors(fsdata *mydata, u32 startsect, u8 *buffer, u32 size)
  506. {
  507. int ret;
  508. debug("startsect: %d\n", startsect);
  509. if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) {
  510. ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
  511. debug("FAT: Misaligned buffer address (%p)\n", buffer);
  512. while (size >= mydata->sect_size) {
  513. memcpy(tmpbuf, buffer, mydata->sect_size);
  514. ret = disk_write(startsect++, 1, tmpbuf);
  515. if (ret != 1) {
  516. debug("Error writing data (got %d)\n", ret);
  517. return -1;
  518. }
  519. buffer += mydata->sect_size;
  520. size -= mydata->sect_size;
  521. }
  522. } else if (size >= mydata->sect_size) {
  523. u32 nsects;
  524. nsects = size / mydata->sect_size;
  525. ret = disk_write(startsect, nsects, buffer);
  526. if (ret != nsects) {
  527. debug("Error writing data (got %d)\n", ret);
  528. return -1;
  529. }
  530. startsect += nsects;
  531. buffer += nsects * mydata->sect_size;
  532. size -= nsects * mydata->sect_size;
  533. }
  534. if (size) {
  535. ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
  536. /* Do not leak content of stack */
  537. memset(tmpbuf, 0, mydata->sect_size);
  538. memcpy(tmpbuf, buffer, size);
  539. ret = disk_write(startsect, 1, tmpbuf);
  540. if (ret != 1) {
  541. debug("Error writing data (got %d)\n", ret);
  542. return -1;
  543. }
  544. }
  545. return 0;
  546. }
  547. /**
  548. * set_cluster() - write data to cluster
  549. *
  550. * Write 'size' bytes from 'buffer' into the specified cluster.
  551. *
  552. * @mydata: data to be written
  553. * @clustnum: cluster to be written to
  554. * @buffer: data to be written
  555. * @size: bytes to be written (but not more than the size of a cluster)
  556. * Return: 0 on success, -1 otherwise
  557. */
  558. static int
  559. set_cluster(fsdata *mydata, u32 clustnum, u8 *buffer, u32 size)
  560. {
  561. return set_sectors(mydata, clust_to_sect(mydata, clustnum),
  562. buffer, size);
  563. }
  564. /**
  565. * flush_dir() - flush directory
  566. *
  567. * @itr: directory iterator
  568. * Return: 0 for success, -EIO on error
  569. */
  570. static int flush_dir(fat_itr *itr)
  571. {
  572. fsdata *mydata = itr->fsdata;
  573. u32 startsect, sect_offset, nsects;
  574. int ret;
  575. if (!itr->is_root || mydata->fatsize == 32) {
  576. ret = set_cluster(mydata, itr->clust, itr->block,
  577. mydata->clust_size * mydata->sect_size);
  578. goto out;
  579. }
  580. sect_offset = itr->clust * mydata->clust_size;
  581. startsect = mydata->rootdir_sect + sect_offset;
  582. /* do not write past the end of rootdir */
  583. nsects = min_t(u32, mydata->clust_size,
  584. mydata->rootdir_size - sect_offset);
  585. ret = set_sectors(mydata, startsect, itr->block,
  586. nsects * mydata->sect_size);
  587. out:
  588. if (ret) {
  589. log_err("Error: writing directory entry\n");
  590. return -EIO;
  591. }
  592. return 0;
  593. }
  594. /*
  595. * Read and modify data on existing and consecutive cluster blocks
  596. */
  597. static int
  598. get_set_cluster(fsdata *mydata, __u32 clustnum, loff_t pos, __u8 *buffer,
  599. loff_t size, loff_t *gotsize)
  600. {
  601. static u8 *tmpbuf_cluster;
  602. unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
  603. __u32 startsect;
  604. loff_t wsize;
  605. int clustcount, i, ret;
  606. *gotsize = 0;
  607. if (!size)
  608. return 0;
  609. if (!tmpbuf_cluster) {
  610. tmpbuf_cluster = memalign(ARCH_DMA_MINALIGN, MAX_CLUSTSIZE);
  611. if (!tmpbuf_cluster)
  612. return -1;
  613. }
  614. assert(pos < bytesperclust);
  615. startsect = clust_to_sect(mydata, clustnum);
  616. debug("clustnum: %d, startsect: %d, pos: %lld\n",
  617. clustnum, startsect, pos);
  618. /* partial write at beginning */
  619. if (pos) {
  620. wsize = min(bytesperclust - pos, size);
  621. ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
  622. if (ret != mydata->clust_size) {
  623. debug("Error reading data (got %d)\n", ret);
  624. return -1;
  625. }
  626. memcpy(tmpbuf_cluster + pos, buffer, wsize);
  627. ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);
  628. if (ret != mydata->clust_size) {
  629. debug("Error writing data (got %d)\n", ret);
  630. return -1;
  631. }
  632. size -= wsize;
  633. buffer += wsize;
  634. *gotsize += wsize;
  635. startsect += mydata->clust_size;
  636. if (!size)
  637. return 0;
  638. }
  639. /* full-cluster write */
  640. if (size >= bytesperclust) {
  641. clustcount = lldiv(size, bytesperclust);
  642. if (!((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1))) {
  643. wsize = clustcount * bytesperclust;
  644. ret = disk_write(startsect,
  645. clustcount * mydata->clust_size,
  646. buffer);
  647. if (ret != clustcount * mydata->clust_size) {
  648. debug("Error writing data (got %d)\n", ret);
  649. return -1;
  650. }
  651. size -= wsize;
  652. buffer += wsize;
  653. *gotsize += wsize;
  654. startsect += clustcount * mydata->clust_size;
  655. } else {
  656. for (i = 0; i < clustcount; i++) {
  657. memcpy(tmpbuf_cluster, buffer, bytesperclust);
  658. ret = disk_write(startsect,
  659. mydata->clust_size,
  660. tmpbuf_cluster);
  661. if (ret != mydata->clust_size) {
  662. debug("Error writing data (got %d)\n",
  663. ret);
  664. return -1;
  665. }
  666. size -= bytesperclust;
  667. buffer += bytesperclust;
  668. *gotsize += bytesperclust;
  669. startsect += mydata->clust_size;
  670. }
  671. }
  672. }
  673. /* partial write at end */
  674. if (size) {
  675. wsize = size;
  676. ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
  677. if (ret != mydata->clust_size) {
  678. debug("Error reading data (got %d)\n", ret);
  679. return -1;
  680. }
  681. memcpy(tmpbuf_cluster, buffer, wsize);
  682. ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);
  683. if (ret != mydata->clust_size) {
  684. debug("Error writing data (got %d)\n", ret);
  685. return -1;
  686. }
  687. size -= wsize;
  688. *gotsize += wsize;
  689. }
  690. assert(!size);
  691. return 0;
  692. }
  693. /*
  694. * Find the first empty cluster
  695. */
  696. static int find_empty_cluster(fsdata *mydata)
  697. {
  698. __u32 fat_val, entry = 3;
  699. while (1) {
  700. fat_val = get_fatent(mydata, entry);
  701. if (fat_val == 0)
  702. break;
  703. entry++;
  704. }
  705. return entry;
  706. }
  707. /**
  708. * new_dir_table() - allocate a cluster for additional directory entries
  709. *
  710. * @itr: directory iterator
  711. * Return: 0 on success, -EIO otherwise
  712. */
  713. static int new_dir_table(fat_itr *itr)
  714. {
  715. fsdata *mydata = itr->fsdata;
  716. int dir_newclust = 0;
  717. int dir_oldclust = itr->clust;
  718. unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
  719. dir_newclust = find_empty_cluster(mydata);
  720. /*
  721. * Flush before updating FAT to ensure valid directory structure
  722. * in case of failure.
  723. */
  724. itr->clust = dir_newclust;
  725. itr->next_clust = dir_newclust;
  726. memset(itr->block, 0x00, bytesperclust);
  727. if (flush_dir(itr))
  728. return -EIO;
  729. set_fatent_value(mydata, dir_oldclust, dir_newclust);
  730. if (mydata->fatsize == 32)
  731. set_fatent_value(mydata, dir_newclust, 0xffffff8);
  732. else if (mydata->fatsize == 16)
  733. set_fatent_value(mydata, dir_newclust, 0xfff8);
  734. else if (mydata->fatsize == 12)
  735. set_fatent_value(mydata, dir_newclust, 0xff8);
  736. if (flush_dirty_fat_buffer(mydata) < 0)
  737. return -EIO;
  738. itr->dent = (dir_entry *)itr->block;
  739. itr->last_cluster = 1;
  740. itr->remaining = bytesperclust / sizeof(dir_entry) - 1;
  741. return 0;
  742. }
  743. /*
  744. * Set empty cluster from 'entry' to the end of a file
  745. */
  746. static int clear_fatent(fsdata *mydata, __u32 entry)
  747. {
  748. __u32 fat_val;
  749. while (!CHECK_CLUST(entry, mydata->fatsize)) {
  750. fat_val = get_fatent(mydata, entry);
  751. if (fat_val != 0)
  752. set_fatent_value(mydata, entry, 0);
  753. else
  754. break;
  755. entry = fat_val;
  756. }
  757. /* Flush fat buffer */
  758. if (flush_dirty_fat_buffer(mydata) < 0)
  759. return -1;
  760. return 0;
  761. }
  762. /*
  763. * Set start cluster in directory entry
  764. */
  765. static void set_start_cluster(const fsdata *mydata, dir_entry *dentptr,
  766. __u32 start_cluster)
  767. {
  768. if (mydata->fatsize == 32)
  769. dentptr->starthi =
  770. cpu_to_le16((start_cluster & 0xffff0000) >> 16);
  771. dentptr->start = cpu_to_le16(start_cluster & 0xffff);
  772. }
  773. /*
  774. * Check whether adding a file makes the file system to
  775. * exceed the size of the block device
  776. * Return -1 when overflow occurs, otherwise return 0
  777. */
  778. static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size)
  779. {
  780. __u32 startsect, sect_num, offset;
  781. if (clustnum > 0)
  782. startsect = clust_to_sect(mydata, clustnum);
  783. else
  784. startsect = mydata->rootdir_sect;
  785. sect_num = div_u64_rem(size, mydata->sect_size, &offset);
  786. if (offset != 0)
  787. sect_num++;
  788. if (startsect + sect_num > total_sector)
  789. return -1;
  790. return 0;
  791. }
  792. /*
  793. * Write at most 'maxsize' bytes from 'buffer' into
  794. * the file associated with 'dentptr'
  795. * Update the number of bytes written in *gotsize and return 0
  796. * or return -1 on fatal errors.
  797. */
  798. static int
  799. set_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, __u8 *buffer,
  800. loff_t maxsize, loff_t *gotsize)
  801. {
  802. unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
  803. __u32 curclust = START(dentptr);
  804. __u32 endclust = 0, newclust = 0;
  805. u64 cur_pos, filesize;
  806. loff_t offset, actsize, wsize;
  807. *gotsize = 0;
  808. filesize = pos + maxsize;
  809. debug("%llu bytes\n", filesize);
  810. if (!filesize) {
  811. if (!curclust)
  812. return 0;
  813. if (!CHECK_CLUST(curclust, mydata->fatsize) ||
  814. IS_LAST_CLUST(curclust, mydata->fatsize)) {
  815. clear_fatent(mydata, curclust);
  816. set_start_cluster(mydata, dentptr, 0);
  817. return 0;
  818. }
  819. debug("curclust: 0x%x\n", curclust);
  820. debug("Invalid FAT entry\n");
  821. return -1;
  822. }
  823. if (!curclust) {
  824. assert(pos == 0);
  825. goto set_clusters;
  826. }
  827. /* go to cluster at pos */
  828. cur_pos = bytesperclust;
  829. while (1) {
  830. if (pos <= cur_pos)
  831. break;
  832. if (IS_LAST_CLUST(curclust, mydata->fatsize))
  833. break;
  834. newclust = get_fatent(mydata, curclust);
  835. if (!IS_LAST_CLUST(newclust, mydata->fatsize) &&
  836. CHECK_CLUST(newclust, mydata->fatsize)) {
  837. debug("curclust: 0x%x\n", curclust);
  838. debug("Invalid FAT entry\n");
  839. return -1;
  840. }
  841. cur_pos += bytesperclust;
  842. curclust = newclust;
  843. }
  844. if (IS_LAST_CLUST(curclust, mydata->fatsize)) {
  845. assert(pos == cur_pos);
  846. goto set_clusters;
  847. }
  848. assert(pos < cur_pos);
  849. cur_pos -= bytesperclust;
  850. /* overwrite */
  851. assert(IS_LAST_CLUST(curclust, mydata->fatsize) ||
  852. !CHECK_CLUST(curclust, mydata->fatsize));
  853. while (1) {
  854. /* search for allocated consecutive clusters */
  855. actsize = bytesperclust;
  856. endclust = curclust;
  857. while (1) {
  858. if (filesize <= (cur_pos + actsize))
  859. break;
  860. newclust = get_fatent(mydata, endclust);
  861. if (newclust != endclust + 1)
  862. break;
  863. if (IS_LAST_CLUST(newclust, mydata->fatsize))
  864. break;
  865. if (CHECK_CLUST(newclust, mydata->fatsize)) {
  866. debug("curclust: 0x%x\n", curclust);
  867. debug("Invalid FAT entry\n");
  868. return -1;
  869. }
  870. actsize += bytesperclust;
  871. endclust = newclust;
  872. }
  873. /* overwrite to <curclust..endclust> */
  874. if (pos < cur_pos)
  875. offset = 0;
  876. else
  877. offset = pos - cur_pos;
  878. wsize = min_t(unsigned long long, actsize, filesize - cur_pos);
  879. wsize -= offset;
  880. if (get_set_cluster(mydata, curclust, offset,
  881. buffer, wsize, &actsize)) {
  882. printf("Error get-and-setting cluster\n");
  883. return -1;
  884. }
  885. buffer += wsize;
  886. *gotsize += wsize;
  887. cur_pos += offset + wsize;
  888. if (filesize <= cur_pos)
  889. break;
  890. if (IS_LAST_CLUST(newclust, mydata->fatsize))
  891. /* no more clusters */
  892. break;
  893. curclust = newclust;
  894. }
  895. if (filesize <= cur_pos) {
  896. /* no more write */
  897. newclust = get_fatent(mydata, endclust);
  898. if (!IS_LAST_CLUST(newclust, mydata->fatsize)) {
  899. /* truncate the rest */
  900. clear_fatent(mydata, newclust);
  901. /* Mark end of file in FAT */
  902. if (mydata->fatsize == 12)
  903. newclust = 0xfff;
  904. else if (mydata->fatsize == 16)
  905. newclust = 0xffff;
  906. else if (mydata->fatsize == 32)
  907. newclust = 0xfffffff;
  908. set_fatent_value(mydata, endclust, newclust);
  909. }
  910. return 0;
  911. }
  912. curclust = endclust;
  913. filesize -= cur_pos;
  914. assert(!do_div(cur_pos, bytesperclust));
  915. set_clusters:
  916. /* allocate and write */
  917. assert(!pos);
  918. /* Assure that curclust is valid */
  919. if (!curclust) {
  920. curclust = find_empty_cluster(mydata);
  921. set_start_cluster(mydata, dentptr, curclust);
  922. } else {
  923. newclust = get_fatent(mydata, curclust);
  924. if (IS_LAST_CLUST(newclust, mydata->fatsize)) {
  925. newclust = determine_fatent(mydata, curclust);
  926. set_fatent_value(mydata, curclust, newclust);
  927. curclust = newclust;
  928. } else {
  929. debug("error: something wrong\n");
  930. return -1;
  931. }
  932. }
  933. /* TODO: already partially written */
  934. if (check_overflow(mydata, curclust, filesize)) {
  935. printf("Error: no space left: %llu\n", filesize);
  936. return -1;
  937. }
  938. actsize = bytesperclust;
  939. endclust = curclust;
  940. do {
  941. /* search for consecutive clusters */
  942. while (actsize < filesize) {
  943. newclust = determine_fatent(mydata, endclust);
  944. if ((newclust - 1) != endclust)
  945. /* write to <curclust..endclust> */
  946. goto getit;
  947. if (CHECK_CLUST(newclust, mydata->fatsize)) {
  948. debug("newclust: 0x%x\n", newclust);
  949. debug("Invalid FAT entry\n");
  950. return 0;
  951. }
  952. endclust = newclust;
  953. actsize += bytesperclust;
  954. }
  955. /* set remaining bytes */
  956. actsize = filesize;
  957. if (set_cluster(mydata, curclust, buffer, (u32)actsize) != 0) {
  958. debug("error: writing cluster\n");
  959. return -1;
  960. }
  961. *gotsize += actsize;
  962. /* Mark end of file in FAT */
  963. if (mydata->fatsize == 12)
  964. newclust = 0xfff;
  965. else if (mydata->fatsize == 16)
  966. newclust = 0xffff;
  967. else if (mydata->fatsize == 32)
  968. newclust = 0xfffffff;
  969. set_fatent_value(mydata, endclust, newclust);
  970. return 0;
  971. getit:
  972. if (set_cluster(mydata, curclust, buffer, (u32)actsize) != 0) {
  973. debug("error: writing cluster\n");
  974. return -1;
  975. }
  976. *gotsize += actsize;
  977. filesize -= actsize;
  978. buffer += actsize;
  979. if (CHECK_CLUST(newclust, mydata->fatsize)) {
  980. debug("newclust: 0x%x\n", newclust);
  981. debug("Invalid FAT entry\n");
  982. return 0;
  983. }
  984. actsize = bytesperclust;
  985. curclust = endclust = newclust;
  986. } while (1);
  987. return 0;
  988. }
  989. /**
  990. * fill_dentry() - fill directory entry with shortname
  991. *
  992. * @mydata: private filesystem parameters
  993. * @dentptr: directory entry
  994. * @shortname: chosen short name
  995. * @start_cluster: first cluster of file
  996. * @size: file size
  997. * @attr: file attributes
  998. */
  999. static void fill_dentry(fsdata *mydata, dir_entry *dentptr,
  1000. const char *shortname, __u32 start_cluster, __u32 size, __u8 attr)
  1001. {
  1002. memset(dentptr, 0, sizeof(*dentptr));
  1003. set_start_cluster(mydata, dentptr, start_cluster);
  1004. dentptr->size = cpu_to_le32(size);
  1005. dentptr->attr = attr;
  1006. memcpy(&dentptr->nameext, shortname, SHORT_NAME_SIZE);
  1007. }
  1008. /**
  1009. * find_directory_entry() - find a directory entry by filename
  1010. *
  1011. * @itr: directory iterator
  1012. * @filename: name of file to find
  1013. * Return: directory entry or NULL
  1014. */
  1015. static dir_entry *find_directory_entry(fat_itr *itr, char *filename)
  1016. {
  1017. int match = 0;
  1018. while (fat_itr_next(itr)) {
  1019. /* check both long and short name: */
  1020. if (!strcasecmp(filename, itr->name))
  1021. match = 1;
  1022. else if (itr->name != itr->s_name &&
  1023. !strcasecmp(filename, itr->s_name))
  1024. match = 1;
  1025. if (!match)
  1026. continue;
  1027. if (itr->dent->nameext.name[0] == '\0')
  1028. return NULL;
  1029. else
  1030. return itr->dent;
  1031. }
  1032. return NULL;
  1033. }
  1034. static int split_filename(char *filename, char **dirname, char **basename)
  1035. {
  1036. char *p, *last_slash, *last_slash_cont;
  1037. again:
  1038. p = filename;
  1039. last_slash = NULL;
  1040. last_slash_cont = NULL;
  1041. while (*p) {
  1042. if (ISDIRDELIM(*p)) {
  1043. last_slash = p;
  1044. last_slash_cont = p;
  1045. /* continuous slashes */
  1046. while (ISDIRDELIM(*p))
  1047. last_slash_cont = p++;
  1048. if (!*p)
  1049. break;
  1050. }
  1051. p++;
  1052. }
  1053. if (last_slash) {
  1054. if (last_slash_cont == (filename + strlen(filename) - 1)) {
  1055. /* remove trailing slashes */
  1056. *last_slash = '\0';
  1057. goto again;
  1058. }
  1059. if (last_slash == filename) {
  1060. /* avoid ""(null) directory */
  1061. *dirname = "/";
  1062. } else {
  1063. *last_slash = '\0';
  1064. *dirname = filename;
  1065. }
  1066. *last_slash_cont = '\0';
  1067. filename = last_slash_cont + 1;
  1068. } else {
  1069. *dirname = "/"; /* root by default */
  1070. }
  1071. /*
  1072. * The FAT32 File System Specification v1.03 requires leading and
  1073. * trailing spaces as well as trailing periods to be ignored.
  1074. */
  1075. for (; *filename == ' '; ++filename)
  1076. ;
  1077. /* Keep special entries '.' and '..' */
  1078. if (filename[0] == '.' &&
  1079. (!filename[1] || (filename[1] == '.' && !filename[2])))
  1080. goto done;
  1081. /* Remove trailing periods and spaces */
  1082. for (p = filename + strlen(filename) - 1; p >= filename; --p) {
  1083. switch (*p) {
  1084. case ' ':
  1085. case '.':
  1086. *p = 0;
  1087. break;
  1088. default:
  1089. goto done;
  1090. }
  1091. }
  1092. done:
  1093. *basename = filename;
  1094. return 0;
  1095. }
  1096. /**
  1097. * normalize_longname() - check long file name and convert to lower case
  1098. *
  1099. * We assume here that the FAT file system is using an 8bit code page.
  1100. * Linux typically uses CP437, EDK2 assumes CP1250.
  1101. *
  1102. * @l_filename: preallocated buffer receiving the normalized name
  1103. * @filename: filename to normalize
  1104. * Return: 0 on success, -1 on failure
  1105. */
  1106. static int normalize_longname(char *l_filename, const char *filename)
  1107. {
  1108. const char *p, illegal[] = "<>:\"/\\|?*";
  1109. size_t len;
  1110. len = strlen(filename);
  1111. if (!len || len >= VFAT_MAXLEN_BYTES || filename[len - 1] == '.')
  1112. return -1;
  1113. for (p = filename; *p; ++p) {
  1114. if ((unsigned char)*p < 0x20)
  1115. return -1;
  1116. if (strchr(illegal, *p))
  1117. return -1;
  1118. }
  1119. strcpy(l_filename, filename);
  1120. downcase(l_filename, VFAT_MAXLEN_BYTES);
  1121. return 0;
  1122. }
  1123. int file_fat_write_at(const char *filename, loff_t pos, void *buffer,
  1124. loff_t size, loff_t *actwrite)
  1125. {
  1126. dir_entry *retdent;
  1127. fsdata datablock = { .fatbuf = NULL, };
  1128. fsdata *mydata = &datablock;
  1129. fat_itr *itr = NULL;
  1130. int ret = -1;
  1131. char *filename_copy, *parent, *basename;
  1132. char l_filename[VFAT_MAXLEN_BYTES];
  1133. debug("writing %s\n", filename);
  1134. filename_copy = strdup(filename);
  1135. if (!filename_copy)
  1136. return -ENOMEM;
  1137. split_filename(filename_copy, &parent, &basename);
  1138. if (!strlen(basename)) {
  1139. ret = -EINVAL;
  1140. goto exit;
  1141. }
  1142. if (normalize_longname(l_filename, basename)) {
  1143. printf("FAT: illegal filename (%s)\n", basename);
  1144. ret = -EINVAL;
  1145. goto exit;
  1146. }
  1147. itr = malloc_cache_aligned(sizeof(fat_itr));
  1148. if (!itr) {
  1149. ret = -ENOMEM;
  1150. goto exit;
  1151. }
  1152. ret = fat_itr_root(itr, &datablock);
  1153. if (ret)
  1154. goto exit;
  1155. total_sector = datablock.total_sect;
  1156. ret = fat_itr_resolve(itr, parent, TYPE_DIR);
  1157. if (ret) {
  1158. printf("%s: doesn't exist (%d)\n", parent, ret);
  1159. goto exit;
  1160. }
  1161. retdent = find_directory_entry(itr, l_filename);
  1162. if (retdent) {
  1163. if (fat_itr_isdir(itr)) {
  1164. ret = -EISDIR;
  1165. goto exit;
  1166. }
  1167. /* A file exists */
  1168. if (pos == -1)
  1169. /* Append to the end */
  1170. pos = FAT2CPU32(retdent->size);
  1171. if (pos > retdent->size) {
  1172. /* No hole allowed */
  1173. ret = -EINVAL;
  1174. goto exit;
  1175. }
  1176. /* Update file size in a directory entry */
  1177. retdent->size = cpu_to_le32(pos + size);
  1178. } else {
  1179. /* Create a new file */
  1180. char shortname[SHORT_NAME_SIZE];
  1181. int ndent;
  1182. if (pos) {
  1183. /* No hole allowed */
  1184. ret = -EINVAL;
  1185. goto exit;
  1186. }
  1187. /* Check if long name is needed */
  1188. ndent = set_name(itr, basename, shortname);
  1189. if (ndent < 0) {
  1190. ret = ndent;
  1191. goto exit;
  1192. }
  1193. ret = fat_find_empty_dentries(itr, ndent);
  1194. if (ret)
  1195. goto exit;
  1196. if (ndent > 1) {
  1197. /* Set long name entries */
  1198. ret = fill_dir_slot(itr, basename, shortname);
  1199. if (ret)
  1200. goto exit;
  1201. }
  1202. /* Set short name entry */
  1203. fill_dentry(itr->fsdata, itr->dent, shortname, 0, size,
  1204. ATTR_ARCH);
  1205. retdent = itr->dent;
  1206. }
  1207. ret = set_contents(mydata, retdent, pos, buffer, size, actwrite);
  1208. if (ret < 0) {
  1209. printf("Error: writing contents\n");
  1210. ret = -EIO;
  1211. goto exit;
  1212. }
  1213. debug("attempt to write 0x%llx bytes\n", *actwrite);
  1214. /* Flush fat buffer */
  1215. ret = flush_dirty_fat_buffer(mydata);
  1216. if (ret) {
  1217. printf("Error: flush fat buffer\n");
  1218. ret = -EIO;
  1219. goto exit;
  1220. }
  1221. /* Write directory table to device */
  1222. ret = flush_dir(itr);
  1223. exit:
  1224. free(filename_copy);
  1225. free(mydata->fatbuf);
  1226. free(itr);
  1227. return ret;
  1228. }
  1229. int file_fat_write(const char *filename, void *buffer, loff_t offset,
  1230. loff_t maxsize, loff_t *actwrite)
  1231. {
  1232. return file_fat_write_at(filename, offset, buffer, maxsize, actwrite);
  1233. }
  1234. static int fat_dir_entries(fat_itr *itr)
  1235. {
  1236. fat_itr *dirs;
  1237. fsdata fsdata = { .fatbuf = NULL, }, *mydata = &fsdata;
  1238. /* for FATBUFSIZE */
  1239. int count;
  1240. dirs = malloc_cache_aligned(sizeof(fat_itr));
  1241. if (!dirs) {
  1242. debug("Error: allocating memory\n");
  1243. count = -ENOMEM;
  1244. goto exit;
  1245. }
  1246. /* duplicate fsdata */
  1247. fat_itr_child(dirs, itr);
  1248. fsdata = *dirs->fsdata;
  1249. /* allocate local fat buffer */
  1250. fsdata.fatbuf = malloc_cache_aligned(FATBUFSIZE);
  1251. if (!fsdata.fatbuf) {
  1252. debug("Error: allocating memory\n");
  1253. count = -ENOMEM;
  1254. goto exit;
  1255. }
  1256. fsdata.fatbufnum = -1;
  1257. dirs->fsdata = &fsdata;
  1258. for (count = 0; fat_itr_next(dirs); count++)
  1259. ;
  1260. exit:
  1261. free(fsdata.fatbuf);
  1262. free(dirs);
  1263. return count;
  1264. }
  1265. /**
  1266. * delete_single_dentry() - delete a single directory entry
  1267. *
  1268. * @itr: directory iterator
  1269. * Return: 0 for success
  1270. */
  1271. static int delete_single_dentry(fat_itr *itr)
  1272. {
  1273. struct dir_entry *dent = itr->dent;
  1274. memset(dent, 0, sizeof(*dent));
  1275. dent->nameext.name[0] = DELETED_FLAG;
  1276. if (!itr->remaining)
  1277. return flush_dir(itr);
  1278. return 0;
  1279. }
  1280. /**
  1281. * delete_long_name() - delete long name directory entries
  1282. *
  1283. * @itr: directory iterator
  1284. * Return: 0 for success
  1285. */
  1286. static int delete_long_name(fat_itr *itr)
  1287. {
  1288. int seqn = itr->dent->nameext.name[0] & ~LAST_LONG_ENTRY_MASK;
  1289. while (seqn--) {
  1290. struct dir_entry *dent;
  1291. int ret;
  1292. ret = delete_single_dentry(itr);
  1293. if (ret)
  1294. return ret;
  1295. dent = next_dent(itr);
  1296. if (!dent)
  1297. return -EIO;
  1298. }
  1299. return 0;
  1300. }
  1301. /**
  1302. * delete_dentry_long() - remove directory entry
  1303. *
  1304. * @itr: directory iterator
  1305. * Return: 0 for success
  1306. */
  1307. static int delete_dentry_long(fat_itr *itr)
  1308. {
  1309. fsdata *mydata = itr->fsdata;
  1310. dir_entry *dent = itr->dent;
  1311. /* free cluster blocks */
  1312. clear_fatent(mydata, START(dent));
  1313. if (flush_dirty_fat_buffer(mydata) < 0) {
  1314. printf("Error: flush fat buffer\n");
  1315. return -EIO;
  1316. }
  1317. /* Position to first directory entry for long name */
  1318. if (itr->clust != itr->dent_clust) {
  1319. int ret;
  1320. ret = fat_move_to_cluster(itr, itr->dent_clust);
  1321. if (ret)
  1322. return ret;
  1323. }
  1324. itr->dent = itr->dent_start;
  1325. itr->remaining = itr->dent_rem;
  1326. dent = itr->dent_start;
  1327. /* Delete long name */
  1328. if ((dent->attr & ATTR_VFAT) == ATTR_VFAT &&
  1329. (dent->nameext.name[0] & LAST_LONG_ENTRY_MASK)) {
  1330. int ret;
  1331. ret = delete_long_name(itr);
  1332. if (ret)
  1333. return ret;
  1334. }
  1335. /* Delete short name */
  1336. delete_single_dentry(itr);
  1337. return flush_dir(itr);
  1338. }
  1339. int fat_unlink(const char *filename)
  1340. {
  1341. fsdata fsdata = { .fatbuf = NULL, };
  1342. fat_itr *itr = NULL;
  1343. int n_entries, ret;
  1344. char *filename_copy, *dirname, *basename;
  1345. filename_copy = strdup(filename);
  1346. if (!filename_copy) {
  1347. printf("Error: allocating memory\n");
  1348. ret = -ENOMEM;
  1349. goto exit;
  1350. }
  1351. split_filename(filename_copy, &dirname, &basename);
  1352. if (!strcmp(dirname, "/") && !strcmp(basename, "")) {
  1353. printf("Error: cannot remove root\n");
  1354. ret = -EINVAL;
  1355. goto exit;
  1356. }
  1357. itr = malloc_cache_aligned(sizeof(fat_itr));
  1358. if (!itr) {
  1359. printf("Error: allocating memory\n");
  1360. ret = -ENOMEM;
  1361. goto exit;
  1362. }
  1363. ret = fat_itr_root(itr, &fsdata);
  1364. if (ret)
  1365. goto exit;
  1366. total_sector = fsdata.total_sect;
  1367. ret = fat_itr_resolve(itr, dirname, TYPE_DIR);
  1368. if (ret) {
  1369. printf("%s: doesn't exist (%d)\n", dirname, ret);
  1370. ret = -ENOENT;
  1371. goto exit;
  1372. }
  1373. if (!find_directory_entry(itr, basename)) {
  1374. printf("%s: doesn't exist\n", basename);
  1375. ret = -ENOENT;
  1376. goto exit;
  1377. }
  1378. if (fat_itr_isdir(itr)) {
  1379. n_entries = fat_dir_entries(itr);
  1380. if (n_entries < 0) {
  1381. ret = n_entries;
  1382. goto exit;
  1383. }
  1384. if (n_entries > 2) {
  1385. printf("Error: directory is not empty: %d\n",
  1386. n_entries);
  1387. ret = -EINVAL;
  1388. goto exit;
  1389. }
  1390. }
  1391. ret = delete_dentry_long(itr);
  1392. exit:
  1393. free(fsdata.fatbuf);
  1394. free(itr);
  1395. free(filename_copy);
  1396. return ret;
  1397. }
  1398. int fat_mkdir(const char *dirname)
  1399. {
  1400. dir_entry *retdent;
  1401. fsdata datablock = { .fatbuf = NULL, };
  1402. fsdata *mydata = &datablock;
  1403. fat_itr *itr = NULL;
  1404. char *dirname_copy, *parent, *basename;
  1405. char l_dirname[VFAT_MAXLEN_BYTES];
  1406. int ret = -1;
  1407. loff_t actwrite;
  1408. unsigned int bytesperclust;
  1409. dir_entry *dotdent = NULL;
  1410. dirname_copy = strdup(dirname);
  1411. if (!dirname_copy)
  1412. goto exit;
  1413. split_filename(dirname_copy, &parent, &basename);
  1414. if (!strlen(basename)) {
  1415. ret = -EINVAL;
  1416. goto exit;
  1417. }
  1418. if (normalize_longname(l_dirname, basename)) {
  1419. printf("FAT: illegal filename (%s)\n", basename);
  1420. ret = -EINVAL;
  1421. goto exit;
  1422. }
  1423. itr = malloc_cache_aligned(sizeof(fat_itr));
  1424. if (!itr) {
  1425. ret = -ENOMEM;
  1426. goto exit;
  1427. }
  1428. ret = fat_itr_root(itr, &datablock);
  1429. if (ret)
  1430. goto exit;
  1431. total_sector = datablock.total_sect;
  1432. ret = fat_itr_resolve(itr, parent, TYPE_DIR);
  1433. if (ret) {
  1434. printf("%s: doesn't exist (%d)\n", parent, ret);
  1435. goto exit;
  1436. }
  1437. retdent = find_directory_entry(itr, l_dirname);
  1438. if (retdent) {
  1439. printf("%s: already exists\n", l_dirname);
  1440. ret = -EEXIST;
  1441. goto exit;
  1442. } else {
  1443. char shortname[SHORT_NAME_SIZE];
  1444. int ndent;
  1445. if (itr->is_root) {
  1446. /* root dir cannot have "." or ".." */
  1447. if (!strcmp(l_dirname, ".") ||
  1448. !strcmp(l_dirname, "..")) {
  1449. ret = -EINVAL;
  1450. goto exit;
  1451. }
  1452. }
  1453. /* Check if long name is needed */
  1454. ndent = set_name(itr, basename, shortname);
  1455. if (ndent < 0) {
  1456. ret = ndent;
  1457. goto exit;
  1458. }
  1459. ret = fat_find_empty_dentries(itr, ndent);
  1460. if (ret)
  1461. goto exit;
  1462. if (ndent > 1) {
  1463. /* Set long name entries */
  1464. ret = fill_dir_slot(itr, basename, shortname);
  1465. if (ret)
  1466. goto exit;
  1467. }
  1468. /* Set attribute as archive for regular file */
  1469. fill_dentry(itr->fsdata, itr->dent, shortname, 0, 0,
  1470. ATTR_DIR | ATTR_ARCH);
  1471. retdent = itr->dent;
  1472. }
  1473. /* Default entries */
  1474. bytesperclust = mydata->clust_size * mydata->sect_size;
  1475. dotdent = malloc_cache_aligned(bytesperclust);
  1476. if (!dotdent) {
  1477. ret = -ENOMEM;
  1478. goto exit;
  1479. }
  1480. memset(dotdent, 0, bytesperclust);
  1481. memcpy(&dotdent[0].nameext, ". ", 11);
  1482. dotdent[0].attr = ATTR_DIR | ATTR_ARCH;
  1483. memcpy(&dotdent[1].nameext, ".. ", 11);
  1484. dotdent[1].attr = ATTR_DIR | ATTR_ARCH;
  1485. if (itr->is_root)
  1486. set_start_cluster(mydata, &dotdent[1], 0);
  1487. else
  1488. set_start_cluster(mydata, &dotdent[1], itr->start_clust);
  1489. ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent,
  1490. bytesperclust, &actwrite);
  1491. if (ret < 0) {
  1492. printf("Error: writing contents\n");
  1493. goto exit;
  1494. }
  1495. /* Write twice for "." */
  1496. set_start_cluster(mydata, &dotdent[0], START(retdent));
  1497. ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent,
  1498. bytesperclust, &actwrite);
  1499. if (ret < 0) {
  1500. printf("Error: writing contents\n");
  1501. goto exit;
  1502. }
  1503. /* Flush fat buffer */
  1504. ret = flush_dirty_fat_buffer(mydata);
  1505. if (ret) {
  1506. printf("Error: flush fat buffer\n");
  1507. ret = -EIO;
  1508. goto exit;
  1509. }
  1510. /* Write directory table to device */
  1511. ret = flush_dir(itr);
  1512. exit:
  1513. free(dirname_copy);
  1514. free(mydata->fatbuf);
  1515. free(itr);
  1516. free(dotdent);
  1517. return ret;
  1518. }