]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/io/fileio/v2_0/src/file.cxx
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / io / fileio / v2_0 / src / file.cxx
1 //==========================================================================
2 //
3 //      file.cxx
4 //
5 //      Fileio file operations
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 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):           nickg
44 // Contributors:        nickg
45 // Date:                2000-05-25
46 // Purpose:             Fileio file operations
47 // Description:         These are the functions that operate on files as a whole,
48 //                      such as open(), creat(), mkdir() etc.
49 //              
50 //              
51 //
52 //####DESCRIPTIONEND####
53 //
54 //==========================================================================
55
56 #include <pkgconf/hal.h>
57 #include <pkgconf/io_fileio.h>
58 #include <pkgconf/isoinfra.h>
59
60 #include <cyg/infra/cyg_trac.h>        // tracing macros
61 #include <cyg/infra/cyg_ass.h>         // assertion macros
62
63 #include <string.h>                    // string functions
64 #include <dirent.h>
65 #include <stdio.h>                     // stdin, stdout, stderr
66
67 #include "fio.h"                       // Private header
68
69 //==========================================================================
70 // Implement filesystem locking protocol. 
71
72 #define LOCK_FS( _mte_ )  {                             \
73    CYG_ASSERT(_mte_ != NULL, "Bad mount table entry");  \
74    CYG_ASSERT(_mte_->fs != NULL, "Bad mount filesystem entry");  \
75    cyg_fs_lock( _mte_, (_mte_)->fs->syncmode);          \
76 }
77
78 #define UNLOCK_FS( _mte_ ) cyg_fs_unlock( _mte_, (_mte_)->fs->syncmode)
79
80 //==========================================================================
81 // A local strcpy clone that returns a pointer to the end of the copied
82 // string, not the beginning.
83
84 static char *my_strcpy( char *s1, const char *s2 )
85 {
86     while( (*s1++ = *s2++) != 0);
87     return s1-1;
88 }
89
90 //==========================================================================
91 // Compare a pathname fragment with an element in a pathname. This
92 // deals with zero or separator termination and avoids substring
93 // matches.
94
95 static int pathcmp( const char *path, const char *name )
96 {
97     while( *path == *name && *path != '\0' )
98         path++, name++;
99     if( *name != '\0' ) return false;
100     if( *path == '/' || *path == '\0' ) return true;
101     return false;
102 }
103
104 //==========================================================================
105 // CWD support
106
107 #ifdef CYGPKG_IO_FILEIO_TRACK_CWD
108
109 // buffer for storing CWD path
110 static char cwd[PATH_MAX];
111 static size_t cwd_size = 0;
112
113
114 static void update_cwd( cyg_mtab_entry *mte, cyg_dir dir, const char *path )
115 {
116     char *p = cwd;
117
118     if( mte != cyg_cdir_mtab_entry || dir != cyg_cdir_dir )
119     {
120         // Here, the path is relative to the root of the filesystem,
121         // or in a totally new filesystem, initialize the cwd with the
122         // mount point name of the filesystem.
123
124         p = my_strcpy( p, mte->name );
125     }
126     else p = cwd+cwd_size;
127
128     // We must now copy the path into the cwd buffer while dealing
129     // with any "." and ".."  components textually.
130
131     while( *path != '\0' )
132     {
133         // skip any stray directory separators.
134         if( *path == '/' ) path++;
135
136         // Look for a "." entry and just ignore it.
137         if( pathcmp( path, "." ) )
138         {
139             path++;
140             continue;
141         }
142
143         // Look for a ".." entry. If found, chew off the last cwd
144         // entry.
145         if( pathcmp( path, ".." ) )
146         {
147             while( *(--p) != '/' );     // back up to last '/'
148             path += 2;                  // skip "..".
149             continue;
150         }
151
152         // Otherwise just copy the name fragment over to the cwd.
153
154         if( *(p-1) != '/' )
155             *p++ = '/';        // add a directory separator
156         while( *path != '/' && *path != '\0' )
157             *p++ = *path++;
158
159     }
160
161     // Zero terminate the cwd.
162     *p = '\0';
163     
164     // update size
165     cwd_size = p-cwd;
166 }
167
168 #else
169
170 #ifdef CYGPKG_KERNEL
171 static Cyg_Mutex getcwd_lock CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO_FS);
172 #endif
173
174 #endif
175
176
177 //==========================================================================
178 // Open a file
179
180 __externC int open( const char *path, int oflag, ... )
181 {
182     FILEIO_ENTRY();
183
184     // we want to be sure we pull in stdin/out/err, so they can be
185     // assigned to fds 0, 1 and 2
186 #ifdef CYGINT_ISO_STDIO_STREAMS
187     CYG_REFERENCE_OBJECT(stdin);
188     CYG_REFERENCE_OBJECT(stdout);
189     CYG_REFERENCE_OBJECT(stderr);
190 #endif
191
192     CYG_CANCELLATION_POINT;
193
194     int ret = 0;
195     int fd;
196     cyg_file *file;
197     cyg_mtab_entry *mte = cyg_cdir_mtab_entry;
198     cyg_dir dir = cyg_cdir_dir;
199     const char *name = path;
200
201     // At least one of O_RDONLY, O_WRONLY, O_RDWR must be provided
202     if( (oflag & O_RDWR) == 0 )
203         FILEIO_RETURN(EINVAL);
204
205     fd = cyg_fd_alloc(0);
206
207     if( fd < 0 )
208         FILEIO_RETURN(EMFILE);
209     
210     file = cyg_file_alloc();
211
212     if( file == NULL )
213     {
214         cyg_fd_free(fd);
215         FILEIO_RETURN(ENFILE);
216     }
217     
218     ret = cyg_mtab_lookup( &dir, &name, &mte );
219     
220     if( 0 != ret )
221     {
222         cyg_fd_free(fd);
223         cyg_file_free(file);
224         FILEIO_RETURN(ENOENT);
225     }
226
227     LOCK_FS( mte );
228     
229     ret = mte->fs->open( mte, dir, name, oflag, file );
230     
231     UNLOCK_FS( mte );
232     
233     if( 0 != ret )
234     {
235         cyg_fd_free(fd);
236         cyg_file_free(file);
237         FILEIO_RETURN(ret);
238     }
239
240     file->f_mte = mte;
241     file->f_syncmode = mte->fs->syncmode;
242     
243     cyg_fd_assign( fd, file );
244
245     FILEIO_RETURN_VALUE(fd);
246 }
247
248 //==========================================================================
249 // create a file
250
251 __externC int creat( const char *path, mode_t mode )
252 {
253     return open( path, O_WRONLY | O_CREAT | O_TRUNC, mode );
254 }
255
256
257 //==========================================================================
258 // Unlink/remove a file
259
260 __externC int unlink( const char *path )
261 {
262     FILEIO_ENTRY();
263     
264     int ret = 0;
265     cyg_mtab_entry *mte = cyg_cdir_mtab_entry;
266     cyg_dir dir = cyg_cdir_dir;
267     const char *name = path;
268
269     ret = cyg_mtab_lookup( &dir, &name, &mte );
270     
271     if( 0 != ret )
272         FILEIO_RETURN(ENOENT);
273
274     LOCK_FS( mte );
275         
276     ret = mte->fs->unlink( mte, dir, name );
277     
278     UNLOCK_FS( mte );
279     
280     FILEIO_RETURN(ret);
281 }
282
283 //==========================================================================
284 // Make a directory
285
286 __externC int mkdir( const char *path, mode_t mode )
287 {
288     FILEIO_ENTRY();
289     
290     int ret = 0;
291     cyg_mtab_entry *mte = cyg_cdir_mtab_entry;
292     cyg_dir dir = cyg_cdir_dir;
293     const char *name = path;
294
295     mode=mode;
296     
297     ret = cyg_mtab_lookup( &dir, &name, &mte );
298     
299     if( 0 != ret )
300         FILEIO_RETURN(ENOENT);
301
302     LOCK_FS( mte );
303     
304     ret = mte->fs->mkdir( mte, dir, name );
305     
306     UNLOCK_FS( mte );
307     
308     FILEIO_RETURN(ret);
309 }
310
311 //==========================================================================
312 // Remove a directory
313
314 __externC int rmdir( const char *path )
315 {
316     FILEIO_ENTRY();
317     
318     int ret = 0;
319     cyg_mtab_entry *mte = cyg_cdir_mtab_entry;
320     cyg_dir dir = cyg_cdir_dir;
321     const char *name = path;
322
323     ret = cyg_mtab_lookup( &dir, &name, &mte );
324     
325     if( 0 != ret )
326         FILEIO_RETURN(ENOENT);
327
328     LOCK_FS( mte );
329     
330     ret = mte->fs->rmdir( mte, dir, name );
331     
332     UNLOCK_FS( mte );
333     
334     FILEIO_RETURN(ret);
335 }
336
337 //==========================================================================
338 // Rename a file
339
340 __externC int rename( const char *path1, const char *path2 ) __THROW
341 {
342     FILEIO_ENTRY();
343     
344     int ret = 0;
345     cyg_mtab_entry *mte1 = cyg_cdir_mtab_entry;
346     cyg_mtab_entry *mte2 = cyg_cdir_mtab_entry;
347     cyg_dir dir1 = cyg_cdir_dir;
348     cyg_dir dir2 = cyg_cdir_dir;
349     const char *name1 = path1;
350     const char *name2 = path2;
351
352     ret = cyg_mtab_lookup( &dir1, &name1, &mte1 );
353     
354     if( 0 != ret )
355         FILEIO_RETURN(ENOENT);
356
357     ret = cyg_mtab_lookup( &dir2, &name2, &mte2 );
358     
359     if( 0 != ret )
360         FILEIO_RETURN(ENOENT);
361
362     // Cannot rename between different filesystems
363     if( mte1 != mte2 )
364         FILEIO_RETURN(EXDEV);
365
366     LOCK_FS( mte1 );
367     
368     ret = mte1->fs->rename( mte1, dir1, name1, dir2, name2 );
369
370     UNLOCK_FS( mte1 );
371     
372     FILEIO_RETURN(ret);
373 }
374
375 //==========================================================================
376 // Create a link from an existing file (path1) to a new one (path2)
377
378 __externC int link( const char *path1, const char *path2 )
379 {
380     FILEIO_ENTRY();
381     
382     int ret = 0;
383     cyg_mtab_entry *mte1 = cyg_cdir_mtab_entry;
384     cyg_mtab_entry *mte2 = cyg_cdir_mtab_entry;
385     cyg_dir dir1 = cyg_cdir_dir;
386     cyg_dir dir2 = cyg_cdir_dir;
387     const char *name1 = path1;
388     const char *name2 = path2;
389
390     ret = cyg_mtab_lookup( &dir1, &name1, &mte1 );
391     
392     if( 0 != ret )
393         FILEIO_RETURN(ENOENT);
394
395     ret = cyg_mtab_lookup( &dir2, &name2, &mte2 );
396     
397     if( 0 != ret )
398         FILEIO_RETURN(ENOENT);
399
400     // Cannot hard-link between different filesystems
401     if( mte1 != mte2 )
402         FILEIO_RETURN(EXDEV);
403
404     LOCK_FS( mte1 );
405     
406     ret = mte1->fs->link( mte1, dir1, name1, dir2, name2, CYG_FSLINK_HARD );
407
408     UNLOCK_FS( mte1 );
409     
410     FILEIO_RETURN(ret);
411 }
412
413 //==========================================================================
414 // Change current directory
415
416 __externC int chdir( const char *path )
417 {
418     FILEIO_ENTRY();
419     
420     int ret = 0;
421     cyg_mtab_entry *mte = cyg_cdir_mtab_entry;
422     cyg_dir dir = cyg_cdir_dir;
423     cyg_dir newdir;
424     const char *name = path;
425
426     ret = cyg_mtab_lookup( &dir, &name, &mte );
427     
428     if( 0 != ret )
429         FILEIO_RETURN(ENOENT);
430
431     LOCK_FS(mte);
432     
433     ret = mte->fs->chdir( mte, dir, name, &newdir );
434
435     UNLOCK_FS(mte);
436     
437     if( 0 != ret )
438         FILEIO_RETURN(ret);
439
440 #ifdef CYGPKG_IO_FILEIO_TRACK_CWD
441     update_cwd( mte, dir, name );
442 #endif
443     
444     if( cyg_cdir_mtab_entry != NULL && cyg_cdir_dir != CYG_DIR_NULL )
445     {
446         // Now detach from current cyg_cdir. We call the current directory's
447         // chdir routine with a NULL dir_out pointer.
448
449         LOCK_FS(cyg_cdir_mtab_entry);
450
451         ret = cyg_cdir_mtab_entry->fs->chdir( cyg_cdir_mtab_entry, cyg_cdir_dir, NULL, NULL );
452     
453         UNLOCK_FS(cyg_cdir_mtab_entry);
454
455         // We really shouldn't get an error here.
456         if( 0 != ret )
457             FILEIO_RETURN(ret);
458     }
459     
460     cyg_cdir_mtab_entry = mte;
461     cyg_cdir_dir = newdir;
462     
463     FILEIO_RETURN(ENOERR);
464 }
465
466 //==========================================================================
467 // Get file statistics
468
469 __externC int stat( const char *path, struct stat *buf )
470 {
471     FILEIO_ENTRY();
472     
473     int ret = 0;
474     cyg_mtab_entry *mte = cyg_cdir_mtab_entry;
475     cyg_dir dir = cyg_cdir_dir;
476     const char *name = path;
477
478     ret = cyg_mtab_lookup( &dir, &name, &mte );
479     
480     if( 0 != ret )
481         FILEIO_RETURN(ENOENT);
482
483     LOCK_FS( mte );
484     
485     ret = mte->fs->stat( mte, dir, name, buf );
486     
487     UNLOCK_FS( mte );
488     
489     FILEIO_RETURN(ret);
490 }
491
492 //==========================================================================
493 // Get file configurable pathname variables
494
495 __externC long pathconf( const char *path, int vname )
496 {
497     FILEIO_ENTRY();
498     
499     int ret = 0;
500     cyg_mtab_entry *mte = cyg_cdir_mtab_entry;
501     cyg_dir dir = cyg_cdir_dir;
502     const char *name = path;
503
504     ret = cyg_mtab_lookup( &dir, &name, &mte );
505     
506     if( 0 != ret )
507         FILEIO_RETURN(ENOENT);
508
509     struct cyg_pathconf_info info;
510
511     info.name = vname;
512     info.value = 0;
513         
514     LOCK_FS( mte );
515     
516     ret = mte->fs->getinfo( mte, dir, name,
517                             FS_INFO_CONF, (char *)&info, sizeof(info) );
518     
519     UNLOCK_FS( mte );
520     
521     if( 0 != ret )
522         FILEIO_RETURN(ret);
523
524     FILEIO_RETURN_VALUE(info.value);
525 }
526
527 //==========================================================================
528 // Sync filesystem without unmounting
529
530 __externC int cyg_fs_fssync( const char *path )
531 {
532     FILEIO_ENTRY();
533     
534     int ret = 0;
535     cyg_mtab_entry *mte = cyg_cdir_mtab_entry;
536     cyg_dir dir = cyg_cdir_dir;
537     const char *name = path;
538
539     ret = cyg_mtab_lookup( &dir, &name, &mte );
540     
541     if( 0 != ret )
542         FILEIO_RETURN(ENOENT);
543
544     LOCK_FS( mte );
545     
546     ret = mte->fs->setinfo( mte, dir, name, FS_INFO_SYNC, NULL, 0 );
547     
548     UNLOCK_FS( mte );
549     
550     if( 0 != ret )
551         FILEIO_RETURN(ret);
552
553     FILEIO_RETURN_VALUE(ENOERR);
554 }
555
556 //==========================================================================
557 // Set file attributes
558
559 __externC int cyg_fs_set_attrib( const char *fname, 
560                                  const cyg_fs_attrib_t new_attrib )
561 {
562     FILEIO_ENTRY();
563     
564     int ret = 0;
565     cyg_mtab_entry *mte = cyg_cdir_mtab_entry;
566     cyg_dir dir = cyg_cdir_dir;
567     const char *name = fname;
568
569     ret = cyg_mtab_lookup( &dir, &name, &mte );
570     
571     if( 0 != ret )
572         FILEIO_RETURN(ENOENT);
573
574     LOCK_FS( mte );
575     
576     ret = mte->fs->setinfo( mte, dir, name,
577                             FS_INFO_ATTRIB, 
578                             (char *)&new_attrib, sizeof(new_attrib) );
579     
580     UNLOCK_FS( mte );
581     
582     if( 0 != ret )
583         FILEIO_RETURN(ret);
584
585     FILEIO_RETURN(ENOERR);
586 }
587
588 //==========================================================================
589 // Get file attributes
590
591 __externC int cyg_fs_get_attrib( const char *fname, 
592                                  cyg_fs_attrib_t * const file_attrib )
593 {
594     FILEIO_ENTRY();
595     
596     int ret = 0;
597     cyg_mtab_entry *mte = cyg_cdir_mtab_entry;
598     cyg_dir dir = cyg_cdir_dir;
599     const char *name = fname;
600
601     ret = cyg_mtab_lookup( &dir, &name, &mte );
602     
603     if( 0 != ret )
604         FILEIO_RETURN(ENOENT);
605
606     LOCK_FS( mte );
607     
608     ret = mte->fs->getinfo( mte, dir, name,
609                             FS_INFO_ATTRIB, 
610                             (char *)file_attrib, sizeof(*file_attrib) );
611     
612     UNLOCK_FS( mte );
613     
614     if( 0 != ret )
615         FILEIO_RETURN(ret);
616
617     FILEIO_RETURN(ENOERR);
618 }
619
620 //==========================================================================
621 // Access() function.
622 // This simply piggybacks onto stat().
623
624 extern int      access(const char *path, int amode)
625 {
626     FILEIO_ENTRY();
627
628     int ret;
629     struct stat buf;
630     
631     ret = stat( path, &buf );
632
633     // Translate not found into EACCES if the F_OK bit is
634     // set.
635     if( (amode & F_OK) && (ret < 0) && (errno == ENOENT) )
636         FILEIO_RETURN(EACCES);
637
638     // All other errors go straight back to the user.
639     if( ret < 0 )
640         FILEIO_RETURN_VALUE(ret);
641
642     // At present we do not have any access modes, so there is nothing
643     // to test.  Just return success for all access modes.
644     
645     FILEIO_RETURN(ENOERR);
646 }
647
648 //==========================================================================
649 // getcwd()
650
651 __externC char *getcwd( char *buf, size_t size )
652 {
653     FILEIO_ENTRY();
654
655     int err = ENOERR;
656     cyg_mtab_entry *mte = cyg_cdir_mtab_entry;
657     cyg_dir dir = cyg_cdir_dir;
658     cyg_getcwd_info info;
659
660     if( size == 0 )
661     {
662         errno = EINVAL;
663         FILEIO_RETURN_VALUE(NULL);        
664     }
665         
666     info.buf = buf;
667     info.size = size;
668
669     LOCK_FS( mte );
670     
671     err = mte->fs->getinfo( mte, dir, "",
672                             FS_INFO_GETCWD, (char *)&info, sizeof(info) );
673     
674     UNLOCK_FS( mte );
675
676     if( err == ENOERR )
677         FILEIO_RETURN_VALUE(buf);
678
679     // Attempting to use filesystem support for getcwd() has
680     // failed.
681
682 #ifdef CYGPKG_IO_FILEIO_TRACK_CWD
683
684     // If this option is set, the current directory path has been
685     // tracked in chdir(). Just report that value here.
686     
687     if( size < cwd_size+1 )
688     {
689         errno = ERANGE;
690         FILEIO_RETURN_VALUE(NULL);        
691     }
692
693     char *p = my_strcpy( buf, cwd );
694     *p = '\0';
695
696 #else
697
698     // As a fallback we try to use ".." entries in the directory tree
699     // to climb back up to the root.  Because we cannot assume that
700     // any filesystem can handle more than one directory pointer we
701     // have to do the climbing textually, by manufacturing a path name
702     // consisting of ".."s. At each level we then scan the parent
703     // directory looking for the entry for the lower level directory
704     // by matching st_ino values. This is not guaranteed to work at
705     // all since there is no requirement on filesystems to support "."
706     // and "..", or for them to report distinct inode values in
707     // stat().
708
709     static char ddbuf[PATH_MAX];
710     char *p = buf+size-1;
711     int ddbufpos;
712
713     // Claim lock to serialize use of ddbuf.
714     FILEIO_MUTEX_LOCK(getcwd_lock);
715
716     // Initialize ddbuf with ".".
717     ddbuf[0] = '.';
718     ddbuf[1] = '\0';
719     ddbufpos = 1;
720
721     // Start result buffer with a zero terminator. We accumulate the
722     // path name in the top end of the result buffer.
723     *p = '\0';
724     
725     for(;;)
726     {
727         struct stat sdbuf;
728         struct stat sddbuf;
729
730         // Get status for "." and "..". If the filesystem does not
731         // support these, then this whole function will fail here.
732         
733         err = stat( ddbuf, &sdbuf );
734         if( err < 0 ) break;
735
736         ddbuf[ddbufpos++] = '/';
737         ddbuf[ddbufpos++] = '.';
738         ddbuf[ddbufpos++] = '.';
739         ddbuf[ddbufpos] = '\0';
740         
741         err = stat( ddbuf, &sddbuf );
742         if( err < 0 ) break;
743
744         // See whether we are at the root. This will be true when
745         // the inode numbers of "." and ".." are the same.
746         if( sdbuf.st_ino == sddbuf.st_ino )
747             break;
748
749         // We now need to find an entry in the ".." directory that
750         // matches the inode number of ".".
751
752         struct dirent de;
753         DIR *d = opendir( ddbuf );
754         if( d == NULL )
755         {
756             err = -1;
757             break;
758         }
759         
760         for(;;)
761         {
762             struct dirent *res;
763             struct stat objstat;
764             int i;
765             
766             err = readdir_r( d, &de, &res );
767             if( err < 0 || res == NULL ) break;
768
769             // Skip "." and ".." entries.
770             if( pathcmp( de.d_name, "." ) || pathcmp( de.d_name, ".." ) )
771                 continue;
772             
773             // Tack the name of the directory entry on to the ddbuf
774             // and stat the object.
775             
776             ddbuf[ddbufpos] = '/';
777             for( i = 0; de.d_name[i] != '\0'; i++ )
778                 ddbuf[ddbufpos+i+1] = de.d_name[i];
779             ddbuf[ddbufpos+i+1] = '\0';
780
781             // Take a look at it
782             err = stat( ddbuf, &objstat );
783             if( err < 0 ) break;
784
785             // Cast out directories
786             if( !S_ISDIR(objstat.st_mode) )
787                 continue;
788
789             // We have a directory. Compare its inode with that of "."
790             // and if they are the same, we have found our entry.
791
792             if( sdbuf.st_ino == objstat.st_ino )
793                 break;
794         }
795
796         ddbuf[ddbufpos] = '\0'; // reterminate ddbuf
797         
798         closedir( d );
799
800         // Halt on any errors.
801         if( err < 0 )
802             break;
803
804         // Here de contains the name of the directory entry in ".."
805         // that has the same inode as ".". Add the name to the path we
806         // are accumulating in the buffer.
807
808         char *q = de.d_name;
809         while( *q != '\0' ) q++;        // skip to end of name
810
811         do
812         {
813             *--p = *--q;
814         } while( q != de.d_name );
815
816         *--p = '/';                     // add a separator
817     }
818
819     // We have finished using ddbuf now.
820     FILEIO_MUTEX_UNLOCK(getcwd_lock);
821     
822     if( err < 0 )
823         FILEIO_RETURN_VALUE(NULL);
824
825     // We have the directory path in the top end of the buffer.  Add
826     // the mount point name at the beginning and copy the rest of the
827     // name down.
828
829     char *bp = buf;
830     
831     bp = my_strcpy( bp, mte->name );
832
833     // Sort out the separators between the mount name and the
834     // pathname.  This is a bit messy since we have to deal with mount
835     // names of both "/" and "/foo" and pathnames that start with '/'
836     // or are empty.
837     if( *(bp-1) != '/' && *p != '\0' ) *bp++ = '/';
838     if( *p == '/' ) p++;
839
840     // Now copy the path over.
841     while( *p )
842         *bp++ = *p++;
843
844     *bp = '\0';                         // Terminate the string
845
846     // All done!
847     
848 #endif
849     
850     FILEIO_RETURN_VALUE(buf);
851 }
852
853 //==========================================================================
854 // FS get info.
855
856 __externC int cyg_fs_getinfo( const char *path, int key, void *buf, int len )
857 {
858     FILEIO_ENTRY();
859     
860     int ret = 0;
861     cyg_mtab_entry *mte = cyg_cdir_mtab_entry;
862     cyg_dir dir = cyg_cdir_dir;
863     const char *name = path;
864     
865     ret = cyg_mtab_lookup( &dir, &name, &mte );
866     
867     if( 0 != ret )
868         FILEIO_RETURN(ENOENT);
869
870     LOCK_FS( mte );
871     
872     ret = mte->fs->getinfo( mte, dir, name, key, buf, len );
873     
874     UNLOCK_FS( mte );
875     
876     FILEIO_RETURN(ret);
877 }
878
879 //==========================================================================
880 // FS set info.
881
882 __externC int cyg_fs_setinfo( const char *path, int key, void *buf, int len )
883 {
884     FILEIO_ENTRY();
885     
886     int ret = 0;
887     cyg_mtab_entry *mte = cyg_cdir_mtab_entry;
888     cyg_dir dir = cyg_cdir_dir;
889     const char *name = path;
890     
891     ret = cyg_mtab_lookup( &dir, &name, &mte );
892     
893     if( 0 != ret )
894         FILEIO_RETURN(ENOENT);
895
896     LOCK_FS( mte );
897     
898     ret = mte->fs->setinfo( mte, dir, name, key, buf, len );
899     
900     UNLOCK_FS( mte );
901     
902     FILEIO_RETURN(ret);
903 }
904
905 // -------------------------------------------------------------------------
906 // EOF file.cxx