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
)
98 if (TAO_debug_level
> 0)
100 TAOLIB_ERROR ((LM_ERROR
,
101 ACE_TEXT ("(%P|%t) TAO::Storable_FlatFileStream, file_copy, f2 handle = %d, %p\n"),
102 ACE_OS::fileno(f2
), ACE_TEXT ("ACE_OS::fwrite")));
112 if (TAO_debug_level
> 0)
114 TAOLIB_ERROR ((LM_ERROR
,
115 ACE_TEXT ("(%P|%t) TAO::Storable_FlatFileStream, file_copy, f1 handle = %d, %p\n"),
116 ACE_OS::fileno(f1
), ACE_TEXT ("ACE_OS::fread")));
127 TAO::Storable_FlatFileStream::Storable_FlatFileStream (const ACE_CString
& file
,
131 : Storable_Base(use_backup
, retry_on_ebadf
)
137 // filelock_ will be completely initialized in call to init ().
138 filelock_
.handle_
= ACE_INVALID_HANDLE
;
139 filelock_
.lockname_
= nullptr;
142 TAO::Storable_FlatFileStream::~Storable_FlatFileStream ()
144 if ( fl_
!= nullptr )
149 TAO::Storable_FlatFileStream::do_remove ()
151 ACE_OS::unlink(file_
.c_str());
155 TAO::Storable_FlatFileStream::exists ()
157 // We could check the mode for this file, but for now just check exists
158 return ! ACE_OS::access(file_
.c_str(), F_OK
);
162 TAO::Storable_FlatFileStream::reopen ()
164 if (TAO_debug_level
> 0)
166 TAOLIB_DEBUG ((LM_DEBUG
,
167 ACE_TEXT ("TAO (%P|%t) Storable_FlatFileStream::reopen, ")
168 ACE_TEXT (" handle = %d\n"),
176 TAO::Storable_FlatFileStream::open()
178 // For now, three flags exist "r", "w", and "c"
180 const char *fdmode
= nullptr;
181 if( ACE_OS::strchr(mode_
.c_str(), 'r') )
182 if( ACE_OS::strchr(mode_
.c_str(), 'w') )
183 flags
= O_RDWR
, fdmode
= "w+";
185 flags
= O_RDONLY
, fdmode
= "r";
187 flags
= O_WRONLY
, fdmode
= "w";
188 if( ACE_OS::strchr(mode_
.c_str(), 'c') )
192 if( ACE_OS::flock_init (&filelock_
, flags
,
193 ACE_TEXT_CHAR_TO_TCHAR (file_
.c_str()), 0666) != 0 )
194 TAOLIB_ERROR_RETURN ((LM_ERROR
,
195 ACE_TEXT ("(%P|%t) Storable_FFS::open ")
196 ACE_TEXT ("Cannot open file %s for mode %s: %p\n"),
197 file_
.c_str(), mode_
.c_str(), ACE_TEXT ("ACE_OS::flock_init")),
200 if( (filelock_
.handle_
= ACE_OS::open (file_
.c_str(), flags
, 0)) == ACE_INVALID_HANDLE
)
201 TAOLIB_ERROR_RETURN ((LM_ERROR
,
202 ACE_TEXT ("(%P|%t) Storable_FFS::open ")
203 ACE_TEXT ("Cannot open file %s for mode %s: %p\n"),
204 file_
.c_str(), mode_
.c_str(), ACE_TEXT ("ACE_OS::open")),
209 for (int attempts
= this->retry_on_ebadf_
? 2 : 1;
210 attempts
> 0 && this->fl_
== nullptr;
213 this->fl_
= ACE_OS::fdopen(filelock_
.handle_
, ACE_TEXT_CHAR_TO_TCHAR (fdmode
));
215 if (this->fl_
== nullptr)
217 if (TAO_debug_level
> 0)
219 TAOLIB_ERROR ((LM_ERROR
,
220 ACE_TEXT ("(%P|%t) Storable_FFS::open ")
221 ACE_TEXT ("Cannot open file %s for mode %s: %p\n"),
222 file_
.c_str(), mode_
.c_str(), ACE_TEXT ("ACE_OS::fdopen")));
230 return this->fl_
== nullptr ? -1 : 0;
234 TAO::Storable_FlatFileStream::close()
238 ACE_OS::flock_destroy (&filelock_
, 0);
240 ACE_OS::fclose (fl_
); // even though flock_destroy closes the handle
241 // we still need to destroy the FILE*
248 TAO::Storable_FlatFileStream::flock (int whence
, int start
, int len
)
251 #if defined (ACE_WIN32)
252 ACE_UNUSED_ARG (whence
);
253 ACE_UNUSED_ARG (start
);
254 ACE_UNUSED_ARG (len
);
256 bool shared
= ACE_OS::strcmp(mode_
.c_str(), "r") == 0;
259 for (int attempts
= this->retry_on_ebadf_
? 2 : 1;
260 attempts
> 0 && result
!= 0;
267 ACE_OS::flock_rdlock(&filelock_
, whence
, start
, len
) :
268 ACE_OS::flock_wrlock(&filelock_
, whence
, start
, len
);
271 if (TAO_debug_level
> 0)
273 TAOLIB_ERROR ((LM_ERROR
,
274 ACE_TEXT ("TAO (%P|%t) - ")
275 ACE_TEXT ("Storable_FlatFileStream::flock, ")
276 ACE_TEXT ("File %C, %p\n"),
278 (shared
? ACE_TEXT("rdlock") : ACE_TEXT("wrlock"))));
292 TAO::Storable_FlatFileStream::funlock (int whence
, int start
, int len
)
295 #if defined (ACE_WIN32)
296 ACE_UNUSED_ARG (whence
);
297 ACE_UNUSED_ARG (start
);
298 ACE_UNUSED_ARG (len
);
302 for (int attempts
= this->retry_on_ebadf_
? 2 : 1;
303 attempts
> 0 && result
!= 0;
309 result
= ACE_OS::flock_unlock(&filelock_
, whence
, start
, len
);
312 if (TAO_debug_level
> 0)
314 TAOLIB_ERROR ((LM_ERROR
,
315 ACE_TEXT ("TAO (%P|%t) - ")
316 ACE_TEXT ("Storable_FlatFileStream::flock, ")
317 ACE_TEXT ("File %C, %p\n"),
319 ACE_TEXT("unlock")));
333 TAO::Storable_FlatFileStream::last_changed()
337 bool do_stat
= filelock_
.handle_
== ACE_INVALID_HANDLE
;
342 for (int attempts
= this->retry_on_ebadf_
? 2 : 1;
343 attempts
> 0 && result
!= 0;
350 result
= ACE_OS::fstat(filelock_
.handle_
, &st
);
353 if (TAO_debug_level
> 0)
355 TAOLIB_ERROR ((LM_ERROR
,
356 ACE_TEXT ("TAO (%P|%t) - ")
357 ACE_TEXT ("Storable_FlatFileStream::last_changed, ")
358 ACE_TEXT ("File %C, handle %d, %p\n"),
359 file_
.c_str (), filelock_
.handle_
, ACE_TEXT("fstat")));
370 result
= ACE_OS::stat (file_
.c_str (), &st
);
374 TAOLIB_ERROR ((LM_ERROR
,
375 ACE_TEXT ("TAO (%P|%t) - ")
376 ACE_TEXT ("Storable_FlatFileStream::last_changed, ")
377 ACE_TEXT ("Error getting file information for %C, handle %d, %p\n"),
378 this->file_
.c_str(), filelock_
.handle_
, ACE_TEXT("fstat")));
379 throw Storable_Exception (this->file_
);
386 TAO::Storable_FlatFileStream::rewind ()
388 ACE_OS::rewind(this->fl_
);
392 TAO::Storable_FlatFileStream::flush ()
394 return ACE_OS::fflush(this->fl_
);
398 TAO::Storable_FlatFileStream::sync ()
400 return ACE_OS::fsync (this->filelock_
.handle_
);
404 TAO::Storable_FlatFileStream::operator << (const ACE_CString
& str
)
407 ACE_OS::fprintf(this->fl_
, ACE_SSIZE_T_FORMAT_SPECIFIER_ASCII
"\n%s\n",
408 str
.length(), str
.c_str());
410 this->throw_on_write_error (badbit
);
416 TAO::Storable_FlatFileStream::operator >> (ACE_CString
& str
)
419 ACE_CString::size_type
const max_buf_len
=
420 ACE_Numeric_Limits
<ACE_CString::size_type
>::max ();
421 int const max_int
= ACE_Numeric_Limits
<int>::max ();
422 switch (fscanf(fl_
, "%d\n", &bufSize
))
425 this->throw_on_read_error (badbit
);
428 this->throw_on_read_error (eofbit
);
432 || static_cast<ACE_CString::size_type
> (bufSize
) >= max_buf_len
433 || bufSize
== max_int
)
435 this->throw_on_read_error (badbit
);
438 int const strSize
= bufSize
+ 1; // Account for newline
439 std::unique_ptr
<char[]> str_array (new char[strSize
]);
441 if (ACE_OS::fgets (str_array
.get (),
443 this->fl_
) == nullptr
446 this->throw_on_read_error (badbit
);
448 str
= ACE_CString (str_array
.get (), nullptr, false);
455 TAO::Storable_FlatFileStream::operator << (ACE_UINT32 i
)
458 ACE_OS::fprintf (this->fl_
, ACE_UINT32_FORMAT_SPECIFIER_ASCII
"\n", i
);
460 this->throw_on_write_error (badbit
);
465 TAO::Storable_FlatFileStream::operator >> (ACE_UINT32
&i
)
467 Storable_State state
= this->rdstate ();
468 read_integer (ACE_UINT32_FORMAT_SPECIFIER_ASCII
"\n", i
, state
, fl_
);
469 this->throw_on_read_error (state
);
475 TAO::Storable_FlatFileStream::operator << (ACE_UINT64 i
)
478 ACE_OS::fprintf (this->fl_
, ACE_UINT64_FORMAT_SPECIFIER_ASCII
"\n", i
);
480 this->throw_on_write_error (badbit
);
485 TAO::Storable_FlatFileStream::operator >> (ACE_UINT64
&i
)
487 Storable_State state
= this->rdstate ();
488 read_integer (ACE_UINT64_FORMAT_SPECIFIER_ASCII
"\n", i
, state
, fl_
);
489 this->throw_on_read_error (state
);
495 TAO::Storable_FlatFileStream::operator << (ACE_INT32 i
)
498 ACE_OS::fprintf (this->fl_
, ACE_INT32_FORMAT_SPECIFIER_ASCII
"\n", i
);
500 this->throw_on_write_error (badbit
);
505 TAO::Storable_FlatFileStream::operator >> (ACE_INT32
&i
)
507 Storable_State state
= this->rdstate ();
508 read_integer (ACE_INT32_FORMAT_SPECIFIER_ASCII
"\n", i
, state
, fl_
);
509 this->throw_on_read_error (state
);
515 TAO::Storable_FlatFileStream::operator << (ACE_INT64 i
)
518 ACE_OS::fprintf (this->fl_
, ACE_INT64_FORMAT_SPECIFIER_ASCII
"\n", i
);
520 this->throw_on_write_error (badbit
);
525 TAO::Storable_FlatFileStream::operator >> (ACE_INT64
&i
)
527 Storable_State state
= this->rdstate ();
528 read_integer (ACE_INT64_FORMAT_SPECIFIER_ASCII
"\n", i
, state
, fl_
);
529 this->throw_on_read_error (state
);
536 TAO::Storable_FlatFileStream::operator << (const TAO_OutputCDR
& cdr
)
538 unsigned int const length
=
539 ACE_Utils::truncate_cast
<unsigned int> (cdr
.total_length ());
541 for (const ACE_Message_Block
*i
= cdr
.begin (); i
!= nullptr; i
= i
->cont ())
543 const char *bytes
= i
->rd_ptr ();
544 size_t const len
= i
->length ();
545 this->write (len
, bytes
);
551 TAO::Storable_FlatFileStream::write (size_t size
, const char * bytes
)
553 return ACE_OS::fwrite (bytes
, size
, 1, fl_
);
557 TAO::Storable_FlatFileStream::read (size_t size
, char * bytes
)
559 return ACE_OS::fread (bytes
, size
, 1, fl_
);
563 TAO::Storable_FlatFileStream::backup_file_name ()
565 return file_
+ ".bak";
569 TAO::Storable_FlatFileStream::create_backup ()
571 if (this->fl_
== nullptr)
578 for (int attempts
= this->retry_on_ebadf_
? 2 : 1;
579 attempts
> 0 && result
< 0;
595 FILE * backup
= ACE_OS::fopen (this->backup_file_name ().c_str (), "w");
596 result
= file_copy(this->fl_
, backup
);
599 if (TAO_debug_level
> 0)
601 TAOLIB_ERROR ((LM_ERROR
,
602 ACE_TEXT ("TAO: (%P|%t) Storable_FlatFileStream::")
603 ACE_TEXT ("create_backup Unable to create backup ")
604 ACE_TEXT ("of file %s\n"), file_
.c_str ()));
608 ACE_OS::fclose (backup
);
612 ACE_OS::fclose (backup
);
618 TAO::Storable_FlatFileStream::remove_backup ()
620 ACE_CString backup_name
= this->backup_file_name ();
622 if (ACE_OS::access (backup_name
.c_str (), F_OK
) == 0)
624 ACE_OS::unlink (backup_name
.c_str ());
629 TAO::Storable_FlatFileStream::restore_backup ()
631 ACE_CString backup_name
= this->backup_file_name ().c_str ();
633 if (ACE_OS::access (backup_name
.c_str (), F_OK
))
636 if (ACE_OS::strchr (this->mode_
.c_str(),'w') == nullptr)
642 FILE * backup
= ACE_OS::fopen (backup_name
.c_str (),
645 int result
= file_copy(backup
, this->fl_
);
646 ACE_OS::fclose (backup
);
653 TAO::Storable_FlatFileStream::throw_on_read_error (Storable_State state
)
655 this->setstate (state
);
659 throw Storable_Read_Exception (this->rdstate (), this->file_
);
664 TAO::Storable_FlatFileStream::throw_on_write_error (Storable_State state
)
666 this->setstate (state
);
670 throw Storable_Write_Exception (this->rdstate (), this->file_
);
674 //------------------------------------------------
676 TAO::Storable_FlatFileFactory::Storable_FlatFileFactory(const ACE_CString
& directory
,
679 : Storable_Factory ()
680 , directory_(directory
)
681 , use_backup_(use_backup
)
682 , retry_on_ebadf_ (retry_on_ebadf
)
686 TAO::Storable_FlatFileFactory::Storable_FlatFileFactory(const ACE_CString
& directory
,
688 : Storable_Factory ()
689 , directory_(directory
)
690 , use_backup_(use_backup
)
691 , retry_on_ebadf_ (Storable_Base::retry_on_ebadf_default
)
693 retry_on_ebadf_
= Storable_FlatFileFactory::is_nfs (directory
);
697 TAO::Storable_FlatFileFactory::is_nfs (const ACE_CString
& directory
)
700 #if defined (ACE_HAS_MNTENT)
701 const char *dir
= directory
.c_str();
702 char rpath
[PATH_MAX
];
706 if (ACE_OS::getcwd (rpath
, PATH_MAX
) == nullptr)
708 if (TAO_debug_level
> 0)
710 TAOLIB_ERROR ((LM_ERROR
,
711 ACE_TEXT ("TAO (%P|%t) Storable_FFFactory::is_nfs ")
712 ACE_TEXT ("could not get full path, %p\n"),
713 ACE_TEXT ("getcwd")));
717 size_t rootlen
= ACE_OS::strlen(rpath
);
718 if ((rootlen
+ directory
.length() +1) > PATH_MAX
)
720 if (TAO_debug_level
> 0)
722 TAOLIB_ERROR ((LM_ERROR
,
723 ACE_TEXT ("TAO (%P|%t) Storable_FFFactory::is_nfs ")
724 ACE_TEXT ("combined root + supplied paths too long:")
725 ACE_TEXT ("%C + / + %C\n"), rpath
, dir
));
729 char *pos
= rpath
+ rootlen
;
731 ACE_OS::strcpy (pos
,directory
.c_str());
735 size_t dirlen
= ACE_OS::strlen(dir
);
736 struct mntent
*ent
= nullptr;
737 const char *fname
= "/etc/mtab";
738 FILE *mt
= ::setmntent(fname
,"r");
741 if (TAO_debug_level
> 0)
743 TAOLIB_ERROR ((LM_ERROR
,
744 ACE_TEXT ("TAO (%P|%t) Storable_FFFactory::is_nfs ")
745 ACE_TEXT ("could not open %C, %p\n"),
746 fname
, ACE_TEXT ("setmntent")));
750 while ((ent
= ::getmntent(mt
)) != nullptr)
752 size_t len
= ACE_OS::strlen(ent
->mnt_dir
);
754 if (len
> dirlen
|| len
< match
)
758 if (len
>= match
&&ACE_OS::strstr (dir
, ent
->mnt_dir
) == dir
)
761 ret
= (ACE_OS::strcasecmp (ent
->mnt_type
, "nfs") == 0);
764 break; // exact match
770 ACE_UNUSED_ARG (directory
);
771 #endif /* ACE_HAS_MNTENT */
775 TAO::Storable_FlatFileFactory::~Storable_FlatFileFactory()
780 TAO::Storable_FlatFileFactory::get_directory () const
786 TAO::Storable_FlatFileFactory::create_stream (const ACE_CString
& file
,
790 TAO::Storable_Base
*stream
= nullptr;
791 ACE_CString path
= this->directory_
+ "/" + file
;
792 ACE_NEW_RETURN (stream
,
793 TAO::Storable_FlatFileStream(path
,
796 this->retry_on_ebadf_
),
801 TAO_END_VERSIONED_NAMESPACE_DECL