fix off by 1 error
[rrdtool.git] / src / rrd_restore.c
index 6a28e34..39148e8 100644 (file)
@@ -1,18 +1,23 @@
 /*****************************************************************************
- * RRDtool 1.3.2  Copyright by Tobi Oetiker, 1997-2009                    
+ * RRDtool 1.4.3  Copyright by Tobi Oetiker, 1997-2010                    
  *****************************************************************************
  * rrd_restore.c  Contains logic to parse XML input and create an RRD file
- *                initial libxml2 version of rrd_restore (c) by Florian octo Forster
+ * This file:
+ * Copyright (C) 2008  Florian octo Forster  (original libxml2 code)
+ * Copyright (C) 2008,2009 Tobias Oetiker
  *****************************************************************************
  * $Id$
  *************************************************************************** */
 
+#include "rrd_tool.h"
+#include "rrd_rpncalc.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <libxml/parser.h>
 #include <libxml/xmlreader.h>
-
+#include <locale.h>
 
 #ifndef WIN32
 #      include <unistd.h>     /* for off_t */
@@ -28,8 +33,6 @@
 # define close _close
 #endif
 
-#include "rrd_tool.h"
-#include "rrd_rpncalc.h"
 
 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof ((a)[0]))
 
@@ -116,7 +119,19 @@ static int expect_element_end (
     char *exp_name)
 {
     xmlChar *name;
-    name = get_xml_element(reader);
+    /* maybe we are already on the end element ... lets see */
+    if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT){
+         xmlChar *temp;
+         xmlChar *temp2;            
+         temp = xmlTextReaderName(reader);
+         temp2 = (xmlChar*)sprintf_alloc("/%s", temp);
+         name = xmlStrdup(temp2);
+         xmlFree(temp);
+         free(temp2);            
+    } else {     
+         name = get_xml_element(reader);
+    }
+
     if (name == NULL)
         return -1;    
     if (xmlStrcasecmp(name+1,(xmlChar *)exp_name) != 0 || name[0] != '/'){
@@ -144,14 +159,24 @@ static xmlChar* get_xml_text (
         if (type == XML_READER_TYPE_ELEMENT){
             xmlChar *name;
             name = xmlTextReaderName(reader);
-            rrd_set_error("line %d: expected a value but found an <%s> element",
+            rrd_set_error("line %d: expected a value but found a <%s> element",
                           xmlTextReaderGetParserLineNumber(reader),
                           name);
             xmlFree(name);            
             return NULL;            
         }
+
+        /* trying to read text from <a></a> we end up here
+           lets return an empty string insead. This is a tad optimistic
+           since we do not check if it is actually </a> and not </b>
+           we got, but first we do not know if we expect </a> and second
+           we the whole implementation is on the optimistic side. */
+        if (type == XML_READER_TYPE_END_ELEMENT){
+            return  xmlStrdup(BAD_CAST "");
+        }        
+
         /* skip all other non-text */
-        if (xmlTextReaderNodeType(reader) != XML_READER_TYPE_TEXT)
+        if (type != XML_READER_TYPE_TEXT)
             continue;
         
         text = xmlTextReaderValue(reader);
@@ -194,17 +219,29 @@ static int get_xml_string(
 }
 
  
-static int get_xml_long(
+static int get_xml_time_t(
     xmlTextReaderPtr reader,
-    long *value)
+    time_t *value)
 {    
     xmlChar *text;
-    long temp;    
+    time_t temp;    
     if ((text = get_xml_text(reader)) != NULL){
         errno = 0;        
+#ifdef TIME_T_IS_32BIT
         temp = strtol((char *)text,NULL, 0);
+#else
+#ifdef TIME_T_IS_64BIT
+        temp = strtoll((char *)text,NULL, 0);        
+#else
+        if (sizeof(time_t) == 4){
+            temp = strtol((char *)text,NULL, 0);
+        } else {
+            temp = strtoll((char *)text,NULL, 0);
+        }
+#endif
+#endif    
         if (errno>0){
-            rrd_set_error("ling %d: get_xml_long from '%s' %s",
+            rrd_set_error("ling %d: get_xml_time_t from '%s' %s",
                           xmlTextReaderGetParserLineNumber(reader),
                           text,rrd_strerror(errno));
             xmlFree(text);            
@@ -215,15 +252,15 @@ static int get_xml_long(
         return 0;
     }
     return -1;
-} /* get_xml_long */
+} /* get_xml_time_t */
 
 static int get_xml_ulong(
     xmlTextReaderPtr reader,
-    ulong *value)
+    unsigned long *value)
 {
     
     xmlChar *text;
-    ulong temp;    
+    unsigned long temp;    
     if ((text = get_xml_text(reader)) != NULL){
         errno = 0;        
         temp = strtoul((char *)text,NULL, 0);        
@@ -246,34 +283,35 @@ static int get_xml_double(
     double *value)
 {
     
-    char *text;
+    xmlChar *text;
     double temp;    
-    if ((text = (char *)get_xml_text(reader))!= NULL){
-        if (strcasestr(text,"nan")){
+    if ((text = get_xml_text(reader))!= NULL){
+        if (xmlStrcasestr(text,(xmlChar *)"nan")){
             *value = DNAN;
             xmlFree(text);
             return 0;            
         }
-        else if (strcasestr(text,"-inf")){
+        else if (xmlStrcasestr(text,(xmlChar *)"-inf")){
             *value = -DINF;
             xmlFree(text);
             return 0;            
         }
-        else if (strcasestr(text,"+inf")
-                 || strcasestr(text,"inf")){
+        else if (xmlStrcasestr(text,(xmlChar *)"+inf")
+                 || xmlStrcasestr(text,(xmlChar *)"inf")){
             *value = DINF;
             xmlFree(text);
             return 0;            
         }        
         errno = 0;
         temp = strtod((char *)text,NULL);
-        xmlFree(text);        
         if (errno>0){
             rrd_set_error("ling %d: get_xml_double from '%s' %s",
                           xmlTextReaderGetParserLineNumber(reader),
                           text,rrd_strerror(errno));
+            xmlFree(text);        
             return -1;
         }
+        xmlFree(text);        
         *value = temp;
         return 0;
     }
@@ -750,7 +788,7 @@ static int parse_tag_rra(
 
     /* All space successfully allocated, increment number of RRAs. */
     rrd->stat_head->rra_cnt++;
-
+    
     status = 0;
     while ((element = get_xml_element(reader)) != NULL){
         if (xmlStrcasecmp(element, (const xmlChar *) "cf") == 0)
@@ -789,7 +827,7 @@ static int parse_tag_rra(
                 return status;
         }
         else if (xmlStrcasecmp(element,(const xmlChar *) "/rra") == 0){
-            xmlFree(element);            
+            xmlFree(element);
             return status;
         }  /* }}} */        
        else {
@@ -986,9 +1024,9 @@ static int parse_tag_rrd(
         else if (xmlStrcasecmp(element, (const xmlChar *) "step") == 0)
             status = get_xml_ulong(reader,
                                         &rrd->stat_head->pdp_step);
-        else if (xmlStrcasecmp(element, (const xmlChar *) "lastupdate") == 0)
-            status = get_xml_long(reader,
-                                        &rrd->live_head->last_up);
+        else if (xmlStrcasecmp(element, (const xmlChar *) "lastupdate") == 0) {
+                status = get_xml_time_t(reader, &rrd->live_head->last_up);
+        }
         else if (xmlStrcasecmp(element, (const xmlChar *) "ds") == 0){            
             xmlFree(element);
             status = parse_tag_ds(reader, rrd);
@@ -1142,15 +1180,16 @@ static int write_file(
         unsigned long num_rows = rrd->rra_def[i].row_cnt;
         unsigned long cur_row = rrd->rra_ptr[i].cur_row;
         unsigned long ds_cnt = rrd->stat_head->ds_cnt;
+        if (num_rows > 0){
+            fwrite(rrd->rrd_value +
+                (rra_offset + num_rows - 1 - cur_row) * ds_cnt,
+                sizeof(rrd_value_t), (cur_row + 1) * ds_cnt, fh);
 
-        fwrite(rrd->rrd_value +
-               (rra_offset + num_rows - 1 - cur_row) * ds_cnt,
-               sizeof(rrd_value_t), (cur_row + 1) * ds_cnt, fh);
+            fwrite(rrd->rrd_value + rra_offset * ds_cnt,
+                sizeof(rrd_value_t), (num_rows - 1 - cur_row) * ds_cnt, fh);
 
-        fwrite(rrd->rrd_value + rra_offset * ds_cnt,
-               sizeof(rrd_value_t), (num_rows - 1 - cur_row) * ds_cnt, fh);
-
-        rra_offset += num_rows;
+            rra_offset += num_rows;
+        }
     }
 
     /* lets see if we had an error */
@@ -1169,7 +1208,7 @@ int rrd_restore(
     char **argv)
 {
     rrd_t    *rrd;
-
+    char     *old_locale;
     /* init rrd clean */
     optind = 0;
     opterr = 0;         /* initialize getopt */
@@ -1211,7 +1250,12 @@ int rrd_restore(
         return (-1);
     }
 
+    old_locale = setlocale(LC_NUMERIC, "C");
+
     rrd = parse_file(argv[optind]);
+
+    setlocale(LC_NUMERIC, old_locale);
+
     if (rrd == NULL)
         return (-1);