00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 #include "libts.h"
00031 
00032 #include <errno.h>
00033 #include <sys/types.h>
00034 #include <sys/stat.h>
00035 #include <fcntl.h>
00036 
00037 #include "Error.h"
00038 
00039 #include "P_EventSystem.h"
00040 #include "I_Machine.h"
00041 #include "LogSock.h"
00042 
00043 #include "LogField.h"
00044 #include "LogFilter.h"
00045 #include "LogFormat.h"
00046 #include "LogBuffer.h"
00047 #include "LogFile.h"
00048 #include "LogHost.h"
00049 #include "LogObject.h"
00050 #include "LogUtils.h"
00051 #include "LogConfig.h"
00052 #include "Log.h"
00053 
00054 
00055 
00056 
00057 
00058 
00059 
00060 
00061 LogFile::LogFile(const char *name, const char *header, LogFileFormat format,
00062                  uint64_t signature, size_t ascii_buffer_size, size_t max_line_size)
00063   : m_file_format(format),
00064     m_name(ats_strdup(name)),
00065     m_header(ats_strdup(header)),
00066     m_signature(signature),
00067     m_meta_info(NULL),
00068     m_max_line_size(max_line_size)
00069 {
00070   delete m_meta_info;
00071   m_meta_info = NULL;
00072   m_fd = -1;
00073   m_start_time = 0L;
00074   m_end_time = 0L;
00075   m_bytes_written = 0;
00076   m_size_bytes = 0;
00077   m_ascii_buffer_size = (ascii_buffer_size < max_line_size ? max_line_size : ascii_buffer_size);
00078 
00079   Debug("log-file", "exiting LogFile constructor, m_name=%s, this=%p", m_name, this);
00080 }
00081 
00082 
00083 
00084 
00085 
00086 
00087 
00088 LogFile::LogFile (const LogFile& copy)
00089   : m_file_format (copy.m_file_format),
00090     m_name  (ats_strdup (copy.m_name)),
00091     m_header  (ats_strdup (copy.m_header)),
00092     m_signature (copy.m_signature),
00093     m_meta_info (NULL),
00094     m_ascii_buffer_size (copy.m_ascii_buffer_size),
00095     m_max_line_size (copy.m_max_line_size),
00096     m_fd (-1),
00097     m_start_time (0L),
00098     m_end_time (0L),
00099     m_bytes_written (0)
00100 {
00101     ink_release_assert(m_ascii_buffer_size >= m_max_line_size);
00102 
00103     Debug("log-file", "exiting LogFile copy constructor, m_name=%s, this=%p",
00104           m_name, this);
00105 }
00106 
00107 
00108 
00109 
00110 LogFile::~LogFile()
00111 {
00112   Debug("log-file", "entering LogFile destructor, this=%p", this);
00113   close_file();
00114 
00115   ats_free(m_name);
00116   ats_free(m_header);
00117   delete m_meta_info;
00118   Debug("log-file", "exiting LogFile destructor, this=%p", this);
00119 }
00120 
00121 
00122 
00123 
00124 
00125 
00126 
00127 bool LogFile::exists(const char *pathname)
00128 {
00129   ink_assert(pathname != NULL);
00130   return (pathname && ::access(pathname, F_OK) == 0);
00131 }
00132 
00133 
00134 
00135 
00136 
00137 void
00138 LogFile::change_name(const char *new_name)
00139 {
00140   ats_free(m_name);
00141   m_name = ats_strdup(new_name);
00142 }
00143 
00144 
00145 
00146 
00147 
00148 void
00149 LogFile::change_header(const char *header)
00150 {
00151   ats_free(m_header);
00152   m_header = ats_strdup(header);
00153 }
00154 
00155 
00156 
00157 
00158 
00159 
00160 
00161 
00162 int
00163 LogFile::open_file()
00164 {
00165   if (is_open()) {
00166     return LOG_FILE_NO_ERROR;
00167   }
00168 
00169   if (m_name && !strcmp(m_name, "stdout")) {
00170     m_fd = STDOUT_FILENO;
00171     return LOG_FILE_NO_ERROR;
00172   }
00173   
00174   
00175   
00176   
00177   bool file_exists = LogFile::exists(m_name);
00178 
00179   if (file_exists) {
00180     if (!m_meta_info) {
00181       
00182       
00183       
00184       
00185       m_meta_info = new MetaInfo(m_name);
00186     }
00187   } else {
00188     
00189     
00190     m_meta_info = new MetaInfo(m_name, LogUtils::timestamp(), m_signature);
00191   }
00192 
00193   int flags, perms;
00194 
00195   if (m_file_format == LOG_FILE_PIPE) {
00196     if (mkfifo(m_name, S_IRUSR | S_IWUSR) < 0) {
00197       if (errno != EEXIST) {
00198         Error("Could not create named pipe %s for logging: %s", m_name, strerror(errno));
00199         return LOG_FILE_COULD_NOT_CREATE_PIPE;
00200       }
00201     } else {
00202       Debug("log-file", "Created named pipe %s for logging", m_name);
00203     }
00204     flags = O_WRONLY | O_NDELAY;
00205     perms = 0;
00206   } else {
00207     flags = O_WRONLY | O_APPEND | O_CREAT;
00208     perms = Log::config->logfile_perm;
00209   }
00210 
00211   Debug("log-file", "attempting to open %s", m_name);
00212   m_fd =::open(m_name, flags, perms);
00213 
00214   if (m_fd < 0) {
00215     
00216     
00217     
00218     if (errno != ENXIO) {
00219       Error("Error opening log file %s: %s", m_name, strerror(errno));
00220       return LOG_FILE_COULD_NOT_OPEN_FILE;
00221     }
00222     Debug("log-file", "no readers for pipe %s", m_name);
00223     return LOG_FILE_NO_PIPE_READERS;
00224   }
00225 
00226   int e = do_filesystem_checks();
00227   if (e != 0) {
00228     m_fd = -1;                  
00229     return LOG_FILE_FILESYSTEM_CHECKS_FAILED;
00230   }
00231 
00232   
00233   m_bytes_written = lseek( m_fd, 0, SEEK_CUR );
00234 
00235   Debug("log-file", "LogFile %s is now open (fd=%d)", m_name, m_fd);
00236 
00237   
00238   
00239   
00240   
00241   
00242   
00243   if (!file_exists) {
00244     if (m_file_format != LOG_FILE_BINARY && m_header != NULL) {
00245       Debug("log-file", "writing header to LogFile %s", m_name);
00246       writeln(m_header, strlen(m_header), m_fd, m_name);
00247     }
00248   }
00249 
00250   RecIncrRawStat(log_rsb, this_thread()->mutex->thread_holding,
00251                  log_stat_log_files_open_stat, 1);
00252 
00253   return LOG_FILE_NO_ERROR;
00254 }
00255 
00256 
00257 
00258 
00259 
00260 
00261 
00262 void
00263 LogFile::close_file()
00264 {
00265   if (is_open()) {
00266     ::close(m_fd);
00267     Debug("log-file", "LogFile %s (fd=%d) is closed", m_name, m_fd);
00268     m_fd = -1;
00269 
00270     RecIncrRawStat(log_rsb, this_thread()->mutex->thread_holding,
00271                    log_stat_log_files_open_stat, -1);
00272   }
00273 }
00274 
00275 
00276 
00277 
00278 
00279 
00280 
00281 
00282 bool LogFile::rolled_logfile(char *path)
00283 {
00284   const int
00285     target_len = (int) strlen(LOGFILE_ROLLED_EXTENSION);
00286   int
00287     len = (int) strlen(path);
00288   if (len > target_len) {
00289     char *
00290       str = &path[len - target_len];
00291     if (!strcmp(str, LOGFILE_ROLLED_EXTENSION)) {
00292       return true;
00293     }
00294   }
00295   return false;
00296 }
00297 
00298 
00299 
00300 
00301 
00302 
00303 
00304 
00305 
00306 
00307 
00308 
00309 
00310 
00311 
00312 
00313 
00314 
00315 
00316 
00317 
00318 
00319 
00320 
00321 
00322 
00323 
00324 int
00325 LogFile::roll(long interval_start, long interval_end)
00326 {
00327   
00328   
00329   
00330   if (m_name == NULL || !LogFile::exists(m_name)) {
00331     Debug("log-file", "Roll not needed for %s; file doesn't exist", (m_name) ? m_name : "no_name");
00332     return 0;
00333   }
00334   
00335   
00336   if (!m_meta_info) {
00337     m_meta_info = new MetaInfo(m_name);
00338   }
00339   
00340   
00341   
00342   
00343   
00344   
00345   
00346   
00347   
00348   
00349   char roll_name[MAXPATHLEN];
00350   char start_time_ext[64];
00351   char end_time_ext[64];
00352   time_t start, end;
00353 
00354   
00355   
00356   
00357   close_file();
00358 
00359   
00360   
00361   
00362   
00363   start = 0L;
00364   end = (interval_end >= m_end_time) ? interval_end : m_end_time;
00365 
00366   if (m_meta_info->data_from_metafile()) {
00367     
00368     
00369     
00370     
00371     
00372     
00373     
00374     m_meta_info->get_creation_time(&start);
00375   } else {
00376     
00377     
00378     
00379     
00380     
00381     
00382     
00383     
00384     
00385     
00386     
00387     
00388     start = (m_start_time < interval_start) ? m_start_time : interval_start;
00389   }
00390 
00391   
00392   
00393   
00394   
00395   LogUtils::timestamp_to_str((long) start, start_time_ext, 64);
00396   LogUtils::timestamp_to_str((long) end, end_time_ext, 64);
00397   snprintf(roll_name, MAXPATHLEN, "%s%s%s.%s-%s%s",
00398                m_name,
00399                LOGFILE_SEPARATOR_STRING,
00400                Machine::instance()->hostname, start_time_ext, end_time_ext, LOGFILE_ROLLED_EXTENSION);
00401 
00402   
00403   
00404   
00405   
00406   
00407 
00408   int version = 1;
00409   while (LogFile::exists(roll_name)) {
00410     Note("The rolled file %s already exists; adding version "
00411          "tag %d to avoid clobbering the existing file.", roll_name, version);
00412     snprintf(roll_name, MAXPATHLEN, "%s%s%s.%s-%s.%d%s",
00413                  m_name,
00414                  LOGFILE_SEPARATOR_STRING,
00415                  Machine::instance()->hostname, start_time_ext, end_time_ext, version, LOGFILE_ROLLED_EXTENSION);
00416     version++;
00417   }
00418 
00419   
00420   
00421   
00422 
00423   if (::rename(m_name, roll_name) < 0) {
00424     Warning("Traffic Server could not rename logfile %s to %s, error %d: "
00425             "%s.", m_name, roll_name, errno, strerror(errno));
00426     return 0;
00427   }
00428   
00429   
00430   m_start_time = 0;
00431   m_bytes_written = 0;
00432 
00433   Debug("log-file", "The logfile %s was rolled to %s.", m_name, roll_name);
00434 
00435   return 1;
00436 }
00437 
00438 
00439 
00440 
00441 
00442 
00443 
00444 int
00445 LogFile::preproc_and_try_delete(LogBuffer * lb)
00446 {
00447   int ret = -1;
00448   LogBufferHeader *buffer_header;
00449 
00450   if (lb == NULL) {
00451     Note("Cannot write LogBuffer to LogFile %s; LogBuffer is NULL", m_name);
00452     return -1;
00453   }
00454 
00455   ink_atomic_increment(&lb->m_references, 1);
00456 
00457   if ((buffer_header = lb->header()) == NULL) {
00458     Note("Cannot write LogBuffer to LogFile %s; LogBufferHeader is NULL",
00459         m_name);
00460     goto done;
00461   }
00462   if (buffer_header->entry_count == 0) {
00463     
00464     Note("LogBuffer with 0 entries for LogFile %s, nothing to write", m_name);
00465     goto done;
00466   }
00467 
00468   
00469   
00470   
00471   
00472   
00473   if (!m_start_time)
00474     m_start_time = buffer_header->low_timestamp;
00475   m_end_time = buffer_header->high_timestamp;
00476 
00477   if (m_file_format == LOG_FILE_BINARY) {
00478     
00479     
00480     
00481     
00482     
00483     
00484     
00485     
00486     LogFlushData *flush_data = new LogFlushData(this, lb);
00487 
00488     ProxyMutex *mutex = this_thread()->mutex;
00489 
00490     RecIncrRawStat(log_rsb, mutex->thread_holding, log_stat_num_flush_to_disk_stat,
00491                    lb->header()->entry_count);
00492 
00493     RecIncrRawStat(log_rsb, mutex->thread_holding, log_stat_bytes_flush_to_disk_stat,
00494                    lb->header()->byte_count);
00495 
00496     ink_atomiclist_push(Log::flush_data_list, flush_data);
00497 
00498     Log::flush_notify->signal();
00499 
00500     
00501     
00502     
00503     return 0;
00504   }
00505   else if (m_file_format == LOG_FILE_ASCII || m_file_format == LOG_FILE_PIPE) {
00506     write_ascii_logbuffer3(buffer_header);
00507     ret = 0;
00508   }
00509   else {
00510     Note("Cannot write LogBuffer to LogFile %s; invalid file format: %d",
00511          m_name, m_file_format);
00512   }
00513 
00514 done:
00515   LogBuffer::destroy(lb);
00516   return ret;
00517 }
00518 
00519 
00520 
00521 
00522 
00523 
00524 
00525 
00526 
00527 
00528 
00529 int
00530 LogFile::write_ascii_logbuffer(LogBufferHeader * buffer_header, int fd, const char *path, const char *alt_format)
00531 {
00532   ink_assert(buffer_header != NULL);
00533   ink_assert(fd >= 0);
00534 
00535   char fmt_buf[LOG_MAX_FORMATTED_BUFFER];
00536   char fmt_line[LOG_MAX_FORMATTED_LINE];
00537   LogBufferIterator iter(buffer_header);
00538   LogEntryHeader *entry_header;
00539   int fmt_buf_bytes = 0;
00540   int fmt_line_bytes = 0;
00541   int bytes = 0;
00542 
00543   LogFormatType format_type;
00544   char *fieldlist_str;
00545   char *printf_str;
00546 
00547   switch (buffer_header->version) {
00548   case LOG_SEGMENT_VERSION:
00549     format_type = (LogFormatType) buffer_header->format_type;
00550 
00551     fieldlist_str = buffer_header->fmt_fieldlist();
00552     printf_str = buffer_header->fmt_printf();
00553     break;
00554 
00555   default:
00556     Note("Invalid LogBuffer version %d in write_ascii_logbuffer; "
00557          "current version is %d", buffer_header->version, LOG_SEGMENT_VERSION);
00558     return 0;
00559   }
00560 
00561   while ((entry_header = iter.next())) {
00562     fmt_line_bytes = LogBuffer::to_ascii(entry_header, format_type,
00563                                          &fmt_line[0], LOG_MAX_FORMATTED_LINE,
00564                                          fieldlist_str, printf_str, buffer_header->version, alt_format);
00565     ink_assert(fmt_line_bytes > 0);
00566 
00567     if (fmt_line_bytes > 0) {
00568       if ((fmt_line_bytes + fmt_buf_bytes) >= LOG_MAX_FORMATTED_BUFFER) {
00569         if (!Log::config->logging_space_exhausted) {
00570           bytes += writeln(fmt_buf, fmt_buf_bytes, fd, path);
00571         }
00572         fmt_buf_bytes = 0;
00573       }
00574       ink_assert(fmt_buf_bytes < LOG_MAX_FORMATTED_BUFFER);
00575       ink_assert(fmt_line_bytes < LOG_MAX_FORMATTED_BUFFER - fmt_buf_bytes);
00576       memcpy(&fmt_buf[fmt_buf_bytes], fmt_line, fmt_line_bytes);
00577       fmt_buf_bytes += fmt_line_bytes;
00578       ink_assert(fmt_buf_bytes < LOG_MAX_FORMATTED_BUFFER);
00579       fmt_buf[fmt_buf_bytes] = '\n';    
00580       fmt_buf_bytes += 1;
00581     }
00582   }
00583   if (fmt_buf_bytes > 0) {
00584     if (!Log::config->logging_space_exhausted) {
00585       ink_assert(fmt_buf_bytes < LOG_MAX_FORMATTED_BUFFER);
00586       bytes += writeln(fmt_buf, fmt_buf_bytes, fd, path);
00587     }
00588   }
00589 
00590   return bytes;
00591 }
00592 
00593 int
00594 LogFile::write_ascii_logbuffer3(LogBufferHeader * buffer_header, const char *alt_format)
00595 {
00596   Debug("log-file", "entering LogFile::write_ascii_logbuffer3 for %s " "(this=%p)", m_name, this);
00597   ink_assert(buffer_header != NULL);
00598 
00599   ProxyMutex *mutex = this_thread()->mutex;
00600   LogBufferIterator iter(buffer_header);
00601   LogEntryHeader *entry_header;
00602   int fmt_entry_count = 0;
00603   int fmt_buf_bytes = 0;
00604   int total_bytes = 0;
00605 
00606   LogFormatType format_type;
00607   char *fieldlist_str;
00608   char *printf_str;
00609   char *ascii_buffer;
00610 
00611   switch (buffer_header->version) {
00612   case LOG_SEGMENT_VERSION:
00613     format_type = (LogFormatType) buffer_header->format_type;
00614     fieldlist_str = buffer_header->fmt_fieldlist();
00615     printf_str = buffer_header->fmt_printf();
00616     break;
00617 
00618   default:
00619     Note("Invalid LogBuffer version %d in write_ascii_logbuffer; "
00620          "current version is %d", buffer_header->version, LOG_SEGMENT_VERSION);
00621     return 0;
00622   }
00623 
00624   while ((entry_header = iter.next())) {
00625     fmt_entry_count = 0;
00626     fmt_buf_bytes = 0;
00627 
00628     if (m_file_format == LOG_FILE_PIPE)
00629       ascii_buffer = (char *)malloc(m_max_line_size);
00630     else
00631       ascii_buffer = (char *)malloc(m_ascii_buffer_size);
00632 
00633     
00634     
00635     do {
00636       if (entry_header->entry_len >= m_max_line_size) {
00637         Warning("Log is too long(%" PRIu32 "), it would be truncated. max_len:%zu",
00638                 entry_header->entry_len, m_max_line_size);
00639       }
00640 
00641       int bytes = LogBuffer::to_ascii(entry_header, format_type,
00642                                       &ascii_buffer[fmt_buf_bytes],
00643                                       m_max_line_size - 1,
00644                                       fieldlist_str, printf_str,
00645                                       buffer_header->version,
00646                                       alt_format);
00647 
00648       if (bytes > 0) {
00649         fmt_buf_bytes += bytes;
00650         ascii_buffer[fmt_buf_bytes] = '\n';
00651         ++fmt_buf_bytes;
00652         ++fmt_entry_count;
00653       } else {
00654         Error("Failed to convert LogBuffer to ascii, have dropped (%" PRIu32 ") bytes.",
00655               entry_header->entry_len);
00656 
00657         RecIncrRawStat(log_rsb, mutex->thread_holding,
00658                        log_stat_num_lost_before_flush_to_disk_stat,
00659                        fmt_entry_count);
00660 
00661         RecIncrRawStat(log_rsb, mutex->thread_holding,
00662                        log_stat_bytes_lost_before_flush_to_disk_stat,
00663                        fmt_buf_bytes);
00664       }
00665       
00666       
00667       
00668       
00669       if (m_file_format == LOG_FILE_PIPE)
00670         break;
00671 
00672       if (m_ascii_buffer_size - fmt_buf_bytes < m_max_line_size)
00673         break;
00674     } while ((entry_header = iter.next()));
00675 
00676     
00677     
00678     LogFlushData *flush_data = new LogFlushData(this, ascii_buffer, fmt_buf_bytes);
00679 
00680     RecIncrRawStat(log_rsb, mutex->thread_holding, log_stat_num_flush_to_disk_stat,
00681                    fmt_entry_count);
00682 
00683     RecIncrRawStat(log_rsb, mutex->thread_holding, log_stat_bytes_flush_to_disk_stat,
00684                    fmt_buf_bytes);
00685 
00686     ink_atomiclist_push(Log::flush_data_list, flush_data);
00687 
00688     Log::flush_notify->signal();
00689 
00690     total_bytes += fmt_buf_bytes;
00691   }
00692 
00693   return total_bytes;
00694 }
00695 
00696 
00697 
00698 
00699 
00700 
00701 
00702 
00703 int
00704 LogFile::writeln(char *data, int len, int fd, const char *path)
00705 {
00706   int total_bytes = 0;
00707 
00708   if (len > 0 && data && fd >= 0) {
00709     struct iovec wvec[2];
00710     memset(&wvec, 0, sizeof(iovec));
00711     memset(&wvec[1], 0, sizeof(iovec));
00712     int bytes_this_write, vcnt = 1;
00713 
00714 #if defined(solaris)
00715     wvec[0].iov_base = (caddr_t) data;
00716 #else
00717     wvec[0].iov_base = (void *) data;
00718 #endif
00719     wvec[0].iov_len = (size_t) len;
00720 
00721     if (data[len - 1] != '\n') {
00722 #if defined(solaris)
00723       wvec[1].iov_base = (caddr_t) "\n";
00724 #else
00725       wvec[1].iov_base = (void *) "\n";
00726 #endif
00727       wvec[1].iov_len = (size_t) 1;
00728       vcnt++;
00729     }
00730 
00731     if ((bytes_this_write = (int)::writev(fd, (const struct iovec *) wvec, vcnt)) < 0) {
00732       Warning("An error was encountered in writing to %s: %s.", ((path) ? path : "logfile"), strerror(errno));
00733     } else
00734       total_bytes = bytes_this_write;
00735   }
00736   return total_bytes;
00737 }
00738 
00739 
00740 
00741 
00742 
00743 
00744 
00745 
00746 
00747 
00748 
00749 void
00750 LogFile::check_fd()
00751 {
00752   static bool failure_last_call = false;
00753   static unsigned stat_check_count = 1;
00754 
00755   if ((stat_check_count % Log::config->file_stat_frequency) == 0) {
00756     
00757     
00758     
00759     
00760     
00761     
00762     if (m_name && !LogFile::exists(m_name)) {
00763       close_file();
00764     }
00765     stat_check_count = 0;
00766   }
00767   stat_check_count++;
00768 
00769   int err = open_file();
00770   
00771   if (err != LOG_FILE_NO_ERROR && err != LOG_FILE_NO_PIPE_READERS) {
00772     if (!failure_last_call) {
00773       LogUtils::manager_alarm(LogUtils::LOG_ALARM_ERROR, "Traffic Server could not open logfile %s.", m_name);
00774       Warning("Traffic Server could not open logfile %s: %s.", m_name, strerror(errno));
00775     }
00776     failure_last_call = true;
00777     return;
00778   }
00779 
00780   failure_last_call = false;
00781 }
00782 
00783 void
00784 LogFile::display(FILE * fd)
00785 {
00786   fprintf(fd, "Logfile: %s, %s\n", get_name(), (is_open())? "file is open" : "file is not open");
00787 }
00788 
00789 
00790 
00791 
00792 
00793 
00794 
00795 
00796 
00797 
00798 
00799 
00800 void
00801 MetaInfo::_build_name(const char *filename)
00802 {
00803   int i = -1, l = 0;
00804   char c;
00805   while (c = filename[l], c != 0) {
00806     if (c == '/') {
00807       i = l;
00808     }
00809     ++l;
00810   }
00811 
00812   
00813   
00814   _filename = (char *)ats_malloc(l + 7);
00815 
00816   if (i < 0) {
00817     ink_string_concatenate_strings(_filename, ".", filename, ".meta", NULL);
00818   } else {
00819     memcpy(_filename, filename, i + 1);
00820     ink_string_concatenate_strings(&_filename[i + 1], ".", &filename[i + 1]
00821                                    , ".meta", NULL);
00822   }
00823 }
00824 
00825 void
00826 MetaInfo::_read_from_file()
00827 {
00828   _flags |= DATA_FROM_METAFILE;
00829   int fd = open(_filename, O_RDONLY);
00830   if (fd < 0) {
00831     Warning("Could not open metafile %s for reading: %s", _filename, strerror(errno));
00832   } else {
00833     _flags |= FILE_OPEN_SUCCESSFUL;
00834     SimpleTokenizer tok('=', SimpleTokenizer::OVERWRITE_INPUT_STRING);
00835     int line_number = 1;
00836     while (ink_file_fd_readline(fd, BUF_SIZE, _buffer) > 0) {
00837       tok.setString(_buffer);
00838       char *t = tok.getNext();
00839       if (t) {
00840         if (strcmp(t, "creation_time") == 0) {
00841           t = tok.getNext();
00842           if (t) {
00843             _creation_time = (time_t) ink_atoi64(t);
00844             _flags |= VALID_CREATION_TIME;
00845           }
00846         } else if (strcmp(t, "object_signature") == 0) {
00847           t = tok.getNext();
00848           if (t) {
00849             _log_object_signature = ink_atoi64(t);
00850             _flags |= VALID_SIGNATURE;
00851             Debug("log-meta", "MetaInfo::_read_from_file\n"
00852                   "\tfilename = %s\n"
00853                   "\tsignature string = %s\n" "\tsignature value = %" PRIu64 "", _filename, t, _log_object_signature);
00854           }
00855         } else if (line_number == 1) {
00856           ink_release_assert(!"no panda support");
00857         }
00858       }
00859       ++line_number;
00860     }
00861     close(fd);
00862   }
00863 }
00864 
00865 void
00866 MetaInfo::_write_to_file()
00867 {
00868   int fd = open(_filename, O_WRONLY | O_CREAT | O_TRUNC,
00869                 Log::config->logfile_perm);
00870 
00871   if (fd <= 0) {
00872     Warning("Could not open metafile %s for writing: %s", _filename, strerror(errno));
00873   } else {
00874     int n;
00875     if (_flags & VALID_CREATION_TIME) {
00876       n = snprintf(_buffer, BUF_SIZE, "creation_time = %lu\n", (unsigned long) _creation_time);
00877       
00878       ink_release_assert(n <= BUF_SIZE);
00879       if (write(fd, _buffer, n) == -1) {
00880         Warning("Could not write creation_time");
00881       }
00882     }
00883     if (_flags & VALID_SIGNATURE) {
00884       n = snprintf(_buffer, BUF_SIZE, "object_signature = %" PRIu64 "\n", _log_object_signature);
00885       
00886       ink_release_assert(n <= BUF_SIZE);
00887       if (write(fd, _buffer, n) == -1) {
00888         Warning("Could not write object_signaure");
00889       }
00890       Debug("log-meta", "MetaInfo::_write_to_file\n"
00891             "\tfilename = %s\n"
00892             "\tsignature value = %" PRIu64 "\n" "\tsignature string = %s", _filename, _log_object_signature, _buffer);
00893     }
00894   }
00895   close(fd);
00896 }