unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / io / fileio / v2_0 / src / misc.cxx
1 //==========================================================================
2 //
3 //      misc.cxx
4 //
5 //      Fileio miscellaneous functions
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2003 Gary Thomas
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 //
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s):           nickg
45 // Contributors:        nickg
46 // Date:                2000-05-25
47 // Purpose:             Fileio miscellaneous functions
48 // Description:         This file contains various miscellaneous functions
49 //                      for use with the fileio system. These include startup,
50 //                      table management, and other service routines.
51 //
52 //####DESCRIPTIONEND####
53 //
54 //==========================================================================
55
56 #include <pkgconf/system.h>
57 #include <pkgconf/hal.h>
58 #include <pkgconf/io_fileio.h>
59 #ifdef CYGPKG_LIBC_TIME
60 #include <pkgconf/libc_time.h>
61 #endif
62
63
64 #include <cyg/infra/cyg_trac.h>        // tracing macros
65 #include <cyg/infra/cyg_ass.h>         // assertion macros
66 #include <string.h>                    // strcmp()
67 #include <time.h>                      // time()
68
69 #ifdef CYGPKG_IO_WALLCLOCK
70 # include <cyg/io/wallclock.hxx>       // Wallclock class
71 #endif
72
73 #ifdef CYGPKG_KERNEL
74 #include <pkgconf/kernel.h>
75 #include <cyg/kernel/ktypes.h>         // base kernel types
76 #include <cyg/kernel/clock.inl>         // Clock inlines
77 #endif
78
79 #include "fio.h"                       // Private header
80
81 //==========================================================================
82 // forward definitions
83
84 static void cyg_mtab_init();
85
86 __externC int chdir( const char *path );
87
88 //==========================================================================
89 // Filesystem tables
90
91 // -------------------------------------------------------------------------
92 // Filesystem table.
93
94 // This array contains entries for all filesystem that are installed in
95 // the system.
96 __externC cyg_fstab_entry cyg_fstab[];
97 CYG_HAL_TABLE_BEGIN( cyg_fstab, fstab );
98
99 // end of filesystem table, set in linker script.
100 __externC cyg_fstab_entry cyg_fstab_end;
101 CYG_HAL_TABLE_END( cyg_fstab_end, fstab );
102
103 #ifdef CYGPKG_KERNEL
104 // Array of mutexes for locking the fstab entries
105 static Cyg_Mutex fstab_lock[CYGNUM_FILEIO_FSTAB_MAX] CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS);
106 #endif
107
108 // -------------------------------------------------------------------------
109 // Mount table.
110
111 // This array contains entries for all valid running filesystems.
112 __externC cyg_mtab_entry cyg_mtab[];
113 CYG_HAL_TABLE_BEGIN( cyg_mtab, mtab );
114
115 // Extra entries at end of mtab for dynamic mount points.
116 #if CYGNUM_FILEIO_MTAB_EXTRA > 0
117 cyg_mtab_entry cyg_mtab_extra[CYGNUM_FILEIO_MTAB_EXTRA] CYG_HAL_TABLE_EXTRA(mtab) = { { NULL } };
118 #endif
119 // End of mount table, set in the linker script.
120 __externC cyg_mtab_entry cyg_mtab_end;
121 CYG_HAL_TABLE_END( cyg_mtab_end, mtab );
122
123 #ifdef CYGPKG_KERNEL
124 // Array of mutexes for locking the mtab entries
125 static Cyg_Mutex mtab_lock[CYGNUM_FILEIO_MTAB_MAX] CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS);
126 #endif
127
128 //==========================================================================
129 // Current directory
130
131 cyg_mtab_entry *cyg_cdir_mtab_entry = NULL;
132 cyg_dir cyg_cdir_dir = CYG_DIR_NULL;
133
134 //==========================================================================
135 // Initialization object
136
137 class Cyg_Fileio_Init_Class
138 {
139 public:    
140     Cyg_Fileio_Init_Class();
141 };
142
143 static Cyg_Fileio_Init_Class fileio_initializer CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS);
144
145 Cyg_Fileio_Init_Class::Cyg_Fileio_Init_Class()
146 {
147     cyg_fd_init();
148
149     cyg_mtab_init();
150
151     chdir("/");
152 }
153
154 //==========================================================================
155 // Mount table initializer
156
157 static void cyg_mtab_init()
158 {
159     cyg_mtab_entry *m;
160     
161     for( m = &cyg_mtab[0]; m != &cyg_mtab_end; m++ )
162     {
163         const char *fsname = m->fsname;
164         cyg_fstab_entry *f;
165
166         // Ignore empty entries
167         if( m->name == NULL )
168             continue;
169         
170         // stop if there are more than the configured maximum
171         if( m-&cyg_mtab[0] >= CYGNUM_FILEIO_MTAB_MAX )
172             break;
173         
174         for( f = &cyg_fstab[0]; f != &cyg_fstab_end; f++ )
175         {
176             // stop if there are more than the configured maximum
177             if( f-&cyg_fstab[0] >= CYGNUM_FILEIO_FSTAB_MAX )
178                 break;
179             
180             if( strcmp( fsname, f->name) == 0 )
181             {
182                 // We have a match.
183
184                 if( f->mount( f, m ) == 0 )
185                 {
186                     m->valid    = true;
187                     m->fs       = f;
188                     // m->root installed by fs.
189                 }
190                 else
191                 {
192                     m->valid = false;
193                 }
194                 
195                 break;
196             }
197         }
198     }
199 }
200
201 //==========================================================================
202 // Mount table matching
203
204 // -------------------------------------------------------------------------
205 // matchlen() compares two strings and returns the number of bytes by which
206 // they match.
207
208 static int matchlen( const char *s1, const char *s2 )
209 {
210     int len = 0;
211     while( s1[len] == s2[len] && s1[len] && s2[len] ) len++;
212
213     // Return length only if s2 is an initial substring of s1,
214     // and it terminates in s1 at end-of-string or a '/'.
215
216     // Special case for s2 == "/"
217     if( len == 1 && s2[0] == '/' && s2[1] == 0 )
218         return len;
219     
220     if( (s2[len] == 0) && (s1[len] == 0 || s1[len] == '/'))
221          return len;
222     else return 0;
223 }
224
225 // -------------------------------------------------------------------------
226 // Simple strlen implementation
227
228 static int my_strlen(const char *c)
229 {
230     int l = 0;
231     while (*c++) l++;
232     return l;
233 }
234
235 // -------------------------------------------------------------------------
236 // Search the mtab for the entry that matches the longest substring of
237 // **name. 
238
239 __externC int cyg_mtab_lookup( cyg_dir *dir, const char **name, cyg_mtab_entry **mte)
240 {
241     cyg_mtab_entry *m, *best = NULL;
242     int best_len = 0;
243
244     // Unrooted file names start from current dir
245     if( **name != '/' ) {
246         int cwd_len;
247         if (*mte == (cyg_mtab_entry *)NULL) {
248             // No known current directory
249             return -1;
250         }
251
252         best = *mte;
253         cwd_len = my_strlen((*mte)->name);
254
255         // current dir is not the correct mte if the relative path crosses
256         // mount points -  search for best matching mount point
257         for( m = &cyg_mtab[0]; m != &cyg_mtab_end; m++ )
258         {
259             if( m->name != NULL && m->valid )
260             {
261                 int len = matchlen(m->name, (*mte)->name);
262                 // mount point under cwd?
263                 if (len == cwd_len)
264                 {
265                     if (m->name[len] == '/')
266                         len++;
267
268                     len = matchlen(*name, &m->name[len]);
269                     if (len > best_len)
270                         best = m, best_len = len;
271                 }
272             }
273         }
274
275         // did we find a better match?
276         if (best != *mte)
277           *dir = best->root;
278     }
279     else
280     {
281         // Otherwise search the mount table.
282         for( m = &cyg_mtab[0]; m != &cyg_mtab_end; m++ )
283         {
284             if( m->name != NULL && m->valid )
285             {
286                 int len = matchlen(*name,m->name);
287                 if( len > best_len )
288                     best = m, best_len = len;
289             }
290         }
291
292         // No match found, bad path name...
293         if( best_len == 0 ) return -1;
294
295         *dir = best->root;
296     }
297
298     *name += best_len;
299     if( **name == '/' )
300         (*name)++;
301     *mte = best;
302
303     return 0;
304 }
305
306 //==========================================================================
307 // mount filesystem
308
309 __externC int mount( const char *devname,
310                      const char *dir,
311                      const char *fsname)
312 {
313
314     FILEIO_ENTRY();
315     
316     cyg_mtab_entry *m;
317     cyg_fstab_entry *f;
318     int result = ENOERR;
319
320     // Search the mount table for an empty entry
321     for( m = &cyg_mtab[0]; m != &cyg_mtab_end; m++ )
322     {
323         // stop if there are more than the configured maximum
324         if( m-&cyg_mtab[0] >= CYGNUM_FILEIO_MTAB_MAX )
325         {
326             m = &cyg_mtab_end;
327             break;
328         }
329
330          if( m->name == NULL ) break;
331     }
332
333     if( m == &cyg_mtab_end )
334         FILEIO_RETURN(ENOMEM);
335
336     // Now search the fstab for the filesystem implementation
337     for( f = &cyg_fstab[0]; f != &cyg_fstab_end; f++ )
338     {
339         // stop if there are more than the configured maximum
340         if( f-&cyg_fstab[0] >= CYGNUM_FILEIO_FSTAB_MAX )
341             break;
342             
343         if( strcmp( fsname, f->name) == 0 )
344             break;
345     }
346
347     if( f == &cyg_fstab_end )
348         FILEIO_RETURN(ENODEV);
349             
350     // We have a match.
351
352     m->name = dir;
353     m->fsname = fsname;
354     m->devname = devname;
355     
356     if( (result = f->mount( f, m )) == 0 )
357     {
358         m->valid    = true;
359         m->fs       = f;
360         // m->root installed by fs.
361     }
362     else
363     {
364         m->valid = false;
365         m->name = NULL;
366     }
367
368     // Make sure that there is something to search (for open)
369
370     if (cyg_cdir_mtab_entry == (cyg_mtab_entry *)NULL) {
371         cyg_cdir_mtab_entry = m;
372     }
373
374     FILEIO_RETURN(result);
375 }
376
377 //==========================================================================
378 // unmount filesystem
379
380 __externC int umount( const char *name)
381 {
382     int err = ENOERR;
383     
384     FILEIO_ENTRY();
385     
386     cyg_mtab_entry *m;
387
388     // Search the mount table for a matching entry
389     for( m = &cyg_mtab[0]; m != &cyg_mtab_end; m++ )
390     {
391         // stop if there are more than the configured maximum
392         if( m-&cyg_mtab[0] >= CYGNUM_FILEIO_MTAB_MAX )
393         {
394             m = &cyg_mtab_end;
395             break;
396         }
397
398         // Ignore empty or invalid entries
399          if( m->name == NULL || !m->valid ) continue;
400
401          // match names.
402          if( strcmp(name,m->name) == 0 ) break;
403
404          // Match device name too?
405     }
406
407     if( m == &cyg_mtab_end )
408         FILEIO_RETURN(EINVAL);
409
410     // We have a match, call the umount function
411
412     err = m->fs->umount( m );
413
414     if( err == ENOERR )
415     {
416         m->valid        = false;
417         m->name         = NULL;
418     }
419     
420     FILEIO_RETURN(err);
421 }
422
423 //==========================================================================
424 // Implement filesystem locking protocol. 
425
426 void cyg_fs_lock( cyg_mtab_entry *mte, cyg_uint32 syncmode )
427 {
428     CYG_ASSERT(mte != NULL, "Bad mount table entry");
429
430     if( syncmode & CYG_SYNCMODE_FILE_FILESYSTEM ) {
431         CYG_ASSERT(mte->fs-&cyg_fstab[0] < CYGNUM_FILEIO_FSTAB_MAX, "Bad file system");
432         FILEIO_MUTEX_LOCK( fstab_lock[mte->fs-&cyg_fstab[0]] );
433     }
434
435     if( syncmode & CYG_SYNCMODE_FILE_MOUNTPOINT ) {
436         CYG_ASSERT(mte-&cyg_mtab[0] < CYGNUM_FILEIO_MTAB_MAX, "Bad mount point");
437         FILEIO_MUTEX_LOCK( mtab_lock[mte-&cyg_mtab[0]] );
438     }
439 }
440
441 void cyg_fs_unlock( cyg_mtab_entry *mte, cyg_uint32 syncmode )
442 {
443     CYG_ASSERT(mte != NULL, "Bad mount table entry");
444
445     if( syncmode & CYG_SYNCMODE_FILE_FILESYSTEM ) {
446         CYG_ASSERT(mte->fs-&cyg_fstab[0] < CYGNUM_FILEIO_FSTAB_MAX, "Bad file system");
447         FILEIO_MUTEX_UNLOCK( fstab_lock[mte->fs-&cyg_fstab[0]] );
448     }
449
450     if( syncmode & CYG_SYNCMODE_FILE_MOUNTPOINT ) {
451         CYG_ASSERT(mte-&cyg_mtab[0] < CYGNUM_FILEIO_MTAB_MAX, "Bad mount point");
452         FILEIO_MUTEX_UNLOCK( mtab_lock[mte-&cyg_mtab[0]] );
453     }
454 }
455
456 //==========================================================================
457 // Search mount table for a filesystems root. 
458
459 __externC cyg_mtab_entry * cyg_fs_root_lookup( cyg_dir *root ) 
460 {
461      cyg_mtab_entry *m;
462
463      for( m = &cyg_mtab[0]; m != &cyg_mtab_end; m++ ) 
464      {
465           if( (cyg_dir *)m->root == root )
466           {
467                return m;
468           }
469      }
470      return NULL;
471 }
472
473 //==========================================================================
474 // Timestamp support
475 // This provides access to the current time/date, expressed as a
476 // time_t.  It uses a number of mechanisms to do this, selecting
477 // whichever is available in the current configuration.
478
479 __externC time_t cyg_timestamp()
480 {
481 #if defined(CYGPKG_IO_WALLCLOCK)
482
483     // First, try to get the time from the wallclock device.
484     
485     return (time_t) Cyg_WallClock::wallclock->get_current_time();
486
487 #elif defined(CYGINT_ISO_POSIX_TIMERS)
488
489     // If POSIX is present, use the current value of the realtime
490     // clock.
491     
492     struct timespec tp;
493
494     clock_gettime( CLOCK_REALTIME, &tp );
495
496     return (time_t) tp.tv_sec;
497     
498 #elif defined(CYGPKG_KERNEL) 
499
500     // If all else fails, get the current realtime clock value and
501     // convert it to seconds ourself.
502     
503     static struct Cyg_Clock::converter sec_converter;
504     static cyg_bool initialized = false;
505     cyg_tick_count ticks;
506     
507     if( !initialized )
508     {
509         Cyg_Clock::real_time_clock->get_clock_to_other_converter( 1000000000, &sec_converter );
510         initialized = true;
511     }
512
513     ticks = Cyg_Clock::real_time_clock->current_value();
514     
515     return (time_t) Cyg_Clock::convert( ticks, &sec_converter );
516 #else    
517     /* No clock support at all. */
518     return (time_t) 0;
519 #endif    
520     
521 }
522
523 //==========================================================================
524 // Default functions
525
526 __externC int cyg_fileio_enosys() { return ENOSYS; }
527 __externC int cyg_fileio_erofs() { return EROFS; }
528 __externC int cyg_fileio_enoerr() { return ENOERR; }
529 __externC int cyg_fileio_enotdir() { return ENOTDIR; }
530
531 __externC cyg_bool cyg_fileio_seltrue (struct CYG_FILE_TAG *fp, int which, CYG_ADDRWORD info)
532 { return 1; }
533
534 // -------------------------------------------------------------------------
535 // EOF misc.cxx