4 //=============================================================================
6 * @file Storable_FlatFileStream.cpp
8 * @author Marina Spivak <marina@cs.wustl.edu>
9 * @author Byron Harris <harrisb@ociweb.com>
11 //=============================================================================
13 #include "tao/Storable_FlatFileStream.h"
15 #include "ace/OS_NS_unistd.h"
16 #include "ace/OS_NS_fcntl.h"
17 #include "ace/OS_NS_sys_stat.h"
18 #include "ace/OS_NS_strings.h"
19 #include "ace/Numeric_Limits.h"
20 #include "ace/Truncate.h"
21 #include "tao/debug.h"
23 #if defined (ACE_HAS_MNTENT)
25 #endif /* ACE_HAS_MNTENT */
29 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
33 /// Avoids using fscanf to read an integer as any
34 /// whitespace following the newline will be
35 /// consumed. This could create problems if
36 /// the data that follows the newline is binary.
38 void read_integer(const char * format
, T
& i
,
39 TAO::Storable_Base::Storable_State
& state
,
43 char * result
= fgets (buf
, BUFSIZ
, fl
);
45 if (result
== nullptr)
49 state
= TAO::Storable_Base::eofbit
;
52 state
= TAO::Storable_Base::badbit
;
56 /// Consume any starting newline, as fscanf would
60 result
= fgets (buf
, BUFSIZ
, fl
);
63 if (result
== nullptr)
67 state
= TAO::Storable_Base::eofbit
;
70 state
= TAO::Storable_Base::badbit
;
74 switch (sscanf (buf
, format
, &i
))
77 state
= TAO::Storable_Base::badbit
;
80 state
= TAO::Storable_Base::eofbit
;
85 int file_copy (FILE *f1
, FILE *f2
)
93 ACE_OS::fread(buffer
, 1, sizeof(buffer
), f1
);
96 if (ACE_OS::fwrite(buffer
, 1, n_read
, f2
) != n_read
)
99 if (TAO_debug_level
> 0)
101 TAOLIB_ERROR ((LM_ERROR
,
102 ACE_TEXT ("(%P|%t) TAO::Storable_FlatFileStream, file_copy, f2 handle = %d, %p\n"),
103 ACE_OS::fileno(f2
), ACE_TEXT ("ACE_OS::fwrite")));
114 if (TAO_debug_level
> 0)
116 TAOLIB_ERROR ((LM_ERROR
,
117 ACE_TEXT ("(%P|%t) TAO::Storable_FlatFileStream, file_copy, f1 handle = %d, %p\n"),
118 ACE_OS::fileno(f1
), ACE_TEXT ("ACE_OS::fread")));
129 TAO::Storable_FlatFileStream::Storable_FlatFileStream (const ACE_CString
& file
,
133 : Storable_Base(use_backup
, retry_on_ebadf
)
139 // filelock_ will be completely initialized in call to init ().
140 filelock_
.handle_
= ACE_INVALID_HANDLE
;
141 filelock_
.lockname_
= nullptr;
144 TAO::Storable_FlatFileStream::~Storable_FlatFileStream ()
146 if ( fl_
!= nullptr )
151 TAO::Storable_FlatFileStream::do_remove ()
153 ACE_OS::unlink(file_
.c_str());
157 TAO::Storable_FlatFileStream::exists ()
159 // We could check the mode for this file, but for now just check exists
160 return ! ACE_OS::access(file_
.c_str(), F_OK
);
164 TAO::Storable_FlatFileStream::reopen ()
166 if (TAO_debug_level
> 0)
168 TAOLIB_DEBUG ((LM_DEBUG
,
169 ACE_TEXT ("TAO (%P|%t) Storable_FlatFileStream::reopen, ")
170 ACE_TEXT (" handle = %d\n"),
178 TAO::Storable_FlatFileStream::open()
180 // For now, three flags exist "r", "w", and "c"
182 const char *fdmode
= nullptr;
183 if( ACE_OS::strchr(mode_
.c_str(), 'r') )
184 if( ACE_OS::strchr(mode_
.c_str(), 'w') )
185 flags
= O_RDWR
, fdmode
= "w+";
187 flags
= O_RDONLY
, fdmode
= "r";
189 flags
= O_WRONLY
, fdmode
= "w";
190 if( ACE_OS::strchr(mode_
.c_str(), 'c') )
194 if( ACE_OS::flock_init (&filelock_
, flags
,
195 ACE_TEXT_CHAR_TO_TCHAR (file_
.c_str()), 0666) != 0 )
196 TAOLIB_ERROR_RETURN ((LM_ERROR
,
197 ACE_TEXT ("(%P|%t) Storable_FFS::open ")
198 ACE_TEXT ("Cannot open file %s for mode %s: %p\n"),
199 file_
.c_str(), mode_
.c_str(), ACE_TEXT ("ACE_OS::flock_init")),
202 if( (filelock_
.handle_
= ACE_OS::open (file_
.c_str(), flags
, 0)) == ACE_INVALID_HANDLE
)
203 TAOLIB_ERROR_RETURN ((LM_ERROR
,
204 ACE_TEXT ("(%P|%t) Storable_FFS::open ")
205 ACE_TEXT ("Cannot open file %s for mode %s: %p\n"),
206 file_
.c_str(), mode_
.c_str(), ACE_TEXT ("ACE_OS::open")),
211 for (int attempts
= this->retry_on_ebadf_
? 2 : 1;
212 attempts
> 0 && this->fl_
== nullptr;
215 this->fl_
= ACE_OS::fdopen(filelock_
.handle_
, ACE_TEXT_CHAR_TO_TCHAR (fdmode
));
217 if (this->fl_
== nullptr)
219 if (TAO_debug_level
> 0)
221 TAOLIB_ERROR ((LM_ERROR
,
222 ACE_TEXT ("(%P|%t) Storable_FFS::open ")
223 ACE_TEXT ("Cannot open file %s for mode %s: %p\n"),
224 file_
.c_str(), mode_
.c_str(), ACE_TEXT ("ACE_OS::fdopen")));
232 return this->fl_
== nullptr ? -1 : 0;
236 TAO::Storable_FlatFileStream::close()
240 ACE_OS::flock_destroy (&filelock_
, 0);
242 ACE_OS::fclose (fl_
); // even though flock_destroy closes the handle
243 // we still need to destroy the FILE*
250 TAO::Storable_FlatFileStream::flock (int whence
, int start
, int len
)
253 #if defined (ACE_WIN32)
254 ACE_UNUSED_ARG (whence
);
255 ACE_UNUSED_ARG (start
);
256 ACE_UNUSED_ARG (len
);
258 bool shared
= ACE_OS::strcmp(mode_
.c_str(), "r") == 0;
261 for (int attempts
= this->retry_on_ebadf_
? 2 : 1;
262 attempts
> 0 && result
!= 0;
269 ACE_OS::flock_rdlock(&filelock_
, whence
, start
, len
) :
270 ACE_OS::flock_wrlock(&filelock_
, whence
, start
, len
);
273 if (TAO_debug_level
> 0)
275 TAOLIB_ERROR ((LM_ERROR
,
276 ACE_TEXT ("TAO (%P|%t) - ")
277 ACE_TEXT ("Storable_FlatFileStream::flock, ")
278 ACE_TEXT ("File %C, %p\n"),
280 (shared
? ACE_TEXT("rdlock") : ACE_TEXT("wrlock"))));
294 TAO::Storable_FlatFileStream::funlock (int whence
, int start
, int len
)
297 #if defined (ACE_WIN32)
298 ACE_UNUSED_ARG (whence
);
299 ACE_UNUSED_ARG (start
);
300 ACE_UNUSED_ARG (len
);
304 for (int attempts
= this->retry_on_ebadf_
? 2 : 1;
305 attempts
> 0 && result
!= 0;
311 result
= ACE_OS::flock_unlock(&filelock_
, whence
, start
, len
);
314 if (TAO_debug_level
> 0)
316 TAOLIB_ERROR ((LM_ERROR
,
317 ACE_TEXT ("TAO (%P|%t) - ")
318 ACE_TEXT ("Storable_FlatFileStream::flock, ")
319 ACE_TEXT ("File %C, %p\n"),
321 ACE_TEXT("unlock")));
335 TAO::Storable_FlatFileStream::last_changed()
339 bool do_stat
= filelock_
.handle_
== ACE_INVALID_HANDLE
;
344 for (int attempts
= this->retry_on_ebadf_
? 2 : 1;
345 attempts
> 0 && result
!= 0;
352 result
= ACE_OS::fstat(filelock_
.handle_
, &st
);
355 if (TAO_debug_level
> 0)
357 TAOLIB_ERROR ((LM_ERROR
,
358 ACE_TEXT ("TAO (%P|%t) - ")
359 ACE_TEXT ("Storable_FlatFileStream::last_changed, ")
360 ACE_TEXT ("File %C, handle %d, %p\n"),
361 file_
.c_str (), filelock_
.handle_
, ACE_TEXT("fstat")));
372 result
= ACE_OS::stat (file_
.c_str (), &st
);
376 TAOLIB_ERROR ((LM_ERROR
,
377 ACE_TEXT ("TAO (%P|%t) - ")
378 ACE_TEXT ("Storable_FlatFileStream::last_changed, ")
379 ACE_TEXT ("Error getting file information for %C, handle %d, %p\n"),
380 this->file_
.c_str(), filelock_
.handle_
, ACE_TEXT("fstat")));
381 throw Storable_Exception (this->file_
);
388 TAO::Storable_FlatFileStream::rewind ()
390 ACE_OS::rewind(this->fl_
);
394 TAO::Storable_FlatFileStream::flush ()
396 return ACE_OS::fflush(this->fl_
);
400 TAO::Storable_FlatFileStream::sync ()
402 return ACE_OS::fsync (this->filelock_
.handle_
);
406 TAO::Storable_FlatFileStream::operator << (const ACE_CString
& str
)
409 ACE_OS::fprintf(this->fl_
, ACE_SSIZE_T_FORMAT_SPECIFIER_ASCII
"\n%s\n",
410 str
.length(), str
.c_str());
412 this->throw_on_write_error (badbit
);
418 TAO::Storable_FlatFileStream::operator >> (ACE_CString
& str
)
421 ACE_CString::size_type
const max_buf_len
=
422 ACE_Numeric_Limits
<ACE_CString::size_type
>::max ();
423 int const max_int
= ACE_Numeric_Limits
<int>::max ();
424 switch (fscanf(fl_
, "%d\n", &bufSize
))
427 this->throw_on_read_error (badbit
);
430 this->throw_on_read_error (eofbit
);
434 || static_cast<ACE_CString::size_type
> (bufSize
) >= max_buf_len
435 || bufSize
== max_int
)
437 this->throw_on_read_error (badbit
);
440 int const strSize
= bufSize
+ 1; // Account for newline
441 std::unique_ptr
<char[]> str_array (new char[strSize
]);
443 if (ACE_OS::fgets (str_array
.get (),
445 this->fl_
) == nullptr
448 this->throw_on_read_error (badbit
);
450 str
= ACE_CString (str_array
.get (), nullptr, false);
457 TAO::Storable_FlatFileStream::operator << (ACE_UINT32 i
)
460 ACE_OS::fprintf (this->fl_
, ACE_UINT32_FORMAT_SPECIFIER_ASCII
"\n", i
);
462 this->throw_on_write_error (badbit
);
467 TAO::Storable_FlatFileStream::operator >> (ACE_UINT32
&i
)
469 Storable_State state
= this->rdstate ();
470 read_integer (ACE_UINT32_FORMAT_SPECIFIER_ASCII
"\n", i
, state
, fl_
);
471 this->throw_on_read_error (state
);
477 TAO::Storable_FlatFileStream::operator << (ACE_UINT64 i
)
480 ACE_OS::fprintf (this->fl_
, ACE_UINT64_FORMAT_SPECIFIER_ASCII
"\n", i
);
482 this->throw_on_write_error (badbit
);
487 TAO::Storable_FlatFileStream::operator >> (ACE_UINT64
&i
)
489 Storable_State state
= this->rdstate ();
490 read_integer (ACE_UINT64_FORMAT_SPECIFIER_ASCII
"\n", i
, state
, fl_
);
491 this->throw_on_read_error (state
);
497 TAO::Storable_FlatFileStream::operator << (ACE_INT32 i
)
500 ACE_OS::fprintf (this->fl_
, ACE_INT32_FORMAT_SPECIFIER_ASCII
"\n", i
);
502 this->throw_on_write_error (badbit
);
507 TAO::Storable_FlatFileStream::operator >> (ACE_INT32
&i
)
509 Storable_State state
= this->rdstate ();
510 read_integer (ACE_INT32_FORMAT_SPECIFIER_ASCII
"\n", i
, state
, fl_
);
511 this->throw_on_read_error (state
);
517 TAO::Storable_FlatFileStream::operator << (ACE_INT64 i
)
520 ACE_OS::fprintf (this->fl_
, ACE_INT64_FORMAT_SPECIFIER_ASCII
"\n", i
);
522 this->throw_on_write_error (badbit
);
527 TAO::Storable_FlatFileStream::operator >> (ACE_INT64
&i
)
529 Storable_State state
= this->rdstate ();
530 read_integer (ACE_INT64_FORMAT_SPECIFIER_ASCII
"\n", i
, state
, fl_
);
531 this->throw_on_read_error (state
);
538 TAO::Storable_FlatFileStream::operator << (const TAO_OutputCDR
& cdr
)
540 unsigned int const length
=
541 ACE_Utils::truncate_cast
<unsigned int> (cdr
.total_length ());
543 for (const ACE_Message_Block
*i
= cdr
.begin (); i
!= nullptr; i
= i
->cont ())
545 const char *bytes
= i
->rd_ptr ();
546 size_t const len
= i
->length ();
547 this->write (len
, bytes
);
553 TAO::Storable_FlatFileStream::write (size_t size
, const char * bytes
)
555 return ACE_OS::fwrite (bytes
, size
, 1, fl_
);
559 TAO::Storable_FlatFileStream::read (size_t size
, char * bytes
)
561 return ACE_OS::fread (bytes
, size
, 1, fl_
);
565 TAO::Storable_FlatFileStream::backup_file_name ()
567 return file_
+ ".bak";
571 TAO::Storable_FlatFileStream::create_backup ()
573 if (this->fl_
== nullptr)
580 for (int attempts
= this->retry_on_ebadf_
? 2 : 1;
581 attempts
> 0 && result
< 0;
597 FILE * backup
= ACE_OS::fopen (this->backup_file_name ().c_str (), "w");
598 result
= file_copy(this->fl_
, backup
);
601 if (TAO_debug_level
> 0)
603 TAOLIB_ERROR ((LM_ERROR
,
604 ACE_TEXT ("TAO: (%P|%t) Storable_FlatFileStream::")
605 ACE_TEXT ("create_backup Unable to create backup ")
606 ACE_TEXT ("of file %s\n"), file_
.c_str ()));
610 ACE_OS::fclose (backup
);
614 ACE_OS::fclose (backup
);
620 TAO::Storable_FlatFileStream::remove_backup ()
622 ACE_CString backup_name
= this->backup_file_name ();
624 if (ACE_OS::access (backup_name
.c_str (), F_OK
) == 0)
626 ACE_OS::unlink (backup_name
.c_str ());
631 TAO::Storable_FlatFileStream::restore_backup ()
633 ACE_CString backup_name
= this->backup_file_name ().c_str ();
635 if (ACE_OS::access (backup_name
.c_str (), F_OK
))
638 if (ACE_OS::strchr (this->mode_
.c_str(),'w') == nullptr)
644 FILE * backup
= ACE_OS::fopen (backup_name
.c_str (),
647 int result
= file_copy(backup
, this->fl_
);
648 ACE_OS::fclose (backup
);
655 TAO::Storable_FlatFileStream::throw_on_read_error (Storable_State state
)
657 this->setstate (state
);
661 throw Storable_Read_Exception (this->rdstate (), this->file_
);
666 TAO::Storable_FlatFileStream::throw_on_write_error (Storable_State state
)
668 this->setstate (state
);
672 throw Storable_Write_Exception (this->rdstate (), this->file_
);
676 //------------------------------------------------
678 TAO::Storable_FlatFileFactory::Storable_FlatFileFactory(const ACE_CString
& directory
,
681 : Storable_Factory ()
682 , directory_(directory
)
683 , use_backup_(use_backup
)
684 , retry_on_ebadf_ (retry_on_ebadf
)
688 TAO::Storable_FlatFileFactory::Storable_FlatFileFactory(const ACE_CString
& directory
,
690 : Storable_Factory ()
691 , directory_(directory
)
692 , use_backup_(use_backup
)
693 , retry_on_ebadf_ (Storable_Base::retry_on_ebadf_default
)
695 retry_on_ebadf_
= Storable_FlatFileFactory::is_nfs (directory
);
699 TAO::Storable_FlatFileFactory::is_nfs (const ACE_CString
& directory
)
702 #if defined (ACE_HAS_MNTENT)
703 const char *dir
= directory
.c_str();
704 char rpath
[PATH_MAX
];
708 if (ACE_OS::getcwd (rpath
, PATH_MAX
) == nullptr)
710 if (TAO_debug_level
> 0)
712 TAOLIB_ERROR ((LM_ERROR
,
713 ACE_TEXT ("TAO (%P|%t) Storable_FFFactory::is_nfs ")
714 ACE_TEXT ("could not get full path, %p\n"),
715 ACE_TEXT ("getcwd")));
719 size_t rootlen
= ACE_OS::strlen(rpath
);
720 if ((rootlen
+ directory
.length() +1) > PATH_MAX
)
722 if (TAO_debug_level
> 0)
724 TAOLIB_ERROR ((LM_ERROR
,
725 ACE_TEXT ("TAO (%P|%t) Storable_FFFactory::is_nfs ")
726 ACE_TEXT ("combined root + supplied paths too long:")
727 ACE_TEXT ("%C + / + %C\n"), rpath
, dir
));
731 char *pos
= rpath
+ rootlen
;
733 ACE_OS::strcpy (pos
,directory
.c_str());
737 size_t dirlen
= ACE_OS::strlen(dir
);
738 struct mntent
*ent
= nullptr;
739 const char *fname
= "/etc/mtab";
740 FILE *mt
= ::setmntent(fname
,"r");
743 if (TAO_debug_level
> 0)
745 TAOLIB_ERROR ((LM_ERROR
,
746 ACE_TEXT ("TAO (%P|%t) Storable_FFFactory::is_nfs ")
747 ACE_TEXT ("could not open %C, %p\n"),
748 fname
, ACE_TEXT ("setmntent")));
752 while ((ent
= ::getmntent(mt
)) != nullptr)
754 size_t len
= ACE_OS::strlen(ent
->mnt_dir
);
756 if (len
> dirlen
|| len
< match
)
760 if (len
>= match
&&ACE_OS::strstr (dir
, ent
->mnt_dir
) == dir
)
763 ret
= (ACE_OS::strcasecmp (ent
->mnt_type
, "nfs") == 0);
766 break; // exact match
772 ACE_UNUSED_ARG (directory
);
773 #endif /* ACE_HAS_MNTENT */
777 TAO::Storable_FlatFileFactory::~Storable_FlatFileFactory()
782 TAO::Storable_FlatFileFactory::get_directory () const
788 TAO::Storable_FlatFileFactory::create_stream (const ACE_CString
& file
,
792 TAO::Storable_Base
*stream
= nullptr;
793 ACE_CString path
= this->directory_
+ "/" + file
;
794 ACE_NEW_RETURN (stream
,
795 TAO::Storable_FlatFileStream(path
,
798 this->retry_on_ebadf_
),
803 TAO_END_VERSIONED_NAMESPACE_DECL