yaffsfs.c 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510
  1. /*
  2. * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
  3. *
  4. * Copyright (C) 2002-2007 Aleph One Ltd.
  5. * for Toby Churchill Ltd and Brightstar Engineering
  6. *
  7. * Created by Charles Manning <charles@aleph1.co.uk>
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2 as
  11. * published by the Free Software Foundation.
  12. */
  13. /* XXX U-BOOT XXX */
  14. #include <common.h>
  15. #include <malloc.h>
  16. #include "yaffsfs.h"
  17. #include "yaffs_guts.h"
  18. #include "yaffscfg.h"
  19. #include "yportenv.h"
  20. /* XXX U-BOOT XXX */
  21. #if 0
  22. #include <string.h> // for memset
  23. #endif
  24. #define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5
  25. #ifndef NULL
  26. #define NULL ((void *)0)
  27. #endif
  28. const char *yaffsfs_c_version="$Id: yaffsfs.c,v 1.18 2007/07/18 19:40:38 charles Exp $";
  29. // configurationList is the list of devices that are supported
  30. static yaffsfs_DeviceConfiguration *yaffsfs_configurationList;
  31. /* Some forward references */
  32. static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const char *path, int symDepth);
  33. static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj);
  34. // Handle management.
  35. //
  36. unsigned int yaffs_wr_attempts;
  37. typedef struct
  38. {
  39. __u8 inUse:1; // this handle is in use
  40. __u8 readOnly:1; // this handle is read only
  41. __u8 append:1; // append only
  42. __u8 exclusive:1; // exclusive
  43. __u32 position; // current position in file
  44. yaffs_Object *obj; // the object
  45. }yaffsfs_Handle;
  46. static yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES];
  47. // yaffsfs_InitHandle
  48. /// Inilitalise handles on start-up.
  49. //
  50. static int yaffsfs_InitHandles(void)
  51. {
  52. int i;
  53. for(i = 0; i < YAFFSFS_N_HANDLES; i++)
  54. {
  55. yaffsfs_handle[i].inUse = 0;
  56. yaffsfs_handle[i].obj = NULL;
  57. }
  58. return 0;
  59. }
  60. yaffsfs_Handle *yaffsfs_GetHandlePointer(int h)
  61. {
  62. if(h < 0 || h >= YAFFSFS_N_HANDLES)
  63. {
  64. return NULL;
  65. }
  66. return &yaffsfs_handle[h];
  67. }
  68. yaffs_Object *yaffsfs_GetHandleObject(int handle)
  69. {
  70. yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
  71. if(h && h->inUse)
  72. {
  73. return h->obj;
  74. }
  75. return NULL;
  76. }
  77. //yaffsfs_GetHandle
  78. // Grab a handle (when opening a file)
  79. //
  80. static int yaffsfs_GetHandle(void)
  81. {
  82. int i;
  83. yaffsfs_Handle *h;
  84. for(i = 0; i < YAFFSFS_N_HANDLES; i++)
  85. {
  86. h = yaffsfs_GetHandlePointer(i);
  87. if(!h)
  88. {
  89. // todo bug: should never happen
  90. }
  91. if(!h->inUse)
  92. {
  93. memset(h,0,sizeof(yaffsfs_Handle));
  94. h->inUse=1;
  95. return i;
  96. }
  97. }
  98. return -1;
  99. }
  100. // yaffs_PutHandle
  101. // Let go of a handle (when closing a file)
  102. //
  103. static int yaffsfs_PutHandle(int handle)
  104. {
  105. yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
  106. if(h)
  107. {
  108. h->inUse = 0;
  109. h->obj = NULL;
  110. }
  111. return 0;
  112. }
  113. // Stuff to search for a directory from a path
  114. int yaffsfs_Match(char a, char b)
  115. {
  116. // case sensitive
  117. return (a == b);
  118. }
  119. // yaffsfs_FindDevice
  120. // yaffsfs_FindRoot
  121. // Scan the configuration list to find the root.
  122. // Curveballs: Should match paths that end in '/' too
  123. // Curveball2 Might have "/x/ and "/x/y". Need to return the longest match
  124. static yaffs_Device *yaffsfs_FindDevice(const char *path, char **restOfPath)
  125. {
  126. yaffsfs_DeviceConfiguration *cfg = yaffsfs_configurationList;
  127. const char *leftOver;
  128. const char *p;
  129. yaffs_Device *retval = NULL;
  130. int thisMatchLength;
  131. int longestMatch = -1;
  132. // Check all configs, choose the one that:
  133. // 1) Actually matches a prefix (ie /a amd /abc will not match
  134. // 2) Matches the longest.
  135. while(cfg && cfg->prefix && cfg->dev)
  136. {
  137. leftOver = path;
  138. p = cfg->prefix;
  139. thisMatchLength = 0;
  140. while(*p && //unmatched part of prefix
  141. strcmp(p,"/") && // the rest of the prefix is not / (to catch / at end)
  142. *leftOver &&
  143. yaffsfs_Match(*p,*leftOver))
  144. {
  145. p++;
  146. leftOver++;
  147. thisMatchLength++;
  148. }
  149. if((!*p || strcmp(p,"/") == 0) && // end of prefix
  150. (!*leftOver || *leftOver == '/') && // no more in this path name part
  151. (thisMatchLength > longestMatch))
  152. {
  153. // Matched prefix
  154. *restOfPath = (char *)leftOver;
  155. retval = cfg->dev;
  156. longestMatch = thisMatchLength;
  157. }
  158. cfg++;
  159. }
  160. return retval;
  161. }
  162. static yaffs_Object *yaffsfs_FindRoot(const char *path, char **restOfPath)
  163. {
  164. yaffs_Device *dev;
  165. dev= yaffsfs_FindDevice(path,restOfPath);
  166. if(dev && dev->isMounted)
  167. {
  168. return dev->rootDir;
  169. }
  170. return NULL;
  171. }
  172. static yaffs_Object *yaffsfs_FollowLink(yaffs_Object *obj,int symDepth)
  173. {
  174. while(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
  175. {
  176. char *alias = obj->variant.symLinkVariant.alias;
  177. if(*alias == '/')
  178. {
  179. // Starts with a /, need to scan from root up
  180. obj = yaffsfs_FindObject(NULL,alias,symDepth++);
  181. }
  182. else
  183. {
  184. // Relative to here, so use the parent of the symlink as a start
  185. obj = yaffsfs_FindObject(obj->parent,alias,symDepth++);
  186. }
  187. }
  188. return obj;
  189. }
  190. // yaffsfs_FindDirectory
  191. // Parse a path to determine the directory and the name within the directory.
  192. //
  193. // eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx"
  194. static yaffs_Object *yaffsfs_DoFindDirectory(yaffs_Object *startDir,const char *path,char **name,int symDepth)
  195. {
  196. yaffs_Object *dir;
  197. char *restOfPath;
  198. char str[YAFFS_MAX_NAME_LENGTH+1];
  199. int i;
  200. if(symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES)
  201. {
  202. return NULL;
  203. }
  204. if(startDir)
  205. {
  206. dir = startDir;
  207. restOfPath = (char *)path;
  208. }
  209. else
  210. {
  211. dir = yaffsfs_FindRoot(path,&restOfPath);
  212. }
  213. while(dir)
  214. {
  215. // parse off /.
  216. // curve ball: also throw away surplus '/'
  217. // eg. "/ram/x////ff" gets treated the same as "/ram/x/ff"
  218. while(*restOfPath == '/')
  219. {
  220. restOfPath++; // get rid of '/'
  221. }
  222. *name = restOfPath;
  223. i = 0;
  224. while(*restOfPath && *restOfPath != '/')
  225. {
  226. if (i < YAFFS_MAX_NAME_LENGTH)
  227. {
  228. str[i] = *restOfPath;
  229. str[i+1] = '\0';
  230. i++;
  231. }
  232. restOfPath++;
  233. }
  234. if(!*restOfPath)
  235. {
  236. // got to the end of the string
  237. return dir;
  238. }
  239. else
  240. {
  241. if(strcmp(str,".") == 0)
  242. {
  243. // Do nothing
  244. }
  245. else if(strcmp(str,"..") == 0)
  246. {
  247. dir = dir->parent;
  248. }
  249. else
  250. {
  251. dir = yaffs_FindObjectByName(dir,str);
  252. while(dir && dir->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
  253. {
  254. dir = yaffsfs_FollowLink(dir,symDepth);
  255. }
  256. if(dir && dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
  257. {
  258. dir = NULL;
  259. }
  260. }
  261. }
  262. }
  263. // directory did not exist.
  264. return NULL;
  265. }
  266. static yaffs_Object *yaffsfs_FindDirectory(yaffs_Object *relativeDirectory,const char *path,char **name,int symDepth)
  267. {
  268. return yaffsfs_DoFindDirectory(relativeDirectory,path,name,symDepth);
  269. }
  270. // yaffsfs_FindObject turns a path for an existing object into the object
  271. //
  272. static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const char *path,int symDepth)
  273. {
  274. yaffs_Object *dir;
  275. char *name;
  276. dir = yaffsfs_FindDirectory(relativeDirectory,path,&name,symDepth);
  277. if(dir && *name)
  278. {
  279. return yaffs_FindObjectByName(dir,name);
  280. }
  281. return dir;
  282. }
  283. int yaffs_open(const char *path, int oflag, int mode)
  284. {
  285. yaffs_Object *obj = NULL;
  286. yaffs_Object *dir = NULL;
  287. char *name;
  288. int handle = -1;
  289. yaffsfs_Handle *h = NULL;
  290. int alreadyOpen = 0;
  291. int alreadyExclusive = 0;
  292. int openDenied = 0;
  293. int symDepth = 0;
  294. int errorReported = 0;
  295. int i;
  296. // todo sanity check oflag (eg. can't have O_TRUNC without WRONLY or RDWR
  297. yaffsfs_Lock();
  298. handle = yaffsfs_GetHandle();
  299. if(handle >= 0)
  300. {
  301. h = yaffsfs_GetHandlePointer(handle);
  302. // try to find the exisiting object
  303. obj = yaffsfs_FindObject(NULL,path,0);
  304. if(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
  305. {
  306. obj = yaffsfs_FollowLink(obj,symDepth++);
  307. }
  308. if(obj)
  309. {
  310. // Check if the object is already in use
  311. alreadyOpen = alreadyExclusive = 0;
  312. for(i = 0; i <= YAFFSFS_N_HANDLES; i++)
  313. {
  314. if(i != handle &&
  315. yaffsfs_handle[i].inUse &&
  316. obj == yaffsfs_handle[i].obj)
  317. {
  318. alreadyOpen = 1;
  319. if(yaffsfs_handle[i].exclusive)
  320. {
  321. alreadyExclusive = 1;
  322. }
  323. }
  324. }
  325. if(((oflag & O_EXCL) && alreadyOpen) || alreadyExclusive)
  326. {
  327. openDenied = 1;
  328. }
  329. // Open should fail if O_CREAT and O_EXCL are specified
  330. if((oflag & O_EXCL) && (oflag & O_CREAT))
  331. {
  332. openDenied = 1;
  333. yaffsfs_SetError(-EEXIST);
  334. errorReported = 1;
  335. }
  336. // Check file permissions
  337. if( (oflag & (O_RDWR | O_WRONLY)) == 0 && // ie O_RDONLY
  338. !(obj->yst_mode & S_IREAD))
  339. {
  340. openDenied = 1;
  341. }
  342. if( (oflag & O_RDWR) &&
  343. !(obj->yst_mode & S_IREAD))
  344. {
  345. openDenied = 1;
  346. }
  347. if( (oflag & (O_RDWR | O_WRONLY)) &&
  348. !(obj->yst_mode & S_IWRITE))
  349. {
  350. openDenied = 1;
  351. }
  352. }
  353. else if((oflag & O_CREAT))
  354. {
  355. // Let's see if we can create this file
  356. dir = yaffsfs_FindDirectory(NULL,path,&name,0);
  357. if(dir)
  358. {
  359. obj = yaffs_MknodFile(dir,name,mode,0,0);
  360. }
  361. else
  362. {
  363. yaffsfs_SetError(-ENOTDIR);
  364. }
  365. }
  366. if(obj && !openDenied)
  367. {
  368. h->obj = obj;
  369. h->inUse = 1;
  370. h->readOnly = (oflag & (O_WRONLY | O_RDWR)) ? 0 : 1;
  371. h->append = (oflag & O_APPEND) ? 1 : 0;
  372. h->exclusive = (oflag & O_EXCL) ? 1 : 0;
  373. h->position = 0;
  374. obj->inUse++;
  375. if((oflag & O_TRUNC) && !h->readOnly)
  376. {
  377. //todo truncate
  378. yaffs_ResizeFile(obj,0);
  379. }
  380. }
  381. else
  382. {
  383. yaffsfs_PutHandle(handle);
  384. if(!errorReported)
  385. {
  386. yaffsfs_SetError(-EACCESS);
  387. errorReported = 1;
  388. }
  389. handle = -1;
  390. }
  391. }
  392. yaffsfs_Unlock();
  393. return handle;
  394. }
  395. int yaffs_close(int fd)
  396. {
  397. yaffsfs_Handle *h = NULL;
  398. int retVal = 0;
  399. yaffsfs_Lock();
  400. h = yaffsfs_GetHandlePointer(fd);
  401. if(h && h->inUse)
  402. {
  403. // clean up
  404. yaffs_FlushFile(h->obj,1);
  405. h->obj->inUse--;
  406. if(h->obj->inUse <= 0 && h->obj->unlinked)
  407. {
  408. yaffs_DeleteFile(h->obj);
  409. }
  410. yaffsfs_PutHandle(fd);
  411. retVal = 0;
  412. }
  413. else
  414. {
  415. // bad handle
  416. yaffsfs_SetError(-EBADF);
  417. retVal = -1;
  418. }
  419. yaffsfs_Unlock();
  420. return retVal;
  421. }
  422. int yaffs_read(int fd, void *buf, unsigned int nbyte)
  423. {
  424. yaffsfs_Handle *h = NULL;
  425. yaffs_Object *obj = NULL;
  426. int pos = 0;
  427. int nRead = -1;
  428. int maxRead;
  429. yaffsfs_Lock();
  430. h = yaffsfs_GetHandlePointer(fd);
  431. obj = yaffsfs_GetHandleObject(fd);
  432. if(!h || !obj)
  433. {
  434. // bad handle
  435. yaffsfs_SetError(-EBADF);
  436. }
  437. else if( h && obj)
  438. {
  439. pos= h->position;
  440. if(yaffs_GetObjectFileLength(obj) > pos)
  441. {
  442. maxRead = yaffs_GetObjectFileLength(obj) - pos;
  443. }
  444. else
  445. {
  446. maxRead = 0;
  447. }
  448. if(nbyte > maxRead)
  449. {
  450. nbyte = maxRead;
  451. }
  452. if(nbyte > 0)
  453. {
  454. nRead = yaffs_ReadDataFromFile(obj,buf,pos,nbyte);
  455. if(nRead >= 0)
  456. {
  457. h->position = pos + nRead;
  458. }
  459. else
  460. {
  461. //todo error
  462. }
  463. }
  464. else
  465. {
  466. nRead = 0;
  467. }
  468. }
  469. yaffsfs_Unlock();
  470. return (nRead >= 0) ? nRead : -1;
  471. }
  472. int yaffs_write(int fd, const void *buf, unsigned int nbyte)
  473. {
  474. yaffsfs_Handle *h = NULL;
  475. yaffs_Object *obj = NULL;
  476. int pos = 0;
  477. int nWritten = -1;
  478. int writeThrough = 0;
  479. yaffsfs_Lock();
  480. h = yaffsfs_GetHandlePointer(fd);
  481. obj = yaffsfs_GetHandleObject(fd);
  482. if(!h || !obj)
  483. {
  484. // bad handle
  485. yaffsfs_SetError(-EBADF);
  486. }
  487. else if( h && obj && h->readOnly)
  488. {
  489. // todo error
  490. }
  491. else if( h && obj)
  492. {
  493. if(h->append)
  494. {
  495. pos = yaffs_GetObjectFileLength(obj);
  496. }
  497. else
  498. {
  499. pos = h->position;
  500. }
  501. nWritten = yaffs_WriteDataToFile(obj,buf,pos,nbyte,writeThrough);
  502. if(nWritten >= 0)
  503. {
  504. h->position = pos + nWritten;
  505. }
  506. else
  507. {
  508. //todo error
  509. }
  510. }
  511. yaffsfs_Unlock();
  512. return (nWritten >= 0) ? nWritten : -1;
  513. }
  514. int yaffs_truncate(int fd, off_t newSize)
  515. {
  516. yaffsfs_Handle *h = NULL;
  517. yaffs_Object *obj = NULL;
  518. int result = 0;
  519. yaffsfs_Lock();
  520. h = yaffsfs_GetHandlePointer(fd);
  521. obj = yaffsfs_GetHandleObject(fd);
  522. if(!h || !obj)
  523. {
  524. // bad handle
  525. yaffsfs_SetError(-EBADF);
  526. }
  527. else
  528. {
  529. // resize the file
  530. result = yaffs_ResizeFile(obj,newSize);
  531. }
  532. yaffsfs_Unlock();
  533. return (result) ? 0 : -1;
  534. }
  535. off_t yaffs_lseek(int fd, off_t offset, int whence)
  536. {
  537. yaffsfs_Handle *h = NULL;
  538. yaffs_Object *obj = NULL;
  539. int pos = -1;
  540. int fSize = -1;
  541. yaffsfs_Lock();
  542. h = yaffsfs_GetHandlePointer(fd);
  543. obj = yaffsfs_GetHandleObject(fd);
  544. if(!h || !obj)
  545. {
  546. // bad handle
  547. yaffsfs_SetError(-EBADF);
  548. }
  549. else if(whence == SEEK_SET)
  550. {
  551. if(offset >= 0)
  552. {
  553. pos = offset;
  554. }
  555. }
  556. else if(whence == SEEK_CUR)
  557. {
  558. if( (h->position + offset) >= 0)
  559. {
  560. pos = (h->position + offset);
  561. }
  562. }
  563. else if(whence == SEEK_END)
  564. {
  565. fSize = yaffs_GetObjectFileLength(obj);
  566. if(fSize >= 0 && (fSize + offset) >= 0)
  567. {
  568. pos = fSize + offset;
  569. }
  570. }
  571. if(pos >= 0)
  572. {
  573. h->position = pos;
  574. }
  575. else
  576. {
  577. // todo error
  578. }
  579. yaffsfs_Unlock();
  580. return pos;
  581. }
  582. int yaffsfs_DoUnlink(const char *path,int isDirectory)
  583. {
  584. yaffs_Object *dir = NULL;
  585. yaffs_Object *obj = NULL;
  586. char *name;
  587. int result = YAFFS_FAIL;
  588. yaffsfs_Lock();
  589. obj = yaffsfs_FindObject(NULL,path,0);
  590. dir = yaffsfs_FindDirectory(NULL,path,&name,0);
  591. if(!dir)
  592. {
  593. yaffsfs_SetError(-ENOTDIR);
  594. }
  595. else if(!obj)
  596. {
  597. yaffsfs_SetError(-ENOENT);
  598. }
  599. else if(!isDirectory && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
  600. {
  601. yaffsfs_SetError(-EISDIR);
  602. }
  603. else if(isDirectory && obj->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
  604. {
  605. yaffsfs_SetError(-ENOTDIR);
  606. }
  607. else
  608. {
  609. result = yaffs_Unlink(dir,name);
  610. if(result == YAFFS_FAIL && isDirectory)
  611. {
  612. yaffsfs_SetError(-ENOTEMPTY);
  613. }
  614. }
  615. yaffsfs_Unlock();
  616. // todo error
  617. return (result == YAFFS_FAIL) ? -1 : 0;
  618. }
  619. int yaffs_rmdir(const char *path)
  620. {
  621. return yaffsfs_DoUnlink(path,1);
  622. }
  623. int yaffs_unlink(const char *path)
  624. {
  625. return yaffsfs_DoUnlink(path,0);
  626. }
  627. int yaffs_rename(const char *oldPath, const char *newPath)
  628. {
  629. yaffs_Object *olddir = NULL;
  630. yaffs_Object *newdir = NULL;
  631. yaffs_Object *obj = NULL;
  632. char *oldname;
  633. char *newname;
  634. int result= YAFFS_FAIL;
  635. int renameAllowed = 1;
  636. yaffsfs_Lock();
  637. olddir = yaffsfs_FindDirectory(NULL,oldPath,&oldname,0);
  638. newdir = yaffsfs_FindDirectory(NULL,newPath,&newname,0);
  639. obj = yaffsfs_FindObject(NULL,oldPath,0);
  640. if(!olddir || !newdir || !obj)
  641. {
  642. // bad file
  643. yaffsfs_SetError(-EBADF);
  644. renameAllowed = 0;
  645. }
  646. else if(olddir->myDev != newdir->myDev)
  647. {
  648. // oops must be on same device
  649. // todo error
  650. yaffsfs_SetError(-EXDEV);
  651. renameAllowed = 0;
  652. }
  653. else if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
  654. {
  655. // It is a directory, check that it is not being renamed to
  656. // being its own decendent.
  657. // Do this by tracing from the new directory back to the root, checking for obj
  658. yaffs_Object *xx = newdir;
  659. while( renameAllowed && xx)
  660. {
  661. if(xx == obj)
  662. {
  663. renameAllowed = 0;
  664. }
  665. xx = xx->parent;
  666. }
  667. if(!renameAllowed) yaffsfs_SetError(-EACCESS);
  668. }
  669. if(renameAllowed)
  670. {
  671. result = yaffs_RenameObject(olddir,oldname,newdir,newname);
  672. }
  673. yaffsfs_Unlock();
  674. return (result == YAFFS_FAIL) ? -1 : 0;
  675. }
  676. static int yaffsfs_DoStat(yaffs_Object *obj,struct yaffs_stat *buf)
  677. {
  678. int retVal = -1;
  679. if(obj)
  680. {
  681. obj = yaffs_GetEquivalentObject(obj);
  682. }
  683. if(obj && buf)
  684. {
  685. buf->st_dev = (int)obj->myDev->genericDevice;
  686. buf->st_ino = obj->objectId;
  687. buf->st_mode = obj->yst_mode & ~S_IFMT; // clear out file type bits
  688. if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
  689. {
  690. buf->st_mode |= S_IFDIR;
  691. }
  692. else if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
  693. {
  694. buf->st_mode |= S_IFLNK;
  695. }
  696. else if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
  697. {
  698. buf->st_mode |= S_IFREG;
  699. }
  700. buf->st_nlink = yaffs_GetObjectLinkCount(obj);
  701. buf->st_uid = 0;
  702. buf->st_gid = 0;;
  703. buf->st_rdev = obj->yst_rdev;
  704. buf->st_size = yaffs_GetObjectFileLength(obj);
  705. buf->st_blksize = obj->myDev->nDataBytesPerChunk;
  706. buf->st_blocks = (buf->st_size + buf->st_blksize -1)/buf->st_blksize;
  707. buf->yst_atime = obj->yst_atime;
  708. buf->yst_ctime = obj->yst_ctime;
  709. buf->yst_mtime = obj->yst_mtime;
  710. retVal = 0;
  711. }
  712. return retVal;
  713. }
  714. static int yaffsfs_DoStatOrLStat(const char *path, struct yaffs_stat *buf,int doLStat)
  715. {
  716. yaffs_Object *obj;
  717. int retVal = -1;
  718. yaffsfs_Lock();
  719. obj = yaffsfs_FindObject(NULL,path,0);
  720. if(!doLStat && obj)
  721. {
  722. obj = yaffsfs_FollowLink(obj,0);
  723. }
  724. if(obj)
  725. {
  726. retVal = yaffsfs_DoStat(obj,buf);
  727. }
  728. else
  729. {
  730. // todo error not found
  731. yaffsfs_SetError(-ENOENT);
  732. }
  733. yaffsfs_Unlock();
  734. return retVal;
  735. }
  736. int yaffs_stat(const char *path, struct yaffs_stat *buf)
  737. {
  738. return yaffsfs_DoStatOrLStat(path,buf,0);
  739. }
  740. int yaffs_lstat(const char *path, struct yaffs_stat *buf)
  741. {
  742. return yaffsfs_DoStatOrLStat(path,buf,1);
  743. }
  744. int yaffs_fstat(int fd, struct yaffs_stat *buf)
  745. {
  746. yaffs_Object *obj;
  747. int retVal = -1;
  748. yaffsfs_Lock();
  749. obj = yaffsfs_GetHandleObject(fd);
  750. if(obj)
  751. {
  752. retVal = yaffsfs_DoStat(obj,buf);
  753. }
  754. else
  755. {
  756. // bad handle
  757. yaffsfs_SetError(-EBADF);
  758. }
  759. yaffsfs_Unlock();
  760. return retVal;
  761. }
  762. static int yaffsfs_DoChMod(yaffs_Object *obj,mode_t mode)
  763. {
  764. int result = YAFFS_FAIL;
  765. if(obj)
  766. {
  767. obj = yaffs_GetEquivalentObject(obj);
  768. }
  769. if(obj)
  770. {
  771. obj->yst_mode = mode;
  772. obj->dirty = 1;
  773. result = yaffs_FlushFile(obj,0);
  774. }
  775. return result == YAFFS_OK ? 0 : -1;
  776. }
  777. int yaffs_chmod(const char *path, mode_t mode)
  778. {
  779. yaffs_Object *obj;
  780. int retVal = -1;
  781. yaffsfs_Lock();
  782. obj = yaffsfs_FindObject(NULL,path,0);
  783. if(obj)
  784. {
  785. retVal = yaffsfs_DoChMod(obj,mode);
  786. }
  787. else
  788. {
  789. // todo error not found
  790. yaffsfs_SetError(-ENOENT);
  791. }
  792. yaffsfs_Unlock();
  793. return retVal;
  794. }
  795. int yaffs_fchmod(int fd, mode_t mode)
  796. {
  797. yaffs_Object *obj;
  798. int retVal = -1;
  799. yaffsfs_Lock();
  800. obj = yaffsfs_GetHandleObject(fd);
  801. if(obj)
  802. {
  803. retVal = yaffsfs_DoChMod(obj,mode);
  804. }
  805. else
  806. {
  807. // bad handle
  808. yaffsfs_SetError(-EBADF);
  809. }
  810. yaffsfs_Unlock();
  811. return retVal;
  812. }
  813. int yaffs_mkdir(const char *path, mode_t mode)
  814. {
  815. yaffs_Object *parent = NULL;
  816. yaffs_Object *dir = NULL;
  817. char *name;
  818. int retVal= -1;
  819. yaffsfs_Lock();
  820. parent = yaffsfs_FindDirectory(NULL,path,&name,0);
  821. if(parent)
  822. dir = yaffs_MknodDirectory(parent,name,mode,0,0);
  823. if(dir)
  824. {
  825. retVal = 0;
  826. }
  827. else
  828. {
  829. yaffsfs_SetError(-ENOSPC); // just assume no space for now
  830. retVal = -1;
  831. }
  832. yaffsfs_Unlock();
  833. return retVal;
  834. }
  835. int yaffs_mount(const char *path)
  836. {
  837. int retVal=-1;
  838. int result=YAFFS_FAIL;
  839. yaffs_Device *dev=NULL;
  840. char *dummy;
  841. T(YAFFS_TRACE_ALWAYS,("yaffs: Mounting %s\n",path));
  842. yaffsfs_Lock();
  843. dev = yaffsfs_FindDevice(path,&dummy);
  844. if(dev)
  845. {
  846. if(!dev->isMounted)
  847. {
  848. result = yaffs_GutsInitialise(dev);
  849. if(result == YAFFS_FAIL)
  850. {
  851. // todo error - mount failed
  852. yaffsfs_SetError(-ENOMEM);
  853. }
  854. retVal = result ? 0 : -1;
  855. }
  856. else
  857. {
  858. //todo error - already mounted.
  859. yaffsfs_SetError(-EBUSY);
  860. }
  861. }
  862. else
  863. {
  864. // todo error - no device
  865. yaffsfs_SetError(-ENODEV);
  866. }
  867. yaffsfs_Unlock();
  868. return retVal;
  869. }
  870. int yaffs_unmount(const char *path)
  871. {
  872. int retVal=-1;
  873. yaffs_Device *dev=NULL;
  874. char *dummy;
  875. yaffsfs_Lock();
  876. dev = yaffsfs_FindDevice(path,&dummy);
  877. if(dev)
  878. {
  879. if(dev->isMounted)
  880. {
  881. int i;
  882. int inUse;
  883. yaffs_FlushEntireDeviceCache(dev);
  884. yaffs_CheckpointSave(dev);
  885. for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse; i++)
  886. {
  887. if(yaffsfs_handle[i].inUse && yaffsfs_handle[i].obj->myDev == dev)
  888. {
  889. inUse = 1; // the device is in use, can't unmount
  890. }
  891. }
  892. if(!inUse)
  893. {
  894. yaffs_Deinitialise(dev);
  895. retVal = 0;
  896. }
  897. else
  898. {
  899. // todo error can't unmount as files are open
  900. yaffsfs_SetError(-EBUSY);
  901. }
  902. }
  903. else
  904. {
  905. //todo error - not mounted.
  906. yaffsfs_SetError(-EINVAL);
  907. }
  908. }
  909. else
  910. {
  911. // todo error - no device
  912. yaffsfs_SetError(-ENODEV);
  913. }
  914. yaffsfs_Unlock();
  915. return retVal;
  916. }
  917. loff_t yaffs_freespace(const char *path)
  918. {
  919. loff_t retVal=-1;
  920. yaffs_Device *dev=NULL;
  921. char *dummy;
  922. yaffsfs_Lock();
  923. dev = yaffsfs_FindDevice(path,&dummy);
  924. if(dev && dev->isMounted)
  925. {
  926. retVal = yaffs_GetNumberOfFreeChunks(dev);
  927. retVal *= dev->nDataBytesPerChunk;
  928. }
  929. else
  930. {
  931. yaffsfs_SetError(-EINVAL);
  932. }
  933. yaffsfs_Unlock();
  934. return retVal;
  935. }
  936. void yaffs_initialise(yaffsfs_DeviceConfiguration *cfgList)
  937. {
  938. yaffsfs_DeviceConfiguration *cfg;
  939. yaffsfs_configurationList = cfgList;
  940. yaffsfs_InitHandles();
  941. cfg = yaffsfs_configurationList;
  942. while(cfg && cfg->prefix && cfg->dev)
  943. {
  944. cfg->dev->isMounted = 0;
  945. cfg->dev->removeObjectCallback = yaffsfs_RemoveObjectCallback;
  946. cfg++;
  947. }
  948. }
  949. //
  950. // Directory search stuff.
  951. //
  952. // Directory search context
  953. //
  954. // NB this is an opaque structure.
  955. typedef struct
  956. {
  957. __u32 magic;
  958. yaffs_dirent de; /* directory entry being used by this dsc */
  959. char name[NAME_MAX+1]; /* name of directory being searched */
  960. yaffs_Object *dirObj; /* ptr to directory being searched */
  961. yaffs_Object *nextReturn; /* obj to be returned by next readddir */
  962. int offset;
  963. struct list_head others;
  964. } yaffsfs_DirectorySearchContext;
  965. static struct list_head search_contexts;
  966. static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc)
  967. {
  968. if(dsc &&
  969. dsc->dirObj &&
  970. dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
  971. dsc->offset = 0;
  972. if( list_empty(&dsc->dirObj->variant.directoryVariant.children)){
  973. dsc->nextReturn = NULL;
  974. } else {
  975. dsc->nextReturn = list_entry(dsc->dirObj->variant.directoryVariant.children.next,
  976. yaffs_Object,siblings);
  977. }
  978. } else {
  979. /* Hey someone isn't playing nice! */
  980. }
  981. }
  982. static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc)
  983. {
  984. if(dsc &&
  985. dsc->dirObj &&
  986. dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
  987. if( dsc->nextReturn == NULL ||
  988. list_empty(&dsc->dirObj->variant.directoryVariant.children)){
  989. dsc->nextReturn = NULL;
  990. } else {
  991. struct list_head *next = dsc->nextReturn->siblings.next;
  992. if( next == &dsc->dirObj->variant.directoryVariant.children)
  993. dsc->nextReturn = NULL; /* end of list */
  994. else
  995. dsc->nextReturn = list_entry(next,yaffs_Object,siblings);
  996. }
  997. } else {
  998. /* Hey someone isn't playing nice! */
  999. }
  1000. }
  1001. static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj)
  1002. {
  1003. struct list_head *i;
  1004. yaffsfs_DirectorySearchContext *dsc;
  1005. /* if search contexts not initilised then skip */
  1006. if(!search_contexts.next)
  1007. return;
  1008. /* Iteratethrough the directory search contexts.
  1009. * If any are the one being removed, then advance the dsc to
  1010. * the next one to prevent a hanging ptr.
  1011. */
  1012. list_for_each(i, &search_contexts) {
  1013. if (i) {
  1014. dsc = list_entry(i, yaffsfs_DirectorySearchContext,others);
  1015. if(dsc->nextReturn == obj)
  1016. yaffsfs_DirAdvance(dsc);
  1017. }
  1018. }
  1019. }
  1020. yaffs_DIR *yaffs_opendir(const char *dirname)
  1021. {
  1022. yaffs_DIR *dir = NULL;
  1023. yaffs_Object *obj = NULL;
  1024. yaffsfs_DirectorySearchContext *dsc = NULL;
  1025. yaffsfs_Lock();
  1026. obj = yaffsfs_FindObject(NULL,dirname,0);
  1027. if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
  1028. {
  1029. dsc = YMALLOC(sizeof(yaffsfs_DirectorySearchContext));
  1030. dir = (yaffs_DIR *)dsc;
  1031. if(dsc)
  1032. {
  1033. memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext));
  1034. dsc->magic = YAFFS_MAGIC;
  1035. dsc->dirObj = obj;
  1036. strncpy(dsc->name,dirname,NAME_MAX);
  1037. INIT_LIST_HEAD(&dsc->others);
  1038. if(!search_contexts.next)
  1039. INIT_LIST_HEAD(&search_contexts);
  1040. list_add(&dsc->others,&search_contexts);
  1041. yaffsfs_SetDirRewound(dsc); }
  1042. }
  1043. yaffsfs_Unlock();
  1044. return dir;
  1045. }
  1046. struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp)
  1047. {
  1048. yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
  1049. struct yaffs_dirent *retVal = NULL;
  1050. yaffsfs_Lock();
  1051. if(dsc && dsc->magic == YAFFS_MAGIC){
  1052. yaffsfs_SetError(0);
  1053. if(dsc->nextReturn){
  1054. dsc->de.d_ino = yaffs_GetEquivalentObject(dsc->nextReturn)->objectId;
  1055. dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
  1056. dsc->de.d_off = dsc->offset++;
  1057. yaffs_GetObjectName(dsc->nextReturn,dsc->de.d_name,NAME_MAX);
  1058. if(strlen(dsc->de.d_name) == 0)
  1059. {
  1060. // this should not happen!
  1061. strcpy(dsc->de.d_name,"zz");
  1062. }
  1063. dsc->de.d_reclen = sizeof(struct yaffs_dirent);
  1064. retVal = &dsc->de;
  1065. yaffsfs_DirAdvance(dsc);
  1066. } else
  1067. retVal = NULL;
  1068. }
  1069. else
  1070. {
  1071. yaffsfs_SetError(-EBADF);
  1072. }
  1073. yaffsfs_Unlock();
  1074. return retVal;
  1075. }
  1076. void yaffs_rewinddir(yaffs_DIR *dirp)
  1077. {
  1078. yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
  1079. yaffsfs_Lock();
  1080. yaffsfs_SetDirRewound(dsc);
  1081. yaffsfs_Unlock();
  1082. }
  1083. int yaffs_closedir(yaffs_DIR *dirp)
  1084. {
  1085. yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
  1086. yaffsfs_Lock();
  1087. dsc->magic = 0;
  1088. list_del(&dsc->others); /* unhook from list */
  1089. YFREE(dsc);
  1090. yaffsfs_Unlock();
  1091. return 0;
  1092. }
  1093. // end of directory stuff
  1094. int yaffs_symlink(const char *oldpath, const char *newpath)
  1095. {
  1096. yaffs_Object *parent = NULL;
  1097. yaffs_Object *obj;
  1098. char *name;
  1099. int retVal= -1;
  1100. int mode = 0; // ignore for now
  1101. yaffsfs_Lock();
  1102. parent = yaffsfs_FindDirectory(NULL,newpath,&name,0);
  1103. obj = yaffs_MknodSymLink(parent,name,mode,0,0,oldpath);
  1104. if(obj)
  1105. {
  1106. retVal = 0;
  1107. }
  1108. else
  1109. {
  1110. yaffsfs_SetError(-ENOSPC); // just assume no space for now
  1111. retVal = -1;
  1112. }
  1113. yaffsfs_Unlock();
  1114. return retVal;
  1115. }
  1116. int yaffs_readlink(const char *path, char *buf, int bufsiz)
  1117. {
  1118. yaffs_Object *obj = NULL;
  1119. int retVal;
  1120. yaffsfs_Lock();
  1121. obj = yaffsfs_FindObject(NULL,path,0);
  1122. if(!obj)
  1123. {
  1124. yaffsfs_SetError(-ENOENT);
  1125. retVal = -1;
  1126. }
  1127. else if(obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK)
  1128. {
  1129. yaffsfs_SetError(-EINVAL);
  1130. retVal = -1;
  1131. }
  1132. else
  1133. {
  1134. char *alias = obj->variant.symLinkVariant.alias;
  1135. memset(buf,0,bufsiz);
  1136. strncpy(buf,alias,bufsiz - 1);
  1137. retVal = 0;
  1138. }
  1139. yaffsfs_Unlock();
  1140. return retVal;
  1141. }
  1142. int yaffs_link(const char *oldpath, const char *newpath)
  1143. {
  1144. // Creates a link called newpath to existing oldpath
  1145. yaffs_Object *obj = NULL;
  1146. yaffs_Object *target = NULL;
  1147. int retVal = 0;
  1148. yaffsfs_Lock();
  1149. obj = yaffsfs_FindObject(NULL,oldpath,0);
  1150. target = yaffsfs_FindObject(NULL,newpath,0);
  1151. if(!obj)
  1152. {
  1153. yaffsfs_SetError(-ENOENT);
  1154. retVal = -1;
  1155. }
  1156. else if(target)
  1157. {
  1158. yaffsfs_SetError(-EEXIST);
  1159. retVal = -1;
  1160. }
  1161. else
  1162. {
  1163. yaffs_Object *newdir = NULL;
  1164. yaffs_Object *link = NULL;
  1165. char *newname;
  1166. newdir = yaffsfs_FindDirectory(NULL,newpath,&newname,0);
  1167. if(!newdir)
  1168. {
  1169. yaffsfs_SetError(-ENOTDIR);
  1170. retVal = -1;
  1171. }
  1172. else if(newdir->myDev != obj->myDev)
  1173. {
  1174. yaffsfs_SetError(-EXDEV);
  1175. retVal = -1;
  1176. }
  1177. if(newdir && strlen(newname) > 0)
  1178. {
  1179. link = yaffs_Link(newdir,newname,obj);
  1180. if(link)
  1181. retVal = 0;
  1182. else
  1183. {
  1184. yaffsfs_SetError(-ENOSPC);
  1185. retVal = -1;
  1186. }
  1187. }
  1188. }
  1189. yaffsfs_Unlock();
  1190. return retVal;
  1191. }
  1192. int yaffs_mknod(const char *pathname, mode_t mode, dev_t dev);
  1193. int yaffs_DumpDevStruct(const char *path)
  1194. {
  1195. char *rest;
  1196. yaffs_Object *obj = yaffsfs_FindRoot(path,&rest);
  1197. if(obj)
  1198. {
  1199. yaffs_Device *dev = obj->myDev;
  1200. printf("\n"
  1201. "nPageWrites.......... %d\n"
  1202. "nPageReads........... %d\n"
  1203. "nBlockErasures....... %d\n"
  1204. "nGCCopies............ %d\n"
  1205. "garbageCollections... %d\n"
  1206. "passiveGarbageColl'ns %d\n"
  1207. "\n",
  1208. dev->nPageWrites,
  1209. dev->nPageReads,
  1210. dev->nBlockErasures,
  1211. dev->nGCCopies,
  1212. dev->garbageCollections,
  1213. dev->passiveGarbageCollections
  1214. );
  1215. }
  1216. return 0;
  1217. }