source: trunk/kernel/fs/vfs.h @ 662

Last change on this file since 662 was 657, checked in by alain, 5 years ago

Introduce remote_buf.c/.h & socket.c/.h files.
Update dev_nic.c/.h files.

File size: 60.9 KB
Line 
1/*
2 * vfs.h - Virtual File System definition.
3 *
4 * Author  Mohamed Lamine Karaoui (2014,2015)
5 *         Alain Greiner (2016,2017,2018,2019,2020)
6 *
7 * Copyright (c) UPMC Sorbonne Universites
8 *
9 * This file is part of ALMOS-MKH.
10 *
11 * ALMOS-MKH is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2.0 of the License.
14 *
15 * ALMOS-MKH is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25#ifndef _VFS_H_
26#define _VFS_H_
27
28#include <kernel_config.h>
29#include <hal_kernel_types.h>
30#include <hal_atomic.h>
31#include <remote_rwlock.h>
32#include <remote_busylock.h>
33#include <busylock.h>
34#include <list.h>
35#include <xlist.h>
36#include <bits.h>
37#include <xhtab.h>
38#include <errno.h>
39#include <shared_syscalls.h>
40#include <fatfs.h>
41#include <ramfs.h>
42#include <devfs.h>
43#include <dev_ioc.h>
44
45/****  Forward declarations  ***/
46
47struct vfs_inode_s;
48struct vfs_dentry_s;
49struct vfs_ctx_s;
50struct vfs_file_s;
51
52struct mapper_s;
53struct process_s;
54struct device_s;
55struct vseg_s;
56struct page_s;
57struct ksock_s;
58
59/******************************************************************************************
60 * These flags are used to define the working mode of the vfs_lookup() function. 
61 *****************************************************************************************/
62
63#define VFS_LOOKUP_DIR      0x01     /* the searched inode must be a directory           */
64#define VFS_LOOKUP_OPEN         0x02     /* the search is for an open/opendir                */
65#define VFS_LOOKUP_PARENT       0x04     /* return the parent inode (not the inode itself)   */
66#define VFS_LOOKUP_CREATE   0x10     /* file must be created if missing                  */
67#define VFS_LOOKUP_EXCL     0x20     /* file cannot previously exist                     */
68
69/******************************************************************************************
70 * This structure defines a VFS context, that contains informations common to all inodes
71 * and dentries for a given file system. As it is declared as a global variable in the
72 * kdata segment (fs_context[] array), it is replicated in all clusters.
73 * The <extend> field is a pointer on the FS specific context extension.
74 * This extension is dynamically allocated by kernel_init in all clusters.
75 * In each cluster, the inum allocator can be accessed by any thread runing
76 * in any cluster, and is therefore protected by a remote_busylock.
77 *****************************************************************************************/
78
79typedef enum
80{
81        FS_TYPE_RAMFS = 0,
82        FS_TYPE_DEVFS = 1,
83        FS_TYPE_FATFS = 2,
84 
85        FS_TYPES_NR   = 3,
86}
87vfs_fs_type_t;
88
89typedef enum
90{
91    CTX_ATTR_READ_ONLY    = 0x01,            /*! write access prohibited                 */
92    CTX_ATTR_SYNC         = 0x10,            /*! synchronise FS on each write            */
93}
94vfs_ctx_attr_t;
95
96typedef struct vfs_ctx_s
97{
98        vfs_fs_type_t      type;                 /*! File System type                        */
99        uint32_t           total_clusters;       /*! total number of clusters on device      */
100        uint32_t           cluster_size;         /*! cluster size on device (bytes)          */
101        xptr_t             vfs_root_xp;          /*! extended pointer on VFS root inode      */
102    remote_busylock_t  lock;                 /*! lock protecting inum allocator          */
103    uint32_t           bitmap[BITMAP_SIZE(CONFIG_VFS_MAX_INODES)];  /* inum allocator    */
104    void               * extend;             /*! FS specific context extension           */
105}
106vfs_ctx_t;
107
108/******************************************************************************************
109 * This structure define a VFS inode.
110 * An inode can have several children dentries (if it is a directory), an can have several
111 * parents dentries (if it has several aliases links):
112 * - The "parents" field is the root of the xlist of parents dentries, and the "links"
113 *   fiels define the number of aliases parent dentries. only a FILE inode can have
114 *   several parents (no hard links for directories).
115 * - The "children" field is an embedded xhtab containing pointers on all local children
116 *   dentries. This set of children is empty for a FILE inode.
117 * Synchronisation:
118 * - the main_lock (remote_rwlock) is used during the inode tree traversal,
119 *   or for inode modification (add/remove children in xhtab).
120 * - the size_lock (remote_rwlock) is used during read/write accesses to the size
121 *   field in the mapper.
122 * - access to the data stored in the associated mapper use the mapper remote_rwlock
123 *   protecting radix tree traversal and modifications.
124 *****************************************************************************************/
125
126/* this enum define the VFS inode types values                                           */
127/* WARNING : this enum must be kept consistent with macros in <shared_stat.h> file       */
128/*           and with types in <shared_dirent.h> file.                                   */
129
130typedef enum   
131{
132    INODE_TYPE_FILE  =     0,           /*! regular file                                 */
133    INODE_TYPE_DIR   =     1,           /*! directory                                    */
134    INODE_TYPE_FIFO  =     2,           /*! POSIX named pipe                             */
135    INODE_TYPE_PIPE  =     3,           /*! POSIX anonymous pipe                         */
136    INODE_TYPE_SOCK  =     4,           /*! POSIX socket                                 */
137    INODE_TYPE_DEV   =     5,           /*! character device                             */
138    INODE_TYPE_BLK   =     6,           /*! block device                                 */
139    INODE_TYPE_SYML  =     7,           /*! symbolic link                                */
140}
141vfs_inode_type_t;
142
143/* this enum define the VFS inode attributes values */
144
145typedef enum 
146{
147    INODE_ATTR_DIRTY   =     0x01,       /*! modified versus the value on device         */ 
148    INODE_ATTR_INLOAD  =     0x04,       /*! loading from device in progress             */
149    INODE_ATTR_NEW     =     0x08,       /*! not saved on device yet                     */
150}
151vfs_inode_attr_t;
152
153typedef struct vfs_inode_s
154{
155    struct vfs_ctx_s * ctx;              /*! local pointer on FS context                 */
156    uint32_t           inum;             /*! inode identifier (unique in file system)    */
157    uint32_t           attr;             /*! inode attributes (see above)                */
158    vfs_inode_type_t   type;             /*! inode type (see above)                      */
159    uint32_t           size;             /*! number of bytes                             */
160    uint32_t           uid;              /*! user owner identifier                       */
161    uint32_t           gid;              /*! group owner identifier                      */
162    uint32_t           rights;           /*! access rights                               */
163    xlist_entry_t      parents;          /*! root of list of parents dentries            */
164    uint32_t           links;            /*! number of parent dentries (hard links)      */
165    xhtab_t            children;         /*! embedded xhtab of children dentries         */
166    remote_rwlock_t    size_lock;        /*! protect read/write to size                  */
167    remote_rwlock_t    main_lock;        /*! protect inode tree traversal and modifs     */
168    struct mapper_s  * mapper;           /*! associated file cache                       */
169    void             * extend;           /*! fs_type_specific inode extension            */
170}
171vfs_inode_t;
172
173/* This define the masks for the inode <rights> field  */
174
175#define VFS_ISUID          0x0004000
176#define VFS_ISGID          0x0002000
177#define VFS_ISVTX          0x0001000
178
179#define VFS_IRWXU      0x0000700
180#define VFS_IRUSR      0x0000400
181#define VFS_IWUSR      0x0000200
182#define VFS_IXUSR      0x0000100
183
184#define VFS_IRWXG      0x0000070
185#define VFS_IRGRP      0x0000040
186#define VFS_IWGRP      0x0000020
187#define VFS_IXGRP      0x0000010
188
189#define VFS_IRWXO      0x0000007
190#define VFS_IROTH      0x0000004
191#define VFS_IWOTH      0x0000002
192#define VFS_IXOTH      0x0000001
193
194/******************************************************************************************
195 * This structure defines a directory entry.
196 * A dentry contains the name of a remote file/dir, an extended pointer on the
197 * inode representing this file/dir, a local pointer on the inode representing
198 * the parent directory.
199 * A dentry can be member of the set of children of a given directory inode (xhtab).
200 * A dentry can be member of the set of parents  of a given inode (xlist).
201 *****************************************************************************************/
202
203typedef struct vfs_dentry_s
204{
205    struct vfs_ctx_s   * ctx;            /*! local pointer on FS context                 */
206        char                 name[CONFIG_VFS_MAX_NAME_LENGTH];
207        uint32_t             length;         /*! name length (bytes)                         */
208    struct vfs_inode_s * parent;         /*! local pointer on parent inode               */
209    xptr_t               child_xp;       /*! extended pointer on child inode             */
210    xlist_entry_t        children;       /*! member of set of children dentries          */
211    xlist_entry_t        parents;        /*! member of set of parent dentries            */
212        void               * extend;         /*! FS specific extension                       */
213}
214vfs_dentry_t;
215
216/******************************************************************************************
217 * This file structure describes an open file/directory for a given process.
218 * It is not replicated, and is dynamically allocated in the cluster that contains
219 * the inode, when a thread makes an open() or opendir() system call.
220 * It cannot exist a file structure without an inode structure in same cluster.
221 * As the fd_array (containing extended pointers on the open file descriptors)
222 * is replicated in all process descriptors, we need a references counter.
223 *****************************************************************************************/
224
225typedef enum
226{
227    FD_ATTR_READ_ENABLE    = 0x01,     /*! read access possible                          */
228    FD_ATTR_WRITE_ENABLE   = 0x02,     /*! write access possible                         */
229    FD_ATTR_APPEND         = 0x04,     /*! append on each write                          */
230    FD_ATTR_CLOSE_EXEC     = 0x08,     /*! close file on exec                            */
231    FD_ATTR_SYNC           = 0x10,     /*! synchronise FS on each write                  */
232    FD_ATTR_IS_DIR         = 0x20,     /*! this is a directory                           */
233}
234vfs_file_attr_t;
235
236typedef struct vfs_file_s
237{
238        struct vfs_ctx_s      * ctx;        /*! local pointer on FS context.                 */
239        vfs_file_attr_t         attr;       /*! file attributes bit vector (see above)       */
240        vfs_inode_type_t        type;       /*! same type as inode                           */
241        uint32_t                offset;     /*! seek position in file                        */
242        uint32_t                refcount;   /*! all pointers on this file descriptor         */
243        remote_rwlock_t         lock;       /*! protect offset modifications                 */
244        struct mapper_s       * mapper;     /*! associated file cache                        */
245        struct vfs_inode_s    * inode;      /*! local pointer on associated inode            */
246    struct socket_s       * socket;     /*! local pointer on associated socket           */
247        void                  * extend;     /*! FS specific extension                        */
248}
249vfs_file_t;
250
251
252/******************************************************************************************
253 *        These functions access / modify  a VFS context.
254 *****************************************************************************************/
255
256/******************************************************************************************
257 * This function initialises a (statically allocated) VFS context in cluster identified
258 * by the <cxy> argument.
259 * It is called by the kernel_init() function.
260 ******************************************************************************************
261 * @ cxy            : target cluster identifier.
262 * @ fs_type        : file system type.
263 * @ total_clusters : total number of clusters on device.
264 * @ cluster_size   : cluster size on device (bytes).
265 * @ vfs_root_xp    : extended pointer on VFS root inode.
266 * @ extend         : fs_type_specific extension.
267 *****************************************************************************************/
268void vfs_ctx_init( cxy_t           cxy,
269                   vfs_fs_type_t   type,
270                       uint32_t        total_clusters,
271                       uint32_t        cluster_size,
272                       xptr_t          vfs_root_xp,
273                   void          * extend );
274
275/******************************************************************************************
276 * This function allocates an inode identifier from the local cluster inum allocator.
277 * The inum respects a fixed format:
278 * - the 16 MSB bits contain the cluster identifier : cxy
279 * - the 16 LSB bits contains the local inode identifier  : lid
280 ******************************************************************************************
281 * @ ctx_xp   : [in]  extended pointer on file system context.
282 * @ inum     : [out] buffer for allocated inode identifier.
283 * @ return 0 if success / return non-zero if error.
284 *****************************************************************************************/
285error_t vfs_ctx_inum_alloc( xptr_t     ctx_xp,
286                            uint32_t * inum );
287
288/******************************************************************************************
289 * This function release an inode identifier.                                 
290 ******************************************************************************************
291 * @ ctx_xp   : [in] extended pointer on file system context.
292 * @ inum     : [in] released inode identifier.
293 *****************************************************************************************/
294void vfs_ctx_inum_release( xptr_t      ctx_xp,
295                           uint32_t    inum );
296
297
298
299/******************************************************************************************
300 *        These low-level functions access / modify a VFS inode descriptor
301 *****************************************************************************************/
302
303/******************************************************************************************
304 * This function returns a printable string for the inode type.
305 *****************************************************************************************/
306const char * vfs_inode_type_str( vfs_inode_type_t type );
307
308/******************************************************************************************
309 * This function allocates memory in cluster identified by the <cxy> argument
310 * for an inode descriptor and for the associated mapper, and partially initialise
311 * this inode from arguments values.
312 * It does NOT link it to the Inode Tree, as this is done by add_child_in_parent().
313 * It can be called by any thread running in any cluster.
314 ******************************************************************************************
315 * @ cxy        : [in]  target cluster identifier
316 * @ fs_type    : [in]  file system type.
317 * @ attr       : [in]  inode attributes.
318 * @ rights     : [in]  inode access rights.
319 * @ uid        : [in]  user owner ID.
320 * @ gid        : [in]  group owner ID.
321 * @ inode_xp   : [out] buffer for extended pointer on created inode.
322 * @ return 0 if success / return -1 if error.
323 *****************************************************************************************/
324error_t vfs_inode_create( cxy_t             cxy,
325                          vfs_fs_type_t     fs_type,
326                          uint32_t          attr,
327                          uint32_t          rights,
328                          uid_t             uid,
329                          gid_t             gid,
330                          xptr_t          * inode_xp );
331
332/******************************************************************************************
333 * This function releases memory allocated to an inode descriptor, including
334 * all memory allocated to the mapper (both mapper descriptor and radix tree).
335 * The mapper should not contain any dirty page (should be synchronized before deletion).
336 * It can be called by any thread running in any cluster.
337 ******************************************************************************************
338 * @ inode_xp  : extended pointer on inode descriptor.
339 *****************************************************************************************/
340void vfs_inode_destroy( xptr_t  inode_xp ); 
341
342/******************************************************************************************
343 * This function returns the <size> of a file/dir from a remote inode,
344 * taking the remote_rwlock protecting <size> in READ_MODE.
345 * It can be called by any thread running in any cluster.
346 *****************************************************************************************
347 * @ inode_xp  : extended pointer on the remote inode.
348 * @ return the current size.
349 *****************************************************************************************/
350uint32_t vfs_inode_get_size( xptr_t inode_xp );
351
352/******************************************************************************************
353 * This function updates the "size" field of a remote inode identified by <inode_xp>.
354 * It takes the rwlock protecting the file size in WRITE_MODE, and set the "size" field
355 * when the current size is smaller than the requested <size> argument.
356 * It can be called by any thread running in any cluster.
357 *****************************************************************************************
358 * @ inode_xp  : extended pointer on the remote inode.
359 * @ size      : requested size value.
360 *****************************************************************************************/
361void vfs_inode_update_size( xptr_t   inode_xp,
362                            uint32_t size );
363
364/******************************************************************************************
365 * This function takes the main lock of a remote inode identified by the <inode_xp>.
366 * This lock protect all inode fields, including the children dentries.
367 * It can be called by any thread running in any cluster.
368 *****************************************************************************************
369 * @ inode_xp  : extended pointer on the remote inode.
370 *****************************************************************************************/
371void vfs_inode_lock( xptr_t inode_xp );
372
373/******************************************************************************************
374 * This function releases the main lock of a remote inode identified by <inode_xp>.
375 * This lock protect all inode fiels, including the children dentries.
376 * It can be called by any thread running in any cluster.
377 *****************************************************************************************
378 * @ inode_xp  : extended pointer on the remote inode.
379 *****************************************************************************************/
380void vfs_inode_unlock( xptr_t inode_xp );
381
382/******************************************************************************************
383 * This debug function copies the name of a remote inode identified by the <inode_xp>
384 * argument to a local buffer identified by the <name> argument.
385 * The local buffer size must be at least CONFIG_VFS_MAX_NAME_LENGTH.
386 * It can be called by any thread running in any cluster.
387 ******************************************************************************************
388 * @ inode_xp  : extended pointer on the remote inode.
389 * @ name      : local buffer pointer.
390 *****************************************************************************************/
391void vfs_inode_get_name( xptr_t inode_xp,
392                         char * name );
393
394/******************************************************************************************
395 * This function accesses successively all pages of a file identified by the <inode_xp>,
396 * argument, to force misses, and load all pages into mapper.
397 * The target inode can be a directory or a file, but this function is mainly used
398 * to prefetch a complete directory to the mapper.
399 * This function does NOT take any lock.
400 * It can be called by any thread running in any cluster.
401 ******************************************************************************************
402 * @ inode_xp  : extended pointer on inode.
403 * @ return 0 if success / return -1 if device access failure.
404 *****************************************************************************************/
405error_t vfs_inode_load_all_pages( xptr_t inode_xp );
406
407/******************************************************************************************
408 * This debug function display the curren state of an inode descriptor.
409 * It can be called by any thread running in any cluster.
410 *****************************************************************************************/
411void vfs_inode_display( xptr_t inode_xp );
412
413/******************************************************************************************
414 *        These low-level functions access / modify a VFS dentry descriptor
415 *****************************************************************************************/
416
417/******************************************************************************************
418 * This function allocates memory in cluster identified by the <cxy> argument
419 * for a dentry descriptor, initialises it from  arguments values, and returns
420 * in <dentry_xp> the extended pointer on dentry.
421 * It can be called by any thread running in any cluster.
422 ******************************************************************************************
423 * @ cxy        : [in]  target cluster identifier
424 * @ fs_type    : [in]  file system type.
425 * @ name       : [in]  directory entry file/dir name.
426 * @ dentry_xp  : [out] buffer for extended pointer on created dentry.
427 * @ return 0 if success / return ENOMEM or EINVAL if error.
428 *****************************************************************************************/
429error_t vfs_dentry_create( cxy_t           cxy,
430                           vfs_fs_type_t   fs_type,
431                           char          * name,
432                           xptr_t        * dentry_xp );
433 
434/******************************************************************************************
435 * This function removes the dentry from the parent inode xhtab, and releases the memory
436 * allocated to the dentry descriptor.
437 * It can be called by any thread running in any cluster.
438 ******************************************************************************************
439 * @ dentry_xp  : [in] extended pointer on dentry descriptor.
440 *****************************************************************************************/
441void vfs_dentry_destroy( xptr_t  dentry_xp ); 
442
443
444/******************************************************************************************
445 *        These low-level functions access / modify a VFS file descriptor
446 *****************************************************************************************/
447
448/******************************************************************************************
449 * This function allocates memory and initializes a new file descriptor in the
450 * cluster defined by the <inode_xp> argument.
451 * It can be called by any thread running in any cluster.
452 ******************************************************************************************
453 * @ inode_xp  : [in]  extended pointer on associated inode.
454 * @ attr      : [in]  file descriptor attributes.
455 * @ file_xp   : [out] buffer for extended pointer on created file descriptor.
456 * @ return 0 if success / return ENOMEM if error.
457 *****************************************************************************************/
458error_t vfs_file_create( xptr_t        inode_xp,
459                         uint32_t      attr,
460                         xptr_t      * file_xp ); 
461
462/******************************************************************************************
463 * This function releases memory allocated to file descriptor identified
464 * by the <file_xp> argument.
465 * It can be called by any thread running in any cluster.
466 ******************************************************************************************
467 * @ file_xp  : [in] extended pointer on file descriptor.
468 *****************************************************************************************/
469void vfs_file_destroy( xptr_t  file_xp ); 
470
471/******************************************************************************************
472 * These functions increment (resp. decrement) the count field in a remote file
473 * descriptor, using a remote_atomic access.
474 *****************************************************************************************
475 * @ file_xp  : extended pointer on file descriptor.
476 *****************************************************************************************/
477void vfs_file_count_up  ( xptr_t   file_xp );
478void vfs_file_count_down( xptr_t   file_xp );
479
480/******************************************************************************************
481 * This debug function copies the name of a the file identified by <file_xp>
482 * argument to a local buffer identified by the <name> argument.
483 * The local buffer size must be at least CONFIG_VFS_MAX_NAME_LENGTH.
484 *****************************************************************************************
485 * @ ionde_xp  : [in] extended pointer on the remote inode.
486 * @ name      : [out] local string.
487 ***************************************************************************************/
488void vfs_file_get_name( xptr_t inode_xp,
489                        char * name );
490
491
492
493
494/******************************************************************************************
495 *        These functions access / modify the distributed VFS Inode Tree
496 *****************************************************************************************/
497
498/******************************************************************************************
499 * This function returns in a kernel <buffer> allocated by the caller function,
500 * the pathname of a file/dir identified by the <inode_xp> argument.
501 * It traverse the Inode Tree from the target node to the root.
502 * It can be called by any thread running in any cluster.
503 * As this buffer if filled in "reverse order" (i.e. from the target inode to the root),
504 * the pathname is stored in the higher part of the buffer.
505 * A pointer on the first character of the pathname is returned in <first> buffer.
506 *
507 * WARNING : This function takes & releases the remote_rwlock protecting the Inode Tree.
508 ******************************************************************************************
509 * @ inode_xp    : [in]  extended pointer on target inode descriptor.
510 * @ buffer      : [in]  kernel buffer for pathname (allocated by caller).
511 * @ first       : [out] pointer on first character in buffer.
512 * @ max_size    : [in]  max number of characters in buffer.
513 * @ return 0 if success / return EINVAL if buffer too small.
514 *****************************************************************************************/
515error_t vfs_get_path( xptr_t    inode_xp,
516                      char    * buffer,
517                      char   ** first,
518                      uint32_t  max_size );
519
520/******************************************************************************************
521 * This function traverses the the Inode Tree, from inode identified by the <root_xp>
522 * argument, and returns in <inode_xp> the inode identified by the < pathname> argument.
523 * It can be called by a thread running in any cluster.
524 * It supports the following flags that define the lookup modes :
525 * - VFS_LOOKUP_DIR    : the searched inode must be a directory
526 * - VFS_LOOKUP_OPEN   : the search is for an open/opendir
527 * - VFS_LOOKUP_PARENT : return the parent inode (not the inode itself)
528 * - VFS_LOOKUP_CREATE : file/directory must be created if missing on IOC
529 * - VFS_LOOKUP_EXCL   : file cannot previously exist
530 * As the inode Tree is a cache, the search policy is the following :
531 * - If a given directory name in the path is not found in the inode tree, it try to load
532 *   the missing dentry/inode couple, from informations found in the parent directory.
533 * - If this directory entry does not exist on IOC, it returns an error.
534 * - If the the file identified by the pathname does not exist on IOC but the
535 *   flag CREATE is set, the inode is created. It returns an error otherwise.
536 * - If the the file identified by the pathname exist on device, but both flags EXCL
537 *   and CREATE are set, an error is returned.
538 * - If the PARENT flag is set, it returns in <inode_xp> an extended pointer on the parent
539 *   inode, and copies in <last_name> buffer a string containing the last name in path.
540 *
541 * WARNING : The remote_rwlock protecting the Inode Tree must be taken by the caller.
542 *
543 * TODO the access rights are not checked yet.
544 ******************************************************************************************
545 * @ root_xp     : [in]  extended pointer on root inode (can be root of a subtree).
546 * @ pathname    : [in]  path (can be relative or absolute).
547 * @ lookup_mode : [in]  flags defining the searching mode.
548 * @ inode_xp    : [out] buffer for extended pointer on searched inode.
549 * @ last_name   : [out] pointer on buffer for last name in path.
550 * @ return 0 if success / ENOENT if inode not found , EACCES if permisson denied,
551 *****************************************************************************************/
552error_t vfs_lookup( xptr_t             root_xp,
553                    char             * pathname,
554                    uint32_t           lookup_mode,
555                                        xptr_t           * inode_xp,
556                    char             * last_name );
557
558/******************************************************************************************
559 * This function creates a new couple dentry/inode, and insert it in the Inode-Tree.
560 * Only the distributed Inode Tree is modified: it does NOT modify the parent mapper,
561 * and does NOT update the FS on IOC device.
562 * It set the inode type to the default INODE_TYPE_FILE value
563 * It can be executed by any thread running in any cluster (can be different from both
564 * the child cluster and the parent cluster).
565 * The new child inode and the parent inode can have different FS types.
566 * [Implementation note]
567 * As there are cross-references between inode and dentry, this function implements
568 * a five steps scenario :
569 * 1) The dentry descriptor is created in the cluster containing the existing <parent_xp>
570 *    inode, and partially initialized, using the RPC_VFS_CREATE DENTRY if required.
571 * 2) The inode and its associated mapper are created in cluster identified by <child_cxy>,
572 *    and partially initialised, using the RPC_VFS_CREATE_INODE if required.
573 * 3) The pointers on dentry in parent inode are updated, using remote access.
574 * 4) The pointers on dentry in child inode are updated, using remotes access.
575 * 5) The pointers on parent and child inode in dentry are updated, using remotes access.
576 *****************************************************************************************
577 * @ child_inode_cxy  : [in]  target cluster for child inode.
578 * @ fs_type          : [in]  child inode FS type.
579 * @ parent_inode_xp  : [in]  extended pointer on parent inode.
580 * @ name             : [in]  new directory entry name.
581 * @ dentry_xp        : [out] buffer for extended pointer on dentry
582 * @ child_inode_xp   : [out] buffer for extended pointer on child inode.
583 * @ return 0 if success / -1 if dentry or inode cannot be created.
584 *****************************************************************************************/
585error_t vfs_add_child_in_parent( cxy_t              child_inode_cxy,
586                                 vfs_fs_type_t      fs_type,
587                                 xptr_t             parent_inode_xp,
588                                 char             * name,
589                                 xptr_t           * dentry_xp,   
590                                 xptr_t           * child_inode_xp );
591
592/******************************************************************************************
593 * This function removes a remote dentry from the Inode-Tree.
594 * - It removes the dentry from the parent inode xhtab ("children" field), and from the
595 *   child inode xlist ("parents" field).
596 * - It releases the memory allocated to the dentry descriptor.
597 * - If the number of parents of the child inode is one, it also releases the memory
598 *   allocated to the child inode.
599 * Only the Inode Tree is modified: it does NOT modify the parent mapper,
600 * and does NOT update the FS on IOC device.
601 * It can be executed by any thread running in any cluster (can be different from both
602 * the inode cluster and the dentry cluster).
603 ******************************************************************************************
604 * @ dentry_xp   : extended pointer on removed dentry.
605 *****************************************************************************************/
606void vfs_remove_child_from_parent( xptr_t dentry_xp );
607
608/******************************************************************************************
609 * This function creates in the directory identified by the <child_inode_xp> argument,
610 * the two special dentries <.> and <..>. The parent directory inode is defined
611 * by the <parent_inode_xp> argument. The two dentries are introduced in the Inode Tree.
612 * They are also introduced in the child directory mapper, and the IOC device is updated.
613 * This function is called by all functions creating a brand new directory : vfs_mkdir(),
614 * devfs_global_init(), and devfs_local_init().
615 ******************************************************************************************
616 * @ child_xp    : extended pointer on new directory inode.
617 * @ parent_xp   : extended pointer on parent directory inode.
618 * @ return 0 if success / -1 if failure.
619 *****************************************************************************************/
620error_t vfs_add_special_dentries( xptr_t  child_inode_xp,
621                                  xptr_t  parent_inode_xp );
622
623/******************************************************************************************
624 * This recursive function diplays a complete inode/dentry sub-tree.
625 * Any inode can be selected as the sub-tree root.
626 * WARNING : this function is not protected against a concurrent inode/dentry removal...
627 ******************************************************************************************
628 * @ inode_xp   : extended pointer on sub-tree root inode.
629 *****************************************************************************************/
630void vfs_display( xptr_t   inode_xp );
631
632/******************************************************************************************
633 * This function mount a given file system type for a given process
634 * TODO non implemented yet [AG].     
635 *****************************************************************************************/
636error_t vfs_mount_fs_root( struct device_s  * device,
637                                       uint32_t           fs_type,
638                                       struct process_s * process );
639
640
641
642
643/******************************************************************************************
644 *        These functions define the VFS "syscalls" API (user commands)
645 *****************************************************************************************/
646
647/******************************************************************************************
648 * This function moves <size> bytes between a remote file mapper, identified by the
649 * <file_xp> argument, and a - possibly distributed - user space <buffer>, taken into
650 * account the offset in <file_xp>. The transfer direction is defined by <to_buffer>.
651 * It is called by the sys_read() and sys_write() functions.
652 * - for a read, it checks the actual file size (registered in the inode descriptor),
653 *   against the (offset + count), and moves only the significant bytes.
654 * - for a write, it updates the the file size in inode descriptor if required.
655 * In case of write to the mapper, the "inode.size" field is updated as required.
656 ******************************************************************************************
657 * @ to_buffer : mapper -> buffer if true / buffer -> mapper if false.
658 * @ file_xp   : extended pointer on the remote file descriptor.
659 * @ buffer    : user space pointer on buffer (can be physically distributed).
660 * @ count     : requested number of bytes from offset.
661 * @ returns number of bytes actually moved if success / -1 if error.
662 *****************************************************************************************/
663uint32_t vfs_user_move( bool_t   to_buffer,
664                        xptr_t   file_xp, 
665                        void   * buffer,
666                        uint32_t count );
667
668/******************************************************************************************
669 * This function moves <size> bytes between a remote file mapper, identified by the
670 * <file_xp> argument, and a - possibly remote - kernel <buffer_xp>, taken into
671 * account the offset in <file_xp>. The transfer direction is defined by <to_buffer>.
672 * It is called by the elf_load_process() function.
673 ******************************************************************************************
674 * @ to_buffer : mapper -> buffer if true / buffer -> mapper if false.
675 * @ file_xp   : extended pointer on the remote file descriptor.
676 * @ buffer_xp : user space pointer on buffer (can be physically distributed).
677 * @ size      : requested number of bytes from offset.
678 * @ returns 0 if success / -1 if error.
679 *****************************************************************************************/
680error_t vfs_kernel_move( bool_t   to_buffer,
681                         xptr_t   file_xp, 
682                         xptr_t   buffer_xp,
683                         uint32_t size );
684
685/******************************************************************************************
686 * This function allocates a vfs_file_t structure in the cluster containing the inode
687 * identified by the <root_xp> & <path> arguments.
688 * It initializes it, register it in the reference process fd_array identified by the
689 * <process_xp> argument, and returns both the extended pointer on the file descriptor,
690 * and the allocated index in the <file_xp> and <file_id> buffers.
691 * The pathname can be relative to current directory or absolute.
692 * If the inode does not exist in the inode cache, it try to find the file on the IOC
693 * device, and creates an inode on a pseudo randomly selected cluster if found.
694 * It the requested file does not exist on device, it creates a new inode if the
695 * O_CREAT flag is set, and return an error otherwise.
696 *
697 * WARNING : this function takes & releases the remote_rwlock protecting the Inode Tree.
698 ******************************************************************************************
699 * @ root_xp     : extended pointer on path root inode.
700 * @ path        : file pathname (absolute or relative to current directory).
701 * @ process_xp  : extended pointer on client reference process.
702 * @ flags       : defined in vfs_file_t structure.
703 * @ mode        : access rights (as defined by chmod).
704 * @ file_xp     : [out] buffer for extended pointer on created remote file descriptor.
705 * @ file_id     : [out] buffer for created file descriptor index in reference fd_array.
706 * @ return 0 if success / return non-zero if error.
707 *****************************************************************************************/
708error_t vfs_open( xptr_t             root_xp,
709                          char             * path,
710                  xptr_t             process_xp,
711                          uint32_t           flags,
712                  uint32_t           mode,
713                          xptr_t           * file_xp,
714                          uint32_t         * file_id );
715
716/******************************************************************************************
717 * This function set a new value in the offset of the open file descriptor <file_xp>.
718 * This value depends on the <whence> argument:
719 * - if VFS_SEEK_SET, new value is <offset>
720 * - if VFS_SEEK_CUR, new value is current_offset + <offset>
721 * - if VFS_SEEK_END, new value is file_size + <offset>
722 ******************************************************************************************
723 * @ file_xp   : extended pointer on the remote open file descriptor.
724 * @ offset    : local pointer on source kernel buffer.
725 * @ whence    : VFS_SEEK_SET / VFS_SEEK_CUR / VFS_SEEK_END.
726 * @ new_offset : [out] buffer for new offset value.
727 * @ returns 0 if success / -1 if error.
728 *****************************************************************************************/
729error_t vfs_lseek( xptr_t     file_xp,
730                   uint32_t   offset,
731                   uint32_t   whence, 
732                   uint32_t * new_offset );
733
734/******************************************************************************************
735 * This function close the - non-replicated - file descriptor identified by the <file_xp>
736 * and <file_id> arguments. The <file_id> is required to reset the fd_array[] slot.
737 * It can be called by a thread running in any cluster, and executes the following actions:
738 * 1) It access the block device to updates all dirty pages from the mapper associated
739 *    to the file, and removes these pages from the dirty list, using an RPC if required.
740 * 2) It updates the file size in all parent directory mapper(s), and update the modified
741 *    pages on the block device, using RPCs if required, only if the size is modified.
742 * 3) All entries in the fd_array copies are directly reset by the calling thread,
743 *    using remote accesses.
744 * 4) The memory allocated to file descriptor in cluster containing the inode is released,
745 *    using an RPC if cluster containing the file descriptor is remote.
746 ******************************************************************************************
747 * @ file_xp     : extended pointer on the file descriptor.
748 * @ file_id     : file descriptor index in fd_array[].
749 * @ returns 0 if success / -1 if error.
750 *****************************************************************************************/
751error_t vfs_close( xptr_t    file_xp,
752                   uint32_t  file_id );
753
754/******************************************************************************************
755 * This function is called by the kernel to create in the file system a new directory
756 * identified by the <root_xp> & <path> arguments, with the access permission defined
757 * by the <rights> argument. All nodes in the path - but the last -  must exist.
758 *
759 * WARNING : this function takes & releases the remote_rwlock protecting the Inode Tree.
760 ******************************************************************************************
761 * @ root_xp : extended pointer on path root inode (any inode in Inode Tree).
762 * @ path    : pathname (absolute or relative to current directory).
763 * @ rights  : access rights.
764 * @ returns 0 if success / -1 if error.
765 *****************************************************************************************/
766error_t vfs_mkdir( xptr_t   root_xp,
767                   char   * path,
768                   uint32_t rights );
769
770/******************************************************************************************
771 * This function is called by the kernel to create in the file system a new directory
772 * entry identified by the <new_root_xp> & <new_path> arguments, to be linked to an
773 * existing inode, identified by the  <old_root_xp> & <old_path> arguments.
774 * If the link is successful, the link count of the target inode is incremented.
775 * The <new_path> and <old_path> share equal access rights to the underlying inode.
776 * Both the IOC device and the Inode Tree are modified.
777 $
778 * TODO This function should handle any type of node, but the current implementation
779 * handles only the FILE and DIR types.
780 *
781 * WARNING : this function takes & releases the remote_rwlock protecting the Inode Tree.
782 ******************************************************************************************
783 * @ old_root_xp : extended pointer on old path root inode (any inode in Inode Tree).
784 * @ old_path    : old pathname (absolute or relative to current directory).
785 * @ nld_root_xp : extended pointer on new path root inode (any inode in Inode Tree).
786 * @ new_path    : new pathname (absolute or relative to current directory).
787 * @ returns 0 if success / -1 if error.
788 *****************************************************************************************/
789error_t vfs_link( xptr_t   old_root_xp,
790                  char   * old_path,
791                  xptr_t   new_root_xp,
792                  char   * new_path );
793
794/******************************************************************************************
795 * This function is called by the kernel to remove from the file system a directory entry
796 * identified by the  <root_xp> & <path> arguments.
797 * The link count of the target node is decremented.
798 * If the removed link is the last, the target inode is deleted.
799 * Both the IOC device and the Inode Tree are modified.
800 *
801 * TODO This function should handle any type of node, but the current implementation
802 * handles only only the FILE and DIR types.
803 *
804 * WARNING : this function takes & releases the remote_rwlock protecting the Inode Tree.
805 ******************************************************************************************
806 * @ root_xp  : extended pointer on root inode (can be any inode in Inode Tree).
807 * @ path     : pathname (absolute or relative to current directory).
808 * @ returns 0 if success / -1 if error.
809 *****************************************************************************************/
810error_t vfs_unlink( xptr_t   root_xp,
811                    char   * path );
812
813/******************************************************************************************
814 * This function returns, in the structure pointed by the <st> pointer, various
815 * informations on the inode identified by the <root_inode_xp> and <patname> arguments.
816 *
817 * TODO : only partially implemented yet (only size and inum fields).
818 *
819 * WARNING : this function takes & releases the remote_rwlock protecting the Inode Tree.
820 ******************************************************************************************
821 * @ root_xp    : extended pointer on path root inode (any inode in Inode Tree)
822 * @ pathname   : pathname to target inode.
823 * @ st         : local pointer on the stat structure in kernel space.
824 * @ returns 0 if success / -1 if error.
825 *****************************************************************************************/
826error_t vfs_stat( xptr_t        root_xp,
827                  char        * pathname,
828                  struct stat * st );
829
830/******************************************************************************************
831 * This function  creates a new directory as defined by the <root_xp> & <path> arguments.
832 * TODO not implemented yet...
833 ******************************************************************************************
834 * @ root_xp  : extended pointer on the path root directory.
835 * @ path     : pathname (absolute or relative to CWD).                     
836 * @ mode     : access rights (as defined by chmod)
837 * @ returns 0 if success / -1 if error.
838 *****************************************************************************************/
839error_t vfs_mkdir( xptr_t     root_xp,
840                   char     * path,
841                   uint32_t   mode );
842
843/******************************************************************************************
844 * This function makes the directory identified by the <root_xp and <path> arguments
845 * to become the working directory for the calling process.
846 ******************************************************************************************
847 * @ root_xp  : extended pointer on the path root directory.
848 * @ path     : pathname (absolute or relative to CWD).
849 * return 0 if success / -1 if error.
850 *****************************************************************************************/
851error_t vfs_chdir( xptr_t   root_xp,
852                   char   * path );
853
854/******************************************************************************************
855 * This function change the access rigths for the file/directory identified by the
856 * <root_xp> and <path> arguments as defined by the <mode> argument value.
857 ******************************************************************************************
858 * @ root_xp  : extended pointer on the path root directory.
859 * @ path     : pathname (absolute or relative to CWD).
860 * @ mode     : access rights
861 * return 0 if success / -1 if error.
862 *****************************************************************************************/
863error_t vfs_chmod( xptr_t        root_xp,
864                   char        * path,
865                   uint32_t      mode );
866
867/******************************************************************************************
868 * This function creates a named FIFO file.
869 * TODO not implemented yet                                                         
870 ******************************************************************************************
871 * @ root_xp  : extended pointer on the path root directory.
872 * @ path     : pathname (absolute or relative to CWD).
873 * @ mode     : access rights new value.
874 *****************************************************************************************/
875error_t vfs_mkfifo( xptr_t       root_xp,
876                    char       * path,
877                    uint32_t     mode );
878
879
880
881
882
883/******************************************************************************************
884 *      These functions define the VFS "FS" API to access a specific File System
885 *****************************************************************************************/
886
887/******************************************************************************************
888 * This function introduces in a directory mapper identified by the <parent_inode_xp>
889 * argument, a new entry identified by the <dentry_ptr> argument.
890 * Depending on the file system type, it calls the proper, FS specific function.
891 * All informations related to the new directory must be contained in the dentry
892 * descriptor, or in the associated child inode descriptor.
893 * The dentry descriptor "extend" field is updated as required by the specific FS.
894 * Finally, it synchronously updates the parent directory on IOC device.
895 * This function can be called by any thread running in any cluster.
896 ******************************************************************************************
897 * @ parent  : local pointer on parent (directory) inode.
898 * @ dentry  : local pointer on dentry containing name.
899 * @ return 0 if success / return -1 if device access failure.
900 *****************************************************************************************/
901error_t vfs_fs_add_dentry( xptr_t         parent_inode_xp,
902                           vfs_dentry_t * dentry_ptr );
903
904/******************************************************************************************
905 * This function removes from a directory mapper identified by the <parent_inode_xp>
906 * argument, an entry identified by the <dentry_ptr> argument.
907 * Depending on the file system type, it calls the proper, FS specific function.
908 * Finally, it synchronously updates the parent directory on IOC device.
909 * This function can be called by any thread running in any cluster.
910 ******************************************************************************************
911 * @ parent_inode_xp  : extended pointer on parent (directory) inode.
912 * @ dentry_ptr       : local pointer on dentry containing name.
913 * @ return 0 if success / return -1 if device access failure.
914 *****************************************************************************************/
915error_t vfs_fs_remove_dentry( xptr_t         parent_inode_xp,
916                              vfs_dentry_t * dentry_ptr );
917
918/******************************************************************************************
919 * This function scan a directory mapper, identified by the <parent_inode_xp> argument
920 * to find a directory entry identified by the <dentry_ptr> argument,
921 * and updates both the child inode descriptor, and the associated dentry descriptor:
922 * - It set the "size", "type", and "extend" fields in inode descriptor.
923 * - It set the "extend" field in dentry descriptor.
924 * It is called by the vfs_lookup() function in case of miss, and does NOT take any lock.
925 * Depending on the file system type, it calls the relevant, FS specific function.
926 * This function can be called by any thread running in any cluster.
927 ******************************************************************************************
928 * @ parent_inode_xp  : extended pointer on parent inode (directory).
929 * @ dentry_ptr       : local pointer on new entry (in parent inode cluster).
930 * @ return 0 if success / return -1 if dentry not found.
931 *****************************************************************************************/
932error_t vfs_fs_new_dentry_from_mapper( xptr_t         parent_inode_xp,
933                                       vfs_dentry_t * dentry_ptr );
934
935/*****************************************************************************************
936 * This function  introduces a brand new dentry identified by the <dentry_ptr> argument
937 * in the mapper of a directory identified by the <parent_inode_xp> argument.
938 * It is called by the vfs_lookup() function, and does NOT take any lock.
939 * The child inode descriptor, and the dentry descriptor must have been previously
940 * allocated and introduced in the Inode Tree. The dentry descriptor contains the name.
941 * Depending on the file system type, it calls the relevant, FS specific function.
942 * This function can be called by any thread running in any cluster.
943 *****************************************************************************************
944 * @ parent_inode_xp : [in]  extended pointer on parent inode (directory).
945 * @ dentry_ptr      : [in]  local pointer on dentry (in parent inode cluster).
946 * @ return 0 if success / return -1 if failure.
947 ****************************************************************************************/
948error_t vfs_fs_new_dentry_to_mapper( xptr_t         parent_inode_xp,
949                                     vfs_dentry_t * dentry_ptr );
950
951/******************************************************************************************
952 * This function updates the "size" field of a directory entry identified by the
953 * <dentry_ptr> argument in a directory mapper identified by the <parent_inode_xp>
954 * from the value contained in the inode descriptor.
955 * The parent directory on device is synchronously updated.
956 * It is called by the vfs_close() function.
957 * Depending on the file system type, it calls the relevant, FS specific function.
958 * This function can be called by any thread running in any cluster.
959 ******************************************************************************************
960 * @ parent_inode_xp  : local pointer on parent inode (directory).
961 * @ dentry_ptr       : local pointer on dentry (in parent directory cluster).
962 * @ return 0 if success / return -1 if not found.
963 *****************************************************************************************/
964error_t vfs_fs_update_dentry( xptr_t         parent_inode_xp,
965                              vfs_dentry_t * dentry_ptr );
966
967/******************************************************************************************
968 * This function scan the mapper of an an existing parent inode directory, identified by
969 * the <inode> argument and copy up to <max_dirent> valid dentries to a
970 * local dirent array, defined by the <array> argument. The <min_dentry> argument defines
971 * the index of the first dentry to copied to the target dirent array.
972 * This function returns in the <entries> buffer the number of dentries actually written,
973 * and signals in the <done> buffer when the last valid entry has been found.
974 * If the <detailed> argument is true, a dentry/inode couple that does not exist in
975 * the Inode Tree is dynamically created, and all dirent fiels are documented in the
976 * dirent array. Otherwise, only the dentry name is documented.
977 * This function does NOT take any lock.
978 * Depending on the file system type, it calls the relevant, FS specific function.
979 *
980 * WARNING : this function must be called by a thread running in the cluster containing
981 * the target directory inode.
982 ******************************************************************************************
983 * @ inode      : [in]  local pointer on directory inode.
984 * @ array      : [in]  local pointer on array of dirents.
985 * @ max_dirent : [in]  max number of slots in dirent array.
986 * @ min_dentry : [in]  index of first dentry to be copied into array.
987 * @ detailed   : [in]  dynamic inode creation if true.
988 * @ entries    : [out] number of dentries actually copied into array.
989 * @ done       : [out] Boolean true when last entry found.
990 * @ return 0 if success / return -1 if failure.
991 *****************************************************************************************/
992error_t vfs_fs_get_user_dir( vfs_inode_t   * inode,
993                             struct dirent * array,
994                             uint32_t        max_dirent,
995                             uint32_t        min_dentry,
996                             bool_t          detailed,
997                             uint32_t      * entries,
998                             bool_t        * done );
999 
1000/*****************************************************************************************
1001 * This function  updates the FS on the IOC device for a given inode identified by
1002 * the <inode> argument. It scan all pages registered in the associated mapper,
1003 * and copies from mapper to device each page marked as dirty.
1004 * WARNING : The target <inode> cannot be a directory, because all modifications in a
1005 * directory are synchronously done on the IOC device by the two vfs_fs_add_dentry()
1006 * and vfs_fs_remove_dentry() functions.
1007 * Depending on the file system type, it calls the relevant, FS specific function.
1008 * This function can be called by any thread running in any cluster.
1009 *****************************************************************************************
1010 * @ inode_xp   : remote pointer on inode.
1011 * @ return 0 if success / return -1 if failure.
1012 ****************************************************************************************/
1013error_t vfs_fs_sync_inode( xptr_t inode_xp );
1014
1015/*****************************************************************************************
1016 * This function updates the FS defined by the <fs_type> argument on the IOC device
1017 * for the FAT itself. It scan all clusters registered in the FAT mapper, and copies
1018 * to device each page marked as dirty.
1019 * Depending on the file system type, it calls the relevant, FS specific function.
1020 * It can be called by a thread running in any cluster.
1021 *****************************************************************************************
1022 * @ fs_type   : specific file system type.
1023 * @ return 0 if success / return EIO if failure during device access.
1024 ****************************************************************************************/
1025error_t vfs_fs_sync_fat( vfs_fs_type_t fs_type );
1026
1027/******************************************************************************************
1028 * This function makes all I/O operations required to release all clusters allocated
1029 * on IOC device to a given inode, identified by the <inode_xp> argument.
1030 * Depending on the file system type, it calls the proper, FS specific function.
1031 * It is called by the vfs_unlink() function.
1032 * This function does NOT take any lock.
1033 * Depending on the file system type, it calls the relevant, FS specific function.
1034 * This function can be executed by any thread running in any cluster.
1035 ******************************************************************************************
1036 * @ inode_xp  : extended pointer on inode.
1037 * @ return 0 if success / return -1 if device access failure.
1038 *****************************************************************************************/
1039error_t vfs_fs_release_inode( xptr_t  inode_xp ); 
1040
1041/******************************************************************************************
1042 * This function makes the I/O operation to move one page identified by the <page_xp>
1043 * argument to/from the IOC device from/to the mapper, as defined by the <cmd_type>.
1044 * It is used in case of MISS on the mapper (read), or when a dirty page in the mapper
1045 * must be updated in the File System (write).
1046 * The mapper pointer, and the page index in file are obtained from the page descriptor.
1047 * This function does NOT take any lock.
1048 * Depending on the file system type, it calls the proper, FS specific function.
1049 * This function can be executed by any thread running in any cluster.
1050 ******************************************************************************************
1051 * @ page_xp   : extended pointer on page descriptor (for mapper and page_id).
1052 * @ cmd_type  : IOC_READ / IOC_WRITE / IOC_SYNC_READ / IOC_SYNC_WRITE
1053 * @ returns 0 if success / return -1 if device access failure.
1054 *****************************************************************************************/
1055error_t vfs_fs_move_page( xptr_t          page_xp,
1056                          ioc_cmd_type_t  cmd_type );
1057
1058
1059#endif  /* _VFS_H_ */
Note: See TracBrowser for help on using the repository browser.