pnutfs.c 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398
  1. /*
  2. * Copyright (C) 2004-2006 by egnite Software GmbH. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the copyright holders nor the names of
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  24. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  25. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  26. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  27. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. *
  30. * For additional information see http://www.ethernut.de/
  31. */
  32. /*!
  33. * \file fs/pnutfs.c
  34. * \brief Peanut File System.
  35. *
  36. * \verbatim
  37. *
  38. * $Log$
  39. * Revision 1.16 2009/02/13 14:52:05 haraldkipp
  40. * Include memdebug.h for heap management debugging support.
  41. *
  42. * Revision 1.15 2009/01/17 11:26:46 haraldkipp
  43. * Getting rid of two remaining BSD types in favor of stdint.
  44. * Replaced 'u_int' by 'unsinged int' and 'uptr_t' by 'uintptr_t'.
  45. *
  46. * Revision 1.14 2008/08/27 06:45:23 thornen
  47. * Added bank support for MMnet03..04 MMnet102..104
  48. *
  49. * Revision 1.13 2008/08/26 17:36:45 haraldkipp
  50. * Revoked changes 2008/08/26 by thornen.
  51. *
  52. * Revision 1.11 2008/08/11 06:59:42 haraldkipp
  53. * BSD types replaced by stdint types (feature request #1282721).
  54. *
  55. * Revision 1.10 2006/08/01 07:43:48 haraldkipp
  56. * PNUT file system failed after some modifications done previously for the
  57. * PHAT file system. During directory open, the NUTFILE structure must be
  58. * allocated in the file system driver. PnutDirRead() must return -1 if the
  59. * end of a directory is reached. Reading unused directory entries must update
  60. * the file position pointer.
  61. *
  62. * Revision 1.9 2006/03/02 20:01:17 haraldkipp
  63. * Added implementation of dev_size makes _filelength() work, which in turn
  64. * enables the use of this file system in pro/httpd.c.
  65. *
  66. * Revision 1.8 2006/01/05 16:45:20 haraldkipp
  67. * Dynamic NUTFILE allocation for detached block device.
  68. *
  69. * Revision 1.7 2005/09/08 10:12:44 olereinhardt
  70. * Added #ifdef statement in NutSegBufEnable to avoid compiler warning
  71. * if no banked mem is used.
  72. *
  73. * Revision 1.6 2005/09/07 16:23:41 christianwelzel
  74. * Added support for MMnet02. Bankswitching is now handled in bankmem.h
  75. *
  76. * Revision 1.5 2005/08/02 17:46:47 haraldkipp
  77. * Major API documentation update.
  78. *
  79. * Revision 1.4 2005/05/16 08:33:59 haraldkipp
  80. * Added banking support for Arthernet.
  81. *
  82. * Revision 1.3 2005/02/21 11:10:21 olereinhardt
  83. * Changed deckaration of the "root" variable to compile with unix emulation
  84. *
  85. * Revision 1.2 2005/02/07 18:57:47 haraldkipp
  86. * ICCAVR compile errors fixed
  87. *
  88. * Revision 1.1 2005/02/05 20:35:21 haraldkipp
  89. * Peanut added
  90. *
  91. * \endverbatim
  92. */
  93. #include <compiler.h>
  94. #include <stdlib.h>
  95. #include <string.h>
  96. #include <time.h>
  97. #include <fcntl.h>
  98. #include <dirent.h>
  99. #include <errno.h>
  100. #include <memdebug.h>
  101. #include <sys/stat.h>
  102. #include <sys/file.h>
  103. #include <sys/bankmem.h>
  104. #include <fs/fs.h>
  105. #include <dev/pnut.h>
  106. /*!
  107. * \addtogroup xgPNut
  108. */
  109. /*@{*/
  110. /*!
  111. * \name Peanut File System Configuration
  112. *
  113. * The Nut/OS Configurator may be used to override the default values.
  114. */
  115. /*@{*/
  116. /*! \brief Size of a filesystem block.
  117. *
  118. * \showinitializer
  119. */
  120. #ifndef PNUT_BLOCK_SIZE
  121. #define PNUT_BLOCK_SIZE 512
  122. #endif
  123. /*!
  124. * \brief Size of a directory entry.
  125. *
  126. *
  127. * \showinitializer
  128. */
  129. #ifndef PNUT_DIRENT_SIZE
  130. #define PNUT_DIRENT_SIZE 32
  131. #endif
  132. /*!
  133. * \brief Maximum number of blocks per node.
  134. *
  135. * Peanut supports only one node per file. Thus, this number
  136. * multiplied by PNUT_BLOCK_SIZE specifies the maximum file
  137. * size.
  138. *
  139. * Changings this number will change the size of the node
  140. * structure, which must fit into a single filesystem block.
  141. *
  142. * \showinitializer
  143. */
  144. #ifndef PNUT_BLOCKS_PER_NODE
  145. #define PNUT_BLOCKS_PER_NODE 250
  146. #endif
  147. #ifndef PNUTBANK_COUNT
  148. #ifdef ARTHERNET1
  149. /* Default for Arthernet 1. */
  150. #define PNUTBANK_COUNT 15
  151. #elif MMNET02 || MMNET03 || MMNET04 ||\
  152. MMNET102 || MMNET103 || MMNET104
  153. /* Default for MMnte02. */
  154. #define PNUTBANK_COUNT 6
  155. #else
  156. /* Default for Ethernet 2. */
  157. #define PNUTBANK_COUNT 30
  158. #endif
  159. #endif
  160. /*@}*/
  161. #ifndef SEEK_SET
  162. # define SEEK_SET 0 /* Seek from beginning of file. */
  163. # define SEEK_CUR 1 /* Seek from current position. */
  164. # define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
  165. #endif
  166. #define NODETYPE_REG 0
  167. #define NODETYPE_DIR 1
  168. typedef short PNUT_BLKNUM;
  169. /*!
  170. * \brief Node structure.
  171. *
  172. * The Peanut filesystem divides the total space into blocks. It
  173. * distinguishes between unallocated blocks, data blocks and blocks
  174. * containing node informations. Each allocated data block is
  175. * associated to a node block. Unallocated blocks are collected
  176. * in a linked list.
  177. *
  178. * Peanut knows two types of nodes, file nodes and directory nodes.
  179. * Each file node represents a file entry and the associated data
  180. * blocks contain the contents of this file. Each directory node
  181. * represents a directory and the associated data blocks contain
  182. * the entries in this directory. Each directory entry in use
  183. * contains a link to to a node block.
  184. *
  185. * \note The node structure must fit into a block.
  186. */
  187. typedef struct {
  188. uint8_t node_type; /*!< Type of this node, 0=file, 1=dir */
  189. uint8_t node_refs; /*!< Reference counter: Number of active open calls. */
  190. /*!
  191. * \brief Number of links.
  192. *
  193. * For file nodes this number keeps track of the number of directory
  194. * entries pointing to it. PNUT currently doesn't support link type
  195. * entries, thus in file entries this is always 1.
  196. *
  197. * For directory nodes the number represents the number
  198. * of subdirectories plus 2.
  199. */
  200. uint16_t node_links;
  201. uint32_t node_size; /*!< Total size of the data area. */
  202. time_t node_mtime; /*!< Time of last modification. */
  203. PNUT_BLKNUM node_blocks[PNUT_BLOCKS_PER_NODE]; /*!< Allocated data blocks. */
  204. } PNUT_NODE;
  205. /*!
  206. * \brief Maximum length of a base name.
  207. *
  208. * This is a calculated value and depends on the definition of the
  209. * block size and the size of a directory entry.
  210. */
  211. #define PNUT_MAX_NAMELEN (PNUT_DIRENT_SIZE - sizeof(PNUT_BLKNUM) - sizeof(uint8_t) - 1)
  212. /*!
  213. * \brief Directory entry structure.
  214. *
  215. * Each directory node contains a list of data blocks. Each of these
  216. * data blocks contains a number of directory entries. Each directory
  217. * entry points to a node block, which may be a file node or a
  218. * directory node.
  219. */
  220. typedef struct {
  221. /*!
  222. * \brief Node block index of this entry.
  223. *
  224. * This may point to a file or directory node.
  225. */
  226. PNUT_BLKNUM dir_node;
  227. /*!
  228. * \brief Allocation flag.
  229. *
  230. * Set to one if this entry is in use.
  231. */
  232. uint8_t dir_inuse;
  233. /*!
  234. * \brief Name of this entry.
  235. *
  236. * Contains the name ot the file or directory.
  237. */
  238. char dir_name[PNUT_MAX_NAMELEN + 1];
  239. } PNUT_DIRENTRY;
  240. /*!
  241. * \brief Maximum size of a file or directory.
  242. *
  243. * This is a calculated value and depends on the definition of the
  244. * block size and the number of blocks per directory entry.
  245. */
  246. #define PNUT_MAX_FILESIZE (PNUT_BLOCKS_PER_NODE * PNUT_BLOCK_SIZE)
  247. /*!
  248. * \brief Directory search result information structure.
  249. */
  250. typedef struct {
  251. /*!
  252. * \brief Node of the entry found.
  253. */
  254. PNUT_BLKNUM fr_node;
  255. /*!
  256. * \brief Parent node of the entry found.
  257. */
  258. PNUT_BLKNUM fr_pnode;
  259. /*!
  260. * \brief Last path component.
  261. *
  262. * Set if all parents found.
  263. */
  264. const char *fr_name;
  265. } PNUT_FINDRESULT;
  266. /*!
  267. * \brief PNUT file descriptor type.
  268. */
  269. typedef struct _PNUTFILE PNUTFILE;
  270. /*!
  271. * \brief PNUT file descriptor structure.
  272. */
  273. struct _PNUTFILE {
  274. PNUT_BLKNUM f_node; /* Node of the file or directory. */
  275. uint32_t f_pos; /* Current file pointer position. */
  276. unsigned int f_flag; /* File mode. */
  277. };
  278. /*! \brief Root node of the filesystem. */
  279. static PNUT_BLKNUM root;
  280. /* -------------------- Banking hardware routines ------------------- */
  281. /*! \brief Size of each memory bank. */
  282. #ifndef NUTBANK_SIZE
  283. #define NUTBANK_SIZE 16384
  284. #endif
  285. /*!
  286. * \brief Total number of blocks on this device.
  287. *
  288. * This value is calulated by multiplying the number of memory banks
  289. * reserved for the file system by the number of blocks per bank.
  290. *
  291. * For example, if all 30 banks, which are available on Ethernut 2, are
  292. * reserved for PNUT and if the size of a block is 512 bytes, then
  293. * 960 blocks are available.
  294. */
  295. #ifndef PNUT_TOTAL_BLOCKS
  296. #define PNUT_TOTAL_BLOCKS (PNUTBANK_COUNT * (NUTBANK_SIZE / PNUT_BLOCK_SIZE))
  297. #endif
  298. #define BLOCKS_PER_BANK (NUTBANK_SIZE / PNUT_BLOCK_SIZE)
  299. #ifndef NUTBANK_SR
  300. #define NUTBANK_SR 0xFF00
  301. #endif
  302. #ifndef NUTBANK_START
  303. #define NUTBANK_START 0x8000
  304. #endif
  305. #define NUTBANK_PTR ((char *)NUTBANK_START)
  306. /*!
  307. * \brief Make the bank visible, which contains the specified block.
  308. *
  309. * On Ethernut 2 we select a bank by writing the bank number to
  310. * the bank register base address plus the bank number.
  311. *
  312. * For example, writing 0x12 to 0xFF12 selects bank 18 (0x12),
  313. * assuming that 0xFF00 is the bank register base address.
  314. *
  315. * \param blk Block number to access.
  316. */
  317. void BankSelect(PNUT_BLKNUM blk)
  318. {
  319. // This is a hack to avoid compiler warning if no banking is enabled...
  320. // But I don't like moving code to header files at all.. (Ole Reinhardt)
  321. #if NUTBANK_COUNT
  322. int bank = blk / BLOCKS_PER_BANK;
  323. #endif
  324. // Bankswitching is now handled in bankmem.h
  325. NutSegBufEnable(bank);
  326. }
  327. /*!
  328. * \brief Select specified bank and return pointer to block.
  329. */
  330. PNUT_NODE *BankNodePointer(PNUT_BLKNUM blk)
  331. {
  332. if (blk < 0) {
  333. return NULL;
  334. }
  335. BankSelect(blk);
  336. return (PNUT_NODE *) & NUTBANK_PTR[(blk % BLOCKS_PER_BANK) * PNUT_BLOCK_SIZE];
  337. }
  338. /* ------------------------ Block routines ------------------------ */
  339. /*
  340. * \brief Index of the first free block.
  341. *
  342. * All free blocks are collected in a linked list. This global variable
  343. * contains the index of the first free block. Each free block contains
  344. * nothing but the index of the next free block, which is -1 in the last
  345. * member of this list.
  346. *
  347. * If this variable is set to -1, then there are no more free blocks
  348. * available. During file system initialization all available blocks are
  349. * added to this list.
  350. */
  351. static PNUT_BLKNUM blockFreeList = -1;
  352. /*!
  353. * \brief Allocate a block.
  354. *
  355. * Removes the block in front of the list of free blocks.
  356. *
  357. * \return Index of the free block or -1 if none is available.
  358. */
  359. static PNUT_BLKNUM PnutBlockAlloc(void)
  360. {
  361. PNUT_BLKNUM rc = blockFreeList;
  362. if (rc >= 0) {
  363. PNUT_BLKNUM *bankptr = (PNUT_BLKNUM *) BankNodePointer(blockFreeList);
  364. blockFreeList = *bankptr;
  365. /* Clear the block contents. */
  366. memset(bankptr, 0, PNUT_BLOCK_SIZE);
  367. }
  368. return rc;
  369. }
  370. /*!
  371. * \brief Release a block.
  372. *
  373. * Inserts a given block in front of the list of free blocks.
  374. *
  375. * \param blk Index of the block to be released.
  376. */
  377. static void PnutBlockRelease(PNUT_BLKNUM blk)
  378. {
  379. PNUT_BLKNUM *bankptr = (PNUT_BLKNUM *) BankNodePointer(blk);
  380. *bankptr = blockFreeList;
  381. blockFreeList = blk;
  382. }
  383. /* ------------------------ Node routines ------------------------ */
  384. /*!
  385. * \brief Allocate a node.
  386. *
  387. * Creates a new node of a specified type.
  388. *
  389. * \param type Type of this node, either NODETYPE_REG or NODETYPE_DIR.
  390. *
  391. * \return Block index of this node or -1 if there are no more blocks.
  392. */
  393. static PNUT_BLKNUM PnutNodeAlloc(uint8_t type)
  394. {
  395. PNUT_BLKNUM node = PnutBlockAlloc();
  396. if (node >= 0) {
  397. int i;
  398. PNUT_NODE *np = BankNodePointer(node);
  399. /* Clear the data block list of this node. */
  400. for (i = 0; i < PNUT_BLOCKS_PER_NODE; i++) {
  401. np->node_blocks[i] = -1;
  402. }
  403. /* Set the type and the last modification date. */
  404. np->node_type = type;
  405. np->node_mtime = time(0);
  406. }
  407. return node;
  408. }
  409. /*
  410. * \brief Free all blocks of a specified node.
  411. */
  412. static void PnutNodeDataRelease(PNUT_BLKNUM node)
  413. {
  414. int i;
  415. for (i = 0; i < PNUT_BLOCKS_PER_NODE; i++) {
  416. if (BankNodePointer(node)->node_blocks[i] >= 0) {
  417. PnutBlockRelease(BankNodePointer(node)->node_blocks[i]);
  418. BankNodePointer(node)->node_blocks[i] = -1;
  419. }
  420. }
  421. BankNodePointer(node)->node_size = 0;
  422. BankNodePointer(node)->node_mtime = time(0);
  423. }
  424. /*!
  425. * \brief Release a node and all its data blocks.
  426. */
  427. static void PnutNodeRelease(PNUT_BLKNUM node)
  428. {
  429. PnutNodeDataRelease(node);
  430. PnutBlockRelease(node);
  431. }
  432. /*!
  433. * \brief Retrieve a pointer into a node's data block.
  434. *
  435. * This function also returns the number of bytes available within
  436. * the data block at the retrieved pointer position.
  437. *
  438. * \param node Node number.
  439. * \param pos Data position.
  440. * \param buffer Receives the pointer to the specified position.
  441. * \param size Receives the remaining number of bytes within the block.
  442. * \param create If the position is beyond the current data size and if
  443. * this parameter is not equal zero, then a new data block
  444. * will be allocated.
  445. *
  446. * \return 0 on success, otherwise returns an error code.
  447. */
  448. static int PnutNodeGetDataPtr(PNUT_BLKNUM node, uint32_t pos, uint8_t **buffer, size_t * size, int create)
  449. {
  450. int blkidx; /* Number of full blocks */
  451. int rc = EINVAL;
  452. *buffer = NULL;
  453. *size = 0;
  454. /* Calculate the block index. Make sure it fits in our maximum file size. */
  455. if ((blkidx = pos / PNUT_BLOCK_SIZE) < PNUT_BLOCKS_PER_NODE) {
  456. PNUT_BLKNUM blk;
  457. /* Get the data block number. Optionally allocate a new block. */
  458. if ((blk = BankNodePointer(node)->node_blocks[blkidx]) < 0 && create) {
  459. if ((blk = PnutBlockAlloc()) < 0) {
  460. rc = ENOSPC;
  461. } else {
  462. BankNodePointer(node)->node_blocks[blkidx] = blk;
  463. }
  464. }
  465. /*
  466. * If we got a valid block, then set the pointer at the specified
  467. * position and the remaining bytes within this block.
  468. */
  469. if (blk >= 0) {
  470. uint8_t *blkptr = (uint8_t *) BankNodePointer(blk);
  471. int blkpos = pos % PNUT_BLOCK_SIZE; /* Position within block */
  472. *buffer = blkptr + blkpos;
  473. *size = PNUT_BLOCK_SIZE - blkpos;
  474. rc = 0;
  475. }
  476. }
  477. return rc;
  478. }
  479. /* ------------------------ Directory routines ------------------------ */
  480. /*!
  481. * \brief Check if a directory is empty.
  482. */
  483. static int PnutDirIsEmpty(PNUT_BLKNUM node)
  484. {
  485. int rc = 1;
  486. uint32_t pos;
  487. size_t size;
  488. PNUT_DIRENTRY *entry = NULL;
  489. /* Loop through the data blocks of this directory node. */
  490. for (pos = 0; pos < BankNodePointer(node)->node_size; pos += PNUT_DIRENT_SIZE) {
  491. /* Get the pointer to the next directory entry. */
  492. uint8_t *ptr = (uint8_t *)entry;
  493. if (PnutNodeGetDataPtr(node, pos, &ptr, &size, 0) || size == 0) {
  494. /* No more entries. */
  495. break;
  496. }
  497. entry = (PNUT_DIRENTRY *)ptr;
  498. if (size >= PNUT_DIRENT_SIZE) {
  499. if (entry->dir_inuse && strcmp(entry->dir_name, ".") && strcmp(entry->dir_name, "..")) {
  500. /* Entry found */
  501. rc = 0;
  502. break;
  503. }
  504. }
  505. }
  506. return rc;
  507. }
  508. /*!
  509. * \brief Find a directory entry with a specified name.
  510. *
  511. * \param node Node of the directory to search.
  512. * \param path Path name of the entry to retrieve.
  513. * \param len Number of characters in the path name to consider,
  514. * starting from the beginning. If the path name
  515. * contains more than one component, the caller must
  516. * set this parameter to the length of the first one.
  517. * \param entry Receives the pointer to the directory entry.
  518. *
  519. * \return 0 on succes, otherwise an error code is returned.
  520. */
  521. static int PnutDirFindEntry(PNUT_BLKNUM node, const char *path, size_t len, PNUT_DIRENTRY ** entry)
  522. {
  523. int rc = ENOENT;
  524. uint32_t pos;
  525. size_t size;
  526. /* Loop through the data blocks of this directory node. */
  527. for (pos = 0; pos < BankNodePointer(node)->node_size; pos += PNUT_DIRENT_SIZE) {
  528. /* Get the pointer to the next directory entry. */
  529. uint8_t *ptr = (uint8_t *)(*entry);
  530. if (PnutNodeGetDataPtr(node, pos, &ptr, &size, 0) || size == 0) {
  531. /* No more entries. */
  532. break;
  533. }
  534. *entry = (PNUT_DIRENTRY *)ptr;
  535. /* Compare this entry. */
  536. if (size >= PNUT_DIRENT_SIZE) { /* Skip entries across block boundaries. */
  537. if ((*entry)->dir_inuse && /* Skip unused entries. */
  538. strlen((*entry)->dir_name) == len && /* Skip non-matching names. */
  539. strncmp((*entry)->dir_name, path, len) == 0) {
  540. /* Requested entry found */
  541. rc = 0;
  542. break;
  543. }
  544. }
  545. }
  546. return rc;
  547. }
  548. /*
  549. * \brief Find directory entry of a specified path.
  550. *
  551. * \param node First node block to search.
  552. * \param path Path to find.
  553. * \param result Search result.
  554. *
  555. * \return Error code.
  556. */
  557. static int PnutDirFindPath(PNUT_BLKNUM node, const char *path, PNUT_FINDRESULT * result)
  558. {
  559. int rc = 0;
  560. size_t len;
  561. PNUT_DIRENTRY *entry = NULL;
  562. result->fr_pnode = node;
  563. result->fr_node = -1;
  564. result->fr_name = NULL;
  565. while (*path == '/') {
  566. path++;
  567. }
  568. if (*path == 0) {
  569. path = ".";
  570. }
  571. /*
  572. * Loop for each path component.
  573. */
  574. while (*path) {
  575. const char *cp;
  576. /* Make sure that this is a directory node. */
  577. if (BankNodePointer(node)->node_type != NODETYPE_DIR) {
  578. rc = ENOTDIR;
  579. break;
  580. }
  581. /* Retrieve the length of first path component. */
  582. for (len = 0, cp = path; *cp && *cp != '/'; cp++) {
  583. len++;
  584. }
  585. /*
  586. * If this component is last, we found all parents.
  587. * Keep the last one stored in the result.
  588. */
  589. if (*cp == 0) {
  590. result->fr_name = path;
  591. }
  592. /* Try to find this component. */
  593. if ((rc = PnutDirFindEntry(node, path, len, &entry)) != 0) {
  594. rc = ENOENT;
  595. break;
  596. }
  597. /* Component found. Return if this was the last one. */
  598. result->fr_node = entry->dir_node;
  599. if (*cp == 0) {
  600. break;
  601. }
  602. /* Not the last component. Store node as previous node. */
  603. result->fr_pnode = result->fr_node;
  604. /* Move forward to the next path component. */
  605. node = result->fr_node;
  606. path += len;
  607. while (*path == '/') {
  608. path++;
  609. }
  610. }
  611. return rc;
  612. }
  613. /*!
  614. * \brief Open a directory.
  615. *
  616. * \param dev Specifies the file system device.
  617. * \param dir Pointer to the internal directory information structure.
  618. * The pathname of the directory to open must have been
  619. * copied to the data buffer prior calling this routine.
  620. *
  621. * \return 0 on success, -1 otherwise.
  622. */
  623. static int PnutDirOpen(NUTDEVICE * dev, DIR * dir)
  624. {
  625. PNUTFILE *fp;
  626. PNUT_FINDRESULT found;
  627. int rc;
  628. /* Locate the entry in our directory structure. */
  629. if ((rc = PnutDirFindPath(root, dir->dd_buf, &found)) != 0) {
  630. errno = rc;
  631. rc = -1;
  632. } else {
  633. if (BankNodePointer(found.fr_node)->node_type != NODETYPE_DIR) {
  634. errno = ENOTDIR;
  635. rc = -1;
  636. }
  637. /* Allocate a PNUT file descriptor. */
  638. else if ((fp = malloc(sizeof(PNUTFILE))) == 0) {
  639. rc = -1;
  640. }
  641. /*
  642. * Initialize the descriptor and store it in the directory
  643. * information structure.
  644. */
  645. else {
  646. fp->f_node = found.fr_node;
  647. fp->f_pos = 0;
  648. if ((dir->dd_fd = malloc(sizeof(NUTFILE))) == 0) {
  649. free(fp);
  650. rc = -1;
  651. }
  652. else {
  653. memset(dir->dd_fd, 0, sizeof(NUTFILE));
  654. dir->dd_fd->nf_dev = dev;
  655. dir->dd_fd->nf_fcb = fp;
  656. /* Keep track of the number of open calls. */
  657. BankNodePointer(fp->f_node)->node_refs++;
  658. }
  659. }
  660. }
  661. return rc;
  662. }
  663. /*!
  664. * \brief Close a directory.
  665. */
  666. static int PnutDirClose(DIR * dir)
  667. {
  668. if (dir && dir->dd_fd) {
  669. if (dir->dd_fd->nf_fcb) {
  670. PNUTFILE *fp = dir->dd_fd->nf_fcb;
  671. BankNodePointer(fp->f_node)->node_refs--;
  672. free(fp);
  673. }
  674. free(dir->dd_fd);
  675. return 0;
  676. }
  677. return EINVAL;
  678. }
  679. /*!
  680. * \brief Read the next directory entry.
  681. */
  682. static int PnutDirRead(DIR * dir)
  683. {
  684. int rc = -1;
  685. uint32_t pos;
  686. PNUT_DIRENTRY *entry = NULL;
  687. size_t size;
  688. PNUTFILE *fp = dir->dd_fd->nf_fcb;
  689. struct dirent *ent = (struct dirent *) dir->dd_buf;
  690. ent->d_name[0] = 0;
  691. for (pos = fp->f_pos; pos < BankNodePointer(fp->f_node)->node_size; pos += PNUT_DIRENT_SIZE) {
  692. uint8_t *ptr = (uint8_t *)entry;
  693. /* Retrieve the entry at the current position. */
  694. rc = PnutNodeGetDataPtr(fp->f_node, pos, &ptr, &size, 0);
  695. if (rc || size == 0) {
  696. /* No more entries. */
  697. rc = -1;
  698. break;
  699. }
  700. entry = (PNUT_DIRENTRY *)ptr;
  701. fp->f_pos = pos + PNUT_DIRENT_SIZE;
  702. /* Skip entries across block boundaries and unused entires. */
  703. if (size >= PNUT_DIRENT_SIZE && entry->dir_inuse) {
  704. memset(ent, 0, sizeof(struct dirent));
  705. ent->d_fileno = entry->dir_node;
  706. ent->d_namlen = (uint8_t) strlen(entry->dir_name);
  707. strcpy(ent->d_name, entry->dir_name);
  708. break;
  709. }
  710. }
  711. return rc;
  712. }
  713. /*!
  714. * \brief Add directory entry.
  715. *
  716. * \param dnode The entry is added to this directory node.
  717. * \param name The entry's name.
  718. * \param enode The entry's node.
  719. *
  720. * \return 0 if successful. Otherwise returns an error code.
  721. */
  722. static int PnutDirAddEntry(PNUT_BLKNUM dnode, const char *name, PNUT_BLKNUM enode)
  723. {
  724. int rc = 0;
  725. uint32_t pos = 0;
  726. size_t size;
  727. PNUT_DIRENTRY *entry = NULL;
  728. PNUT_NODE *np;
  729. /*
  730. * Loop through all directory entries until an unused one
  731. * is found. If required, a new data block is allocated,
  732. * so success is guaranteed unless we run out of free
  733. * blocks.
  734. */
  735. for (;;) {
  736. /*
  737. * Get the data pointer to the specified position. Automatically
  738. * create a new block if we reached the end of the data.
  739. */
  740. uint8_t *ptr = (uint8_t *)entry;
  741. if ((rc = PnutNodeGetDataPtr(dnode, pos, &ptr, &size, 1)) != 0) {
  742. break;
  743. }
  744. entry = (PNUT_DIRENTRY *)ptr;
  745. pos += PNUT_DIRENT_SIZE;
  746. /* Process entry if it doesn't cross block boundaries. */
  747. if (size >= PNUT_DIRENT_SIZE) {
  748. /* Did we find a previously released or a newly allocated entry? */
  749. if (entry->dir_inuse == 0) {
  750. /* Update the entry. */
  751. entry->dir_node = enode;
  752. entry->dir_inuse = 1;
  753. strcpy(entry->dir_name, name);
  754. /* Update the directory node. */
  755. np = BankNodePointer(dnode);
  756. np->node_mtime = time(0);
  757. if (pos > np->node_size) {
  758. np->node_size = pos;
  759. }
  760. /* Update the entry's node. */
  761. np = BankNodePointer(enode);
  762. np->node_links++;
  763. break;
  764. }
  765. }
  766. }
  767. return rc;
  768. }
  769. /*!
  770. * \brief Remove a directory entry.
  771. *
  772. * Entries referring to nodes with active open calls are not deleted.
  773. *
  774. * Entries referring to directory nodes with more than two links left
  775. * are not deleted.
  776. *
  777. * File nodes are released if the entry to remove was the last link
  778. * to them.
  779. *
  780. * \param node Remove the entry from the directory node in this block.
  781. * \param name Name of the entry to be removed.
  782. *
  783. * \return 0 if successful. Otherwise returns an error code.
  784. */
  785. static int PnutDirDelEntry(PNUT_BLKNUM node, const char *name)
  786. {
  787. int rc;
  788. PNUT_DIRENTRY *entry = NULL;
  789. PNUT_NODE *rnp;
  790. PNUT_BLKNUM rnode;
  791. /* Make sure this entry exists. */
  792. if ((rc = PnutDirFindEntry(node, name, strlen(name), &entry)) != 0) {
  793. return rc;
  794. }
  795. /* The node to remove. */
  796. rnode = entry->dir_node;
  797. rnp = BankNodePointer(rnode);
  798. /* Make sure that this node has no pending open calls. */
  799. if (rnp->node_refs) {
  800. return EACCES;
  801. }
  802. /* We only remove empty directories. */
  803. if (rnp->node_type == NODETYPE_DIR) {
  804. if (rnp->node_links > 2 || !PnutDirIsEmpty(rnode)) {
  805. return EACCES;
  806. }
  807. rnp = BankNodePointer(node);
  808. rnp->node_links--;
  809. PnutNodeRelease(rnode);
  810. }
  811. /* Remove a file. */
  812. else {
  813. PnutNodeRelease(rnode);
  814. }
  815. /* Mark this entry unused. */
  816. PnutDirFindEntry(node, name, strlen(name), &entry);
  817. entry->dir_inuse = 0;
  818. return 0;
  819. }
  820. /*!
  821. * \brief Create a new subdirectory.
  822. *
  823. * \param path Full path to the directory.
  824. *
  825. * \return 0 on success. Otherwise -1 is returned.
  826. */
  827. static int PnutDirCreate(const char *path)
  828. {
  829. PNUT_BLKNUM node;
  830. PNUT_FINDRESULT found;
  831. int ec;
  832. /* Return an error if this entry already exists. */
  833. if ((ec = PnutDirFindPath(root, path, &found)) == 0) {
  834. ec = EEXIST;
  835. }
  836. /* If this component does not exist, we can create it... */
  837. else if (ec == ENOENT) {
  838. /* ...provided that all parents had been found. */
  839. if (found.fr_name) {
  840. /* Allocate a new node block. */
  841. if ((node = PnutNodeAlloc(NODETYPE_DIR)) < 0) {
  842. ec = ENOSPC;
  843. }
  844. /* Create a reference to itself. */
  845. else if ((ec = PnutDirAddEntry(node, ".", node)) != 0) {
  846. PnutNodeRelease(node);
  847. }
  848. /* Create a reference to the parent. */
  849. else if ((ec = PnutDirAddEntry(node, "..", found.fr_pnode)) != 0) {
  850. PnutNodeRelease(node);
  851. }
  852. /* Create a reference in the parent. */
  853. else if ((ec = PnutDirAddEntry(found.fr_pnode, found.fr_name, node)) != 0) {
  854. PnutNodeRelease(node);
  855. }
  856. }
  857. }
  858. /* Something went wrong. */
  859. if (ec) {
  860. errno = ec;
  861. return -1;
  862. }
  863. return 0;
  864. }
  865. /* ------------------------ File routines ------------------------ */
  866. /*!
  867. * \brief Open a file.
  868. *
  869. * This function is called by the low level open routine of the C runtime
  870. * library, using the _NUTDEVICE::dev_open entry.
  871. *
  872. * \param dev Pointer to the NUTDEVICE structure.
  873. * \param path Pathname of the file to open.
  874. * \param mode Operation mode. Any of the following values may be or-ed:
  875. * - \ref _O_RDONLY
  876. * - \ref _O_WRONLY
  877. * - \ref _O_RDWR
  878. * - \ref _O_APPEND
  879. * - \ref _O_CREAT
  880. * - \ref _O_TRUNC
  881. * - \ref _O_EXCL
  882. * - \ref _O_TEXT
  883. * - \ref _O_BINARY
  884. * \param acc Ignored, should be zero.
  885. *
  886. * \return Pointer to a NUTFILE structure if successful or NUTFILE_EOF otherwise.
  887. */
  888. static NUTFILE *PnutFileOpen(NUTDEVICE * dev, const char *path, int mode, int acc)
  889. {
  890. PNUT_BLKNUM node = -1;
  891. PNUT_FINDRESULT found;
  892. int rc;
  893. PNUTFILE *file;
  894. NUTFILE *nfp = NUTFILE_EOF;
  895. /* Try to find an exisiting file. */
  896. if ((rc = PnutDirFindPath(root, path, &found)) == 0) {
  897. /* Return an error, if this is no regular file. */
  898. if (BankNodePointer(found.fr_node)->node_type != NODETYPE_REG) {
  899. errno = EISDIR;
  900. }
  901. /*
  902. * We return an error, if the file exists and _O_EXCL has been
  903. * set with _O_CREAT.
  904. */
  905. else if ((mode & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL)) {
  906. errno = EEXIST;
  907. } else {
  908. node = found.fr_node;
  909. if (mode & _O_TRUNC) {
  910. PnutNodeDataRelease(node);
  911. }
  912. }
  913. }
  914. else if (rc == ENOENT) {
  915. /*
  916. * If the search failed on the last path component, then
  917. * PnutDirFindPath() set fr_name. Only in this case we can
  918. * create a new file.
  919. */
  920. if (found.fr_name && (mode & _O_CREAT)) {
  921. node = PnutNodeAlloc(NODETYPE_REG);
  922. if (node < 0) {
  923. errno = ENOSPC;
  924. return NUTFILE_EOF;
  925. }
  926. rc = PnutDirAddEntry(found.fr_pnode, found.fr_name, node);
  927. if (rc) {
  928. PnutBlockRelease(node);
  929. }
  930. }
  931. }
  932. if (rc == 0 && node >= 0) {
  933. if ((file = malloc(sizeof(PNUTFILE))) != 0) {
  934. file->f_flag |= mode & (_O_RDONLY | _O_WRONLY | _O_APPEND);
  935. file->f_pos = (mode & _O_APPEND) ? BankNodePointer(node)->node_size : 0;
  936. file->f_node = node;
  937. if ((nfp = malloc(sizeof(NUTFILE))) == 0) {
  938. free(file);
  939. nfp = NUTFILE_EOF;
  940. } else {
  941. nfp->nf_dev = dev;
  942. nfp->nf_fcb = file;
  943. /* Keep track of the number of open calls. */
  944. BankNodePointer(node)->node_refs++;
  945. }
  946. }
  947. }
  948. return nfp;
  949. }
  950. /*!
  951. * \brief Close a file.
  952. */
  953. static int PnutFileClose(NUTFILE * nfp)
  954. {
  955. if (nfp != NUTFILE_EOF) {
  956. PNUTFILE *fp = nfp->nf_fcb;
  957. if (fp) {
  958. BankNodePointer(fp->f_node)->node_refs--;
  959. free(fp);
  960. }
  961. free(nfp);
  962. return 0;
  963. }
  964. return EINVAL;
  965. }
  966. /*!
  967. * \brief Delete a file or directory.
  968. *
  969. * \param path Full path to the directory.
  970. *
  971. * \return 0 on success. Otherwise -1 is returned.
  972. */
  973. static int PnutDelete(char *path)
  974. {
  975. int ec;
  976. PNUT_FINDRESULT found;
  977. if ((ec = PnutDirFindPath(root, path, &found)) == 0) {
  978. ec = PnutDirDelEntry(found.fr_pnode, found.fr_name);
  979. }
  980. if (ec) {
  981. errno = ec;
  982. return -1;
  983. }
  984. return 0;
  985. }
  986. /*!
  987. * \brief Return information about a specified file entry.
  988. *
  989. * \param path Pointer to the full pathname of the file.
  990. * \param status Pointer to a stat structure for the information returned.
  991. *
  992. * \return 0 on success. Otherwise -1 is returned.
  993. */
  994. static int PnutStatus(const char *path, struct stat *status)
  995. {
  996. int rc;
  997. PNUT_FINDRESULT found;
  998. if ((rc = PnutDirFindPath(root, path, &found)) == 0) {
  999. status->st_mode = BankNodePointer(found.fr_node)->node_type;
  1000. status->st_ino = found.fr_node;
  1001. status->st_nlink = BankNodePointer(found.fr_node)->node_links;
  1002. status->st_size = BankNodePointer(found.fr_node)->node_size;
  1003. status->st_mtime = BankNodePointer(found.fr_node)->node_mtime;
  1004. }
  1005. return rc;
  1006. }
  1007. /*!
  1008. * \brief Return information about a previously opened file.
  1009. *
  1010. * \param nfp Pointer to a \ref NUTFILE structure, obtained by a previous
  1011. * call to PnutFileOpen().
  1012. * \param status Pointer to a stat structure for the information returned.
  1013. *
  1014. * \return 0 on success. Otherwise -1 is returned.
  1015. */
  1016. static int PnutFileStatus(PNUTFILE * fp, struct stat *status)
  1017. {
  1018. status->st_mode = BankNodePointer(fp->f_node)->node_type;
  1019. status->st_ino = fp->f_node;
  1020. status->st_nlink = BankNodePointer(fp->f_node)->node_links;
  1021. status->st_size = BankNodePointer(fp->f_node)->node_size;
  1022. status->st_mtime = BankNodePointer(fp->f_node)->node_mtime;
  1023. return 0;
  1024. }
  1025. /*!
  1026. * \brief Write data to a file.
  1027. *
  1028. * \param nfp Pointer to a \ref NUTFILE structure, obtained by a previous
  1029. * call to PnutFileOpen().
  1030. * \param buffer Pointer to the data to be written. If zero, then the
  1031. * output buffer will be flushed.
  1032. * \param len Number of bytes to write.
  1033. *
  1034. * \return The number of bytes written. A return value of -1 indicates an
  1035. * error.
  1036. */
  1037. static int PnutFileWrite(NUTFILE * nfp, const void *buffer, int len)
  1038. {
  1039. PNUTFILE *fp = nfp->nf_fcb;
  1040. int ec = 0;
  1041. int rc = 0;
  1042. PNUT_BLKNUM node = fp->f_node;
  1043. uint8_t *blkptr;
  1044. size_t blksiz;
  1045. const char *buf = buffer;
  1046. while (len) {
  1047. if ((ec = PnutNodeGetDataPtr(node, fp->f_pos, &blkptr, &blksiz, 1)) != 0) {
  1048. break;
  1049. }
  1050. if (blksiz >= len) {
  1051. blksiz = len;
  1052. len = 0;
  1053. } else {
  1054. len -= blksiz;
  1055. }
  1056. memcpy(blkptr, buf, blksiz);
  1057. rc += blksiz;
  1058. buf += blksiz;
  1059. fp->f_pos += blksiz;
  1060. }
  1061. if (ec == 0 || ec == ENOSPC) {
  1062. if (BankNodePointer(node)->node_size < fp->f_pos) {
  1063. BankNodePointer(node)->node_size = fp->f_pos;
  1064. }
  1065. BankNodePointer(node)->node_mtime = time(0);
  1066. }
  1067. return rc;
  1068. }
  1069. #ifdef __HARVARD_ARCH__
  1070. static int PnutFileWrite_P(NUTFILE * nfp, PGM_P buffer, int len)
  1071. {
  1072. return -1;
  1073. }
  1074. #endif
  1075. /*!
  1076. * \brief Read data from a file.
  1077. *
  1078. * \param nfp Pointer to a ::NUTFILE structure, obtained by a previous
  1079. * call to PnutFileOpen().
  1080. * \param buffer Pointer to the data buffer to fill.
  1081. * \param len Maximum number of bytes to read.
  1082. *
  1083. * \return The number of bytes actually read. A return value of -1 indicates
  1084. * an error.
  1085. */
  1086. static int PnutFileRead(NUTFILE * nfp, void *buffer, int len)
  1087. {
  1088. PNUTFILE *fp = nfp->nf_fcb;
  1089. int ec = 0;
  1090. int rc = 0;
  1091. PNUT_BLKNUM node = fp->f_node;
  1092. uint8_t *blkptr;
  1093. size_t blksiz;
  1094. char *buf = buffer;
  1095. /* Respect end of file. */
  1096. if (len > BankNodePointer(node)->node_size - fp->f_pos) {
  1097. len = (size_t) (BankNodePointer(node)->node_size - fp->f_pos);
  1098. }
  1099. while (len) {
  1100. if ((ec = PnutNodeGetDataPtr(node, fp->f_pos, &blkptr, &blksiz, 0)) != 0) {
  1101. break;
  1102. }
  1103. if (blksiz >= len) {
  1104. blksiz = len;
  1105. len = 0;
  1106. } else {
  1107. len -= blksiz;
  1108. }
  1109. memcpy(buf, blkptr, blksiz);
  1110. rc += blksiz;
  1111. buf += blksiz;
  1112. fp->f_pos += blksiz;
  1113. }
  1114. return rc;
  1115. }
  1116. static int PnutFileSeek(PNUTFILE * fp, long *pos, int whence)
  1117. {
  1118. int rc = 0;
  1119. long npos = *pos;
  1120. switch (whence) {
  1121. case SEEK_CUR:
  1122. npos += fp->f_pos;
  1123. break;
  1124. case SEEK_END:
  1125. npos += BankNodePointer(fp->f_node)->node_size;
  1126. break;
  1127. }
  1128. if (npos < 0 || npos > (long) BankNodePointer(fp->f_node)->node_size) {
  1129. rc = EINVAL;
  1130. } else {
  1131. fp->f_pos = npos;
  1132. *pos = npos;
  1133. }
  1134. return rc;
  1135. }
  1136. /* ------------------------ Special function interface ------------------------ */
  1137. /*!
  1138. * \brief Device specific functions.
  1139. */
  1140. int PnutIOCtl(NUTDEVICE * dev, int req, void *conf)
  1141. {
  1142. int rc = -1;
  1143. switch (req) {
  1144. case FS_STATUS:
  1145. {
  1146. FSCP_STATUS *par = (FSCP_STATUS *) conf;
  1147. rc = PnutStatus(par->par_path, par->par_stp);
  1148. }
  1149. break;
  1150. case FS_DIR_CREATE:
  1151. rc = PnutDirCreate((char *) conf);
  1152. break;
  1153. case FS_DIR_REMOVE:
  1154. rc = PnutDelete((char *) conf);
  1155. break;
  1156. case FS_DIR_OPEN:
  1157. rc = PnutDirOpen(dev, (DIR *) conf);
  1158. break;
  1159. case FS_DIR_CLOSE:
  1160. rc = PnutDirClose((DIR *) conf);
  1161. break;
  1162. case FS_DIR_READ:
  1163. rc = PnutDirRead((DIR *) conf);
  1164. break;
  1165. case FS_FILE_STATUS:
  1166. rc = PnutFileStatus((PNUTFILE *) ((IOCTL_ARG2 *) conf)->arg1, /* */
  1167. (struct stat *) ((IOCTL_ARG2 *) conf)->arg2);
  1168. break;
  1169. case FS_FILE_DELETE:
  1170. rc = PnutDelete((char *) conf);
  1171. break;
  1172. case FS_FILE_SEEK:
  1173. PnutFileSeek((PNUTFILE *) ((IOCTL_ARG3 *) conf)->arg1, /* */
  1174. (long *) ((IOCTL_ARG3 *) conf)->arg2, /* */
  1175. (int) ((IOCTL_ARG3 *) conf)->arg3);
  1176. break;
  1177. }
  1178. return rc;
  1179. }
  1180. /*!
  1181. * \brief Retrieve the size of a previously opened file.
  1182. *
  1183. * This function is called by the low level size routine of the C runtime
  1184. * library, using the _NUTDEVICE::dev_size entry.
  1185. *
  1186. * \param nfp Pointer to a \ref _NUTFILE structure, obtained by a
  1187. * previous call to PhatFileOpen().
  1188. *
  1189. * \return Size of the file.
  1190. */
  1191. static long PnutFileSize(NUTFILE *nfp)
  1192. {
  1193. PNUTFILE *fp = nfp->nf_fcb;
  1194. return BankNodePointer(fp->f_node)->node_size;
  1195. }
  1196. /* ------------------------ Initialization ------------------------ */
  1197. /*!
  1198. * \brief Initialize the Peanut filesystem.
  1199. *
  1200. * Peanut is a volatile RAM filesystem. All contents is lost when
  1201. * power supply is removed. After initialization we start with
  1202. * a clean filesystem.
  1203. *
  1204. * \param Pointer to the device information structure.
  1205. *
  1206. * \return Zero on success. Otherwise an error code is returned.
  1207. */
  1208. static int PnutInit(NUTDEVICE * dev)
  1209. {
  1210. PNUT_BLKNUM i;
  1211. int rc;
  1212. /* Add all blocks to the free list. */
  1213. for (i = 0; i < PNUT_TOTAL_BLOCKS; i++) {
  1214. PnutBlockRelease(i);
  1215. }
  1216. /* Initialize the root directory. */
  1217. if ((root = PnutNodeAlloc(NODETYPE_DIR)) == -1) {
  1218. rc = ENOSPC;
  1219. } else {
  1220. if ((rc = PnutDirAddEntry(root, ".", root)) == 0) {
  1221. rc = PnutDirAddEntry(root, "..", root);
  1222. }
  1223. if (rc) {
  1224. PnutBlockRelease(root);
  1225. }
  1226. }
  1227. return rc;
  1228. }
  1229. /*!
  1230. * \brief Peanut device information structure.
  1231. */
  1232. NUTDEVICE devPnut = {
  1233. 0, /*!< Pointer to next device, dev_next. */
  1234. {'P', 'N', 'U', 'T', 0, 0, 0, 0, 0}
  1235. , /*!< Unique device name, dev_name. */
  1236. IFTYP_RAM, /*!< Type of device, dev_type. Obsolete. */
  1237. 0, /*!< Base address, dev_base. Unused. */
  1238. 0, /*!< First interrupt number, dev_irq. Unused. */
  1239. 0, /*!< Interface control block, dev_icb. Unused. */
  1240. 0, /*!< Driver control block, dev_dcb. Unused. */
  1241. PnutInit, /*!< Driver initialization routine, dev_init. */
  1242. PnutIOCtl, /*!< Driver specific control function, dev_ioctl. */
  1243. PnutFileRead, /*!< Read data from a file, dev_read. */
  1244. PnutFileWrite, /*!< Write data to a file, dev_write. */
  1245. #ifdef __HARVARD_ARCH__
  1246. PnutFileWrite_P, /*!< Write data from program space to a file, dev_write_P. */
  1247. #endif
  1248. PnutFileOpen, /*!< Open a file, dev_open. */
  1249. PnutFileClose, /*!< Close a file, dev_close. */
  1250. PnutFileSize, /*!< Return file size, dev_size. */
  1251. NULL, /*!< Select function, optional, not yet implemented */
  1252. };
  1253. /*@}*/