1.1.9 release a
[asdcplib.git] / src / KM_fileio.cpp
1 /*
2 Copyright (c) 2004-2006, John Hurst
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 1. Redistributions of source code must retain the above copyright
9    notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11    notice, this list of conditions and the following disclaimer in the
12    documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14    derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27   /*! \file    KM_fileio.cpp
28     \version $Id$
29     \brief   portable file i/o
30   */
31
32 #include <KM_fileio.h>
33 #include <KM_log.h>
34 #include <fcntl.h>
35 #include <assert.h>
36
37 using namespace Kumu;
38
39 #ifdef KM_WIN32
40 typedef struct _stati64 fstat_t;
41 #define S_IFLNK 0
42
43
44 // win32 has WriteFileGather() and ReadFileScatter() but they
45 // demand page alignment and page sizing, making them unsuitable
46 // for use with arbitrary buffer sizes.
47 struct iovec {
48   char* iov_base; // stupid iovec uses char*
49   int   iov_len;
50 };
51 #else
52 #include <sys/uio.h>
53 typedef struct stat     fstat_t;
54 #endif
55
56 //
57 static Kumu::Result_t
58 do_stat(const char* path, fstat_t* stat_info)
59 {
60   KM_TEST_NULL_STR(path);
61   KM_TEST_NULL(stat_info);
62
63   Kumu::Result_t result = Kumu::RESULT_OK;
64
65 #ifdef KM_WIN32
66   UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
67
68   if ( _stati64(path, stat_info) == (__int64)-1 )
69     result = Kumu::RESULT_FILEOPEN;
70
71   ::SetErrorMode( prev );
72 #else
73   if ( stat(path, stat_info) == -1L )
74     result = Kumu::RESULT_FILEOPEN;
75
76   if ( stat_info->st_mode & (S_IFREG|S_IFLNK|S_IFDIR) == 0 )
77     result = Kumu::RESULT_FILEOPEN;
78 #endif
79
80   return result;
81 }
82
83 #ifndef KM_WIN32
84
85 //
86 static Kumu::Result_t
87 do_fstat(HANDLE handle, fstat_t* stat_info)
88 {
89   KM_TEST_NULL(stat_info);
90
91   Kumu::Result_t result = Kumu::RESULT_OK;
92
93   if ( fstat(handle, stat_info) == -1L )
94     result = Kumu::RESULT_FILEOPEN;
95
96   if ( stat_info->st_mode & (S_IFREG|S_IFLNK|S_IFDIR) == 0 )
97     result = Kumu::RESULT_FILEOPEN;
98
99   return result;
100 }
101
102 #endif
103
104
105 //
106 bool
107 Kumu::PathIsFile(const char* pathname)
108 {
109   assert(pathname);
110   fstat_t info;
111
112   if ( KM_SUCCESS(do_stat(pathname, &info)) )
113     {
114       if ( info.st_mode & ( S_IFREG|S_IFLNK ) )
115         return true;
116     }
117
118   return false;
119 }
120
121
122 //
123 bool
124 Kumu::PathIsDirectory(const char* pathname)
125 {
126   assert(pathname);
127   fstat_t info;
128
129   if ( KM_SUCCESS(do_stat(pathname, &info)) )
130     {
131       if ( info.st_mode & S_IFDIR )
132         return true;
133     }
134
135   return false;
136 }
137
138
139 //
140 Kumu::fsize_t
141 Kumu::FileSize(const char* pathname)
142 {
143   assert(pathname);
144   fstat_t info;
145
146   if ( KM_SUCCESS(do_stat(pathname, &info)) )
147     {
148       if ( info.st_mode & ( S_IFREG|S_IFLNK ) )
149         return(info.st_size);
150     }
151
152   return 0;
153 }
154
155 //------------------------------------------------------------------------------------------
156 // portable aspects of the file classes
157
158 const int IOVecMaxEntries = 32; // we never use more that 3, but that number seems somehow small...
159
160 //
161 class Kumu::FileWriter::h__iovec
162 {
163 public:
164   int            m_Count;
165   struct iovec   m_iovec[IOVecMaxEntries];
166   h__iovec() : m_Count(0) {}
167 };
168
169
170
171 //
172 Kumu::fsize_t
173 Kumu::FileReader::Size() const
174 {
175 #ifdef KM_WIN32
176   return FileSize(m_Filename.c_str());
177 #else
178   fstat_t info;
179
180   if ( KM_SUCCESS(do_fstat(m_Handle, &info)) )
181     {
182       if ( info.st_mode & ( S_IFREG|S_IFLNK ) )
183         return(info.st_size);
184     }
185 #endif
186
187   return 0;
188 }
189
190 // these are declared here instead of in the header file
191 // because we have a mem_ptr that is managing a hidden class
192 Kumu::FileWriter::FileWriter() {}
193 Kumu::FileWriter::~FileWriter() {}
194
195 //
196 Kumu::Result_t
197 Kumu::FileWriter::Writev(const byte_t* buf, ui32_t buf_len)
198 {
199   assert( ! m_IOVec.empty() );
200   register h__iovec* iov = m_IOVec;
201   KM_TEST_NULL(buf);
202
203   if ( iov->m_Count >= IOVecMaxEntries )
204     {
205       DefaultLogSink().Error("The iovec is full! Only %u entries allowed before a flush.\n",
206                              IOVecMaxEntries);
207       return RESULT_FAIL;
208     }
209
210   iov->m_iovec[iov->m_Count].iov_base = (char*)buf; // stupid iovec uses char*
211   iov->m_iovec[iov->m_Count].iov_len = buf_len;
212   iov->m_Count++;
213
214   return RESULT_OK;
215 }
216
217
218 #ifdef KM_WIN32
219 //------------------------------------------------------------------------------------------
220 //
221
222 Kumu::Result_t
223 Kumu::FileReader::OpenRead(const char* filename) const
224 {
225   KM_TEST_NULL_STR(filename);
226   const_cast<FileReader*>(this)->m_Filename = filename;
227   
228   // suppress popup window on error
229   UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
230
231   const_cast<FileReader*>(this)->m_Handle = ::CreateFile(filename,
232                           (GENERIC_READ),                // open for reading
233                           FILE_SHARE_READ,               // share for reading
234                           NULL,                          // no security
235                           OPEN_EXISTING,                 // read
236                           FILE_ATTRIBUTE_NORMAL,         // normal file
237                           NULL                           // no template file
238                           );
239
240   ::SetErrorMode(prev);
241
242   return ( m_Handle == INVALID_HANDLE_VALUE ) ?
243     Kumu::RESULT_FILEOPEN : Kumu::RESULT_OK;
244 }
245
246 //
247 Kumu::Result_t
248 Kumu::FileReader::Close() const
249 {
250   if ( m_Handle == INVALID_HANDLE_VALUE )
251     return Kumu::RESULT_FILEOPEN;
252
253   // suppress popup window on error
254   UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
255   BOOL result = ::CloseHandle(m_Handle);
256   ::SetErrorMode(prev);
257   const_cast<FileReader*>(this)->m_Handle = INVALID_HANDLE_VALUE;
258
259   return ( result == 0 ) ? Kumu::RESULT_FAIL : Kumu::RESULT_OK;
260 }
261
262 //
263 Kumu::Result_t
264 Kumu::FileReader::Seek(Kumu::fpos_t position, SeekPos_t whence) const
265 {
266   if ( m_Handle == INVALID_HANDLE_VALUE )
267     return Kumu::RESULT_STATE;
268
269   LARGE_INTEGER in;
270   UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
271   in.QuadPart = position;
272   in.LowPart = ::SetFilePointer(m_Handle, in.LowPart, &in.HighPart, whence);
273   HRESULT LastError = GetLastError();
274   ::SetErrorMode(prev);
275
276   if ( (LastError != NO_ERROR
277         && (in.LowPart == INVALID_SET_FILE_POINTER
278             || in.LowPart == ERROR_NEGATIVE_SEEK )) )
279     return Kumu::RESULT_READFAIL;
280   
281   return Kumu::RESULT_OK;
282 }
283
284 //
285 Kumu::Result_t
286 Kumu::FileReader::Tell(Kumu::fpos_t* pos) const
287 {
288   KM_TEST_NULL(pos);
289
290   if ( m_Handle == (HANDLE)-1L )
291     return Kumu::RESULT_FILEOPEN;
292
293   LARGE_INTEGER in;
294   UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
295   in.QuadPart = (__int64)0;
296   in.LowPart = ::SetFilePointer(m_Handle, in.LowPart, &in.HighPart, FILE_CURRENT);
297   HRESULT LastError = GetLastError();
298   ::SetErrorMode(prev);
299
300   if ( (LastError != NO_ERROR
301         && (in.LowPart == INVALID_SET_FILE_POINTER
302             || in.LowPart == ERROR_NEGATIVE_SEEK )) )
303     return Kumu::RESULT_READFAIL;
304
305   *pos = (Kumu::fpos_t)in.QuadPart;
306   return Kumu::RESULT_OK;
307 }
308
309 //
310 Kumu::Result_t
311 Kumu::FileReader::Read(byte_t* buf, ui32_t buf_len, ui32_t* read_count) const
312 {
313   KM_TEST_NULL(buf);
314   Result_t result = Kumu::RESULT_OK;
315   DWORD    tmp_count;
316   ui32_t tmp_int;
317
318   if ( read_count == 0 )
319     read_count = &tmp_int;
320
321   *read_count = 0;
322
323   if ( m_Handle == INVALID_HANDLE_VALUE )
324     return Kumu::RESULT_FILEOPEN;
325   
326   UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
327   if ( ::ReadFile(m_Handle, buf, buf_len, &tmp_count, NULL) == 0 )
328     result = Kumu::RESULT_READFAIL;
329
330   ::SetErrorMode(prev);
331
332   if ( tmp_count == 0 ) /* EOF */
333     result = Kumu::RESULT_ENDOFFILE;
334
335   if ( KM_SUCCESS(result) )
336     *read_count = tmp_count;
337
338   return result;
339 }
340
341
342
343 //------------------------------------------------------------------------------------------
344 //
345
346 //
347 Kumu::Result_t
348 Kumu::FileWriter::OpenWrite(const char* filename)
349 {
350   KM_TEST_NULL_STR(filename);
351   m_Filename = filename;
352   
353   // suppress popup window on error
354   UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
355
356   m_Handle = ::CreateFile(filename,
357                           (GENERIC_WRITE|GENERIC_READ),  // open for reading
358                           FILE_SHARE_READ,               // share for reading
359                           NULL,                          // no security
360                           CREATE_ALWAYS,                 // overwrite (beware!)
361                           FILE_ATTRIBUTE_NORMAL,         // normal file
362                           NULL                           // no template file
363                           );
364
365   ::SetErrorMode(prev);
366
367   if ( m_Handle == INVALID_HANDLE_VALUE )
368     return Kumu::RESULT_FILEOPEN;
369   
370   m_IOVec = new h__iovec;
371   return Kumu::RESULT_OK;
372 }
373
374 //
375 Kumu::Result_t
376 Kumu::FileWriter::Writev(ui32_t* bytes_written)
377 {
378   assert( ! m_IOVec.empty() );
379   register h__iovec* iov = m_IOVec;
380   ui32_t tmp_int;
381
382   if ( bytes_written == 0 )
383     bytes_written = &tmp_int;
384
385   if ( m_Handle == INVALID_HANDLE_VALUE )
386     return Kumu::RESULT_STATE;
387
388   *bytes_written = 0;
389   UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
390   Result_t result = Kumu::RESULT_OK;
391
392   // AFAIK, there is no writev() equivalent in the win32 API
393   for ( register int i = 0; i < iov->m_Count; i++ )
394     {
395       ui32_t tmp_count = 0;
396       BOOL wr_result = ::WriteFile(m_Handle,
397                                    iov->m_iovec[i].iov_base,
398                                    iov->m_iovec[i].iov_len,
399                                    (DWORD*)&tmp_count,
400                                    NULL);
401
402       if ( wr_result == 0 )
403         {
404           result = Kumu::RESULT_WRITEFAIL;
405           break;
406         }
407
408       assert(iov->m_iovec[i].iov_len == tmp_count);
409       *bytes_written += tmp_count;
410     }
411
412   ::SetErrorMode(prev);
413   iov->m_Count = 0; // error nor not, all is lost
414
415   return result;
416 }
417
418 //
419 Kumu::Result_t
420 Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written)
421 {
422   KM_TEST_NULL(buf);
423   ui32_t tmp_int;
424
425   if ( bytes_written == 0 )
426     bytes_written = &tmp_int;
427
428   if ( m_Handle == INVALID_HANDLE_VALUE )
429     return Kumu::RESULT_STATE;
430
431   // suppress popup window on error
432   UINT prev = ::SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
433   BOOL result = ::WriteFile(m_Handle, buf, buf_len, (DWORD*)bytes_written, NULL);
434   ::SetErrorMode(prev);
435
436   return ( result == 0 ) ? Kumu::RESULT_WRITEFAIL : Kumu::RESULT_OK;
437 }
438
439 #else // KM_WIN32
440 //------------------------------------------------------------------------------------------
441 // POSIX
442
443 //
444 Kumu::Result_t
445 Kumu::FileReader::OpenRead(const char* filename) const
446 {
447   KM_TEST_NULL_STR(filename);
448   const_cast<FileReader*>(this)->m_Filename = filename;
449   const_cast<FileReader*>(this)->m_Handle = open(filename, O_RDONLY, 0);
450   return ( m_Handle == -1L ) ? RESULT_FILEOPEN : RESULT_OK;
451 }
452
453 //
454 Kumu::Result_t
455 Kumu::FileReader::Close() const
456 {
457   if ( m_Handle == -1L )
458     return RESULT_FILEOPEN;
459
460   close(m_Handle);
461   const_cast<FileReader*>(this)->m_Handle = -1L;
462   return RESULT_OK;
463 }
464
465 //
466 Kumu::Result_t
467 Kumu::FileReader::Seek(Kumu::fpos_t position, SeekPos_t whence) const
468 {
469   if ( m_Handle == -1L )
470     return RESULT_FILEOPEN;
471
472   if ( lseek(m_Handle, position, whence) == -1L )
473     return RESULT_BADSEEK;
474
475   return RESULT_OK;
476 }
477
478 //
479 Kumu::Result_t
480 Kumu::FileReader::Tell(Kumu::fpos_t* pos) const
481 {
482   KM_TEST_NULL(pos);
483
484   if ( m_Handle == -1L )
485     return RESULT_FILEOPEN;
486
487   Kumu::fpos_t tmp_pos;
488
489   if (  (tmp_pos = lseek(m_Handle, 0, SEEK_CUR)) == -1 )
490     return RESULT_READFAIL;
491
492   *pos = tmp_pos;
493   return RESULT_OK;
494 }
495
496 //
497 Kumu::Result_t
498 Kumu::FileReader::Read(byte_t* buf, ui32_t buf_len, ui32_t* read_count) const
499 {
500   KM_TEST_NULL(buf);
501   i32_t  tmp_count = 0;
502   ui32_t tmp_int = 0;
503
504   if ( read_count == 0 )
505     read_count = &tmp_int;
506
507   *read_count = 0;
508
509   if ( m_Handle == -1L )
510     return RESULT_FILEOPEN;
511
512   if ( (tmp_count = read(m_Handle, buf, buf_len)) == -1L )
513     return RESULT_READFAIL;
514
515   *read_count = tmp_count;
516   return (tmp_count == 0 ? RESULT_ENDOFFILE : RESULT_OK);
517 }
518
519
520 //------------------------------------------------------------------------------------------
521 //
522
523 //
524 Kumu::Result_t
525 Kumu::FileWriter::OpenWrite(const char* filename)
526 {
527   KM_TEST_NULL_STR(filename);
528   m_Filename = filename;
529   m_Handle = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0664);
530
531   if ( m_Handle == -1L )
532     {
533       DefaultLogSink().Error("Error opening file %s: %s\n", filename, strerror(errno));
534       return RESULT_FILEOPEN;
535     }
536
537   m_IOVec = new h__iovec;
538   return RESULT_OK;
539 }
540
541 //
542 Kumu::Result_t
543 Kumu::FileWriter::OpenModify(const char* filename)
544 {
545   KM_TEST_NULL_STR(filename);
546   m_Filename = filename;
547   m_Handle = open(filename, O_RDWR|O_CREAT, 0664);
548
549   if ( m_Handle == -1L )
550     {
551       DefaultLogSink().Error("Error opening file %s: %s\n", filename, strerror(errno));
552       return RESULT_FILEOPEN;
553     }
554
555   m_IOVec = new h__iovec;
556   return RESULT_OK;
557 }
558
559 //
560 Kumu::Result_t
561 Kumu::FileWriter::Writev(ui32_t* bytes_written)
562 {
563   assert( ! m_IOVec.empty() );
564   register h__iovec* iov = m_IOVec;
565   ui32_t tmp_int;
566
567   if ( bytes_written == 0 )
568     bytes_written = &tmp_int;
569
570   if ( m_Handle == -1L )
571     return RESULT_STATE;
572
573   int read_size = writev(m_Handle, iov->m_iovec, iov->m_Count);
574   
575   if ( read_size == -1L )
576     return RESULT_WRITEFAIL;
577
578   iov->m_Count = 0;
579   *bytes_written = read_size;  
580   return RESULT_OK;
581 }
582
583 //
584 Kumu::Result_t
585 Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written)
586 {
587   KM_TEST_NULL(buf);
588   ui32_t tmp_int;
589
590   if ( bytes_written == 0 )
591     bytes_written = &tmp_int;
592
593   // TODO: flush iovec
594
595
596   if ( m_Handle == -1L )
597     return RESULT_STATE;
598
599   int read_size = write(m_Handle, buf, buf_len);
600   
601   if ( read_size == -1L )
602     return RESULT_WRITEFAIL;
603
604   *bytes_written = read_size;  
605   return RESULT_OK;
606 }
607
608
609 #endif // KM_WIN32
610
611 //------------------------------------------------------------------------------------------
612
613
614 //
615 Kumu::Result_t
616 Kumu::ReadFileIntoString(const char* filename, std::string& outString, ui32_t max_size)
617 {
618   fsize_t    fsize = 0;
619   ui32_t     read_size = 0;
620   FileReader File;
621   ByteString ReadBuf;
622
623   KM_TEST_NULL_STR(filename);
624
625   Result_t result = File.OpenRead(filename);
626
627   if ( KM_SUCCESS(result) )
628     {
629       fsize = File.Size();
630
631       if ( fsize > (Kumu::fpos_t)max_size )
632         {
633           DefaultLogSink().Error("%s: exceeds available buffer size (%u)", filename, max_size);
634           return RESULT_ALLOC;
635         }
636
637       result = ReadBuf.Capacity((ui32_t)fsize);
638     }
639
640   if ( KM_SUCCESS(result) )
641     result = File.Read(ReadBuf.Data(), ReadBuf.Capacity(), &read_size);
642
643   if ( KM_SUCCESS(result) )
644     outString.assign((const char*)ReadBuf.RoData(), read_size);
645
646   return result;
647 }
648
649
650 //
651 Kumu::Result_t
652 Kumu::WriteStringIntoFile(const char* filename, const std::string& inString)
653 {
654   FileWriter File;
655   ui32_t write_count = 0;
656   KM_TEST_NULL_STR(filename);
657
658   Result_t result = File.OpenWrite(filename);
659
660   if ( KM_SUCCESS(result) )
661     result = File.Write((byte_t*)inString.c_str(), inString.length(), &write_count);
662
663   if ( KM_SUCCESS(result) && write_count != inString.length() )
664     return RESULT_WRITEFAIL;
665
666   return RESULT_OK;
667 }
668
669
670 //------------------------------------------------------------------------------------------
671 //
672
673 // Win32 directory scanner
674 //
675 #ifdef KM_WIN32
676
677 //
678 //
679 Result_t
680 Kumu::DirScanner::Open(const char* filename)
681 {
682   KM_TEST_NULL_STR(filename);
683
684   // we need to append a '*' to read the entire directory
685   ui32_t fn_len = strlen(filename); 
686   char* tmp_file = (char*)malloc(fn_len + 8);
687
688   if ( tmp_file == 0 )
689     return RESULT_ALLOC;
690
691   strcpy(tmp_file, filename);
692   char* p = &tmp_file[fn_len] - 1;
693
694   if ( *p != '/' && *p != '\\' )
695     {
696       p++;
697       *p++ = '/';
698     }
699
700   *p++ = '*';
701   *p = 0;
702   // whew...
703
704   m_Handle = _findfirsti64(tmp_file, &m_FileInfo);
705   Result_t result = RESULT_OK;
706
707   if ( m_Handle == -1 )
708     result = RESULT_NOT_FOUND;
709
710   return result;
711 }
712
713
714 //
715 //
716 Result_t
717 Kumu::DirScanner::Close()
718 {
719   if ( m_Handle == -1 )
720     return RESULT_FILEOPEN;
721
722   if ( _findclose((long)m_Handle) == -1 )
723     return RESULT_FAIL;
724
725   m_Handle = -1;
726   return RESULT_OK;
727 }
728
729
730 // This sets filename param to the same per-instance buffer every time, so
731 // the value will change on the next call
732 Result_t
733 Kumu::DirScanner::GetNext(char* filename)
734 {
735   KM_TEST_NULL(filename);
736
737   if ( m_Handle == -1 )
738     return RESULT_FILEOPEN;
739
740   if ( m_FileInfo.name[0] == '\0' )
741     return RESULT_ENDOFFILE;
742
743   strncpy(filename, m_FileInfo.name, MaxFilePath);
744   Result_t result = RESULT_OK;
745
746   if ( _findnexti64((long)m_Handle, &m_FileInfo) == -1 )
747     {
748       m_FileInfo.name[0] = '\0';
749           
750       if ( errno != ENOENT )
751         result = RESULT_FAIL;
752     }
753
754   return result;
755 }
756
757
758 #else // KM_WIN32
759
760 // POSIX directory scanner
761
762 //
763 Result_t
764 Kumu::DirScanner::Open(const char* filename)
765 {
766   KM_TEST_NULL_STR(filename);
767
768   Result_t result = RESULT_OK;
769
770   if ( ( m_Handle = opendir(filename) ) == NULL )
771     {
772       if ( errno == ENOENT )
773         result = RESULT_ENDOFFILE;
774
775       else
776         result = RESULT_FAIL;
777     }
778
779   return result;
780 }
781
782
783 //
784 Result_t
785 Kumu::DirScanner::Close()
786 {
787   if ( m_Handle == NULL )
788     return RESULT_FILEOPEN;
789
790   if ( closedir(m_Handle) == -1 )
791     return RESULT_FAIL;
792
793   m_Handle = NULL;
794   return RESULT_OK;
795 }
796
797
798 //
799 Result_t
800 Kumu::DirScanner::GetNext(char* filename)
801 {
802   KM_TEST_NULL(filename);
803
804   if ( m_Handle == NULL )
805     return RESULT_FILEOPEN;
806
807   struct dirent* entry;
808
809   for (;;)
810     {
811       if ( ( entry = readdir(m_Handle)) == NULL )
812         return RESULT_ENDOFFILE;
813
814       break;
815     }
816
817   strncpy(filename, entry->d_name, MaxFilePath);
818   return RESULT_OK;
819 }
820
821
822 #endif // KM_WIN32
823
824
825
826 //
827 // end KM_fileio.cpp
828 //