Imported Upstream version 3.3.3
[debian/amanda] / common-src / tapelist.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1998 University of Maryland at College Park
4  * Copyright (c) 2007-2012 Zmanda, Inc.  All Rights Reserved.
5  * All Rights Reserved.
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and its
8  * documentation for any purpose is hereby granted without fee, provided that
9  * the above copyright notice appear in all copies and that both that
10  * copyright notice and this permission notice appear in supporting
11  * documentation, and that the name of U.M. not be used in advertising or
12  * publicity pertaining to distribution of the software without specific,
13  * written prior permission.  U.M. makes no representations about the
14  * suitability of this software for any purpose.  It is provided "as is"
15  * without express or implied warranty.
16  *
17  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23  *
24  * Authors: the Amanda Development Team.  Its members are listed in a
25  * file named AUTHORS, in the root directory of this distribution.
26  */
27 /*
28  * $Id: tapelist.c,v 1.8 2006/06/12 15:34:48 martinea Exp $
29  *
30  * Support code for amidxtaped and amindexd.
31  */
32
33 #include "amanda.h"
34 #include "tapelist.h"
35
36 /*
37  * Count the number of entries in this tapelist
38  */
39 int
40 num_entries(
41     tapelist_t *        tapelist)
42 {
43     tapelist_t *cur_tape;
44     int count = 0;
45
46     for(cur_tape = tapelist ; cur_tape ; cur_tape = cur_tape->next)
47         count++;
48
49     dbprintf("num_entries(tapelist=%p)=%d\n", tapelist, count);
50     return(count);
51 }
52
53 void
54 dump_tapelist(
55     tapelist_t *tapelist)
56 {
57     tapelist_t *cur_tape;
58     int count = 0;
59     int file;
60
61     dbprintf("dump_tapelist(%p):\n", tapelist);
62     for(cur_tape = tapelist ; cur_tape != NULL ; cur_tape = cur_tape->next) {
63         dbprintf("  %p->next     = %p\n", cur_tape, cur_tape->next);
64         dbprintf("  %p->label    = %s\n", cur_tape, cur_tape->label);
65         dbprintf("  %p->isafile  = %d\n", cur_tape, cur_tape->isafile);
66         dbprintf("  %p->numfiles = %d\n", cur_tape, cur_tape->numfiles);
67         for (file=0; file < cur_tape->numfiles; file++) {
68             dbprintf("  %p->files[%d] = %lld, %p->partnum[%d] = %lld\n",
69                      cur_tape, file, (long long)cur_tape->files[file],
70                      cur_tape, file, (long long)cur_tape->partnum[file]);
71         }
72         count++;
73     }
74     dbprintf("  %p count     = %d\n", tapelist, count);
75 }
76
77 /*
78  * Add a tape entry with the given label to the given tapelist, creating a new
79  * tapelist if handed a NULL one.  Squashes duplicates.
80  */
81 tapelist_t *
82 append_to_tapelist(
83     tapelist_t *tapelist,
84     char *      label,
85     off_t       file,
86     int         partnum,
87     int         isafile)
88 {
89     tapelist_t *new_tape, *cur_tape;
90     int c;
91
92     dbprintf("append_to_tapelist(tapelist=%p, label='%s', file=%lld, partnum=%d,  isafile=%d)\n",
93                 tapelist, label, (long long)file, partnum, isafile);
94
95     /* see if we have this tape already, and if so just add to its file list */
96     for(cur_tape = tapelist; cur_tape; cur_tape = cur_tape->next) {
97         if(strcmp(label, cur_tape->label) == 0) {
98             int d_idx = 0;
99             off_t *newfiles;
100             int   *newpartnum;
101
102             if(file >= (off_t)0) {
103                 newfiles = alloc(SIZEOF(*newfiles) *
104                                  (cur_tape->numfiles + 1));
105                 newpartnum = alloc(SIZEOF(*newpartnum) *
106                                  (cur_tape->numfiles + 1));
107                 for(c = 0; c < cur_tape->numfiles ; c++) {
108                     if(cur_tape->files[c] > file && c == d_idx) {
109                         newfiles[d_idx] = file;
110                         newpartnum[d_idx] = partnum;
111                         d_idx++;
112                     }
113                     newfiles[d_idx] = cur_tape->files[c];
114                     newpartnum[d_idx] = cur_tape->partnum[c];
115                     d_idx++;
116                 }
117                 if(c == d_idx) {
118                     newfiles[d_idx] = file;
119                     newpartnum[d_idx] = partnum;
120                 }
121                 cur_tape->numfiles++;
122                 amfree(cur_tape->files);
123                 amfree(cur_tape->partnum);
124                 cur_tape->files = newfiles;
125                 cur_tape->partnum = newpartnum;
126             }
127             return(tapelist);
128         }
129     }
130
131     new_tape = alloc(SIZEOF(tapelist_t));
132     memset(new_tape, 0, SIZEOF(tapelist_t));
133     new_tape->label = stralloc(label);
134     if(file >= (off_t)0){
135         new_tape->files = alloc(SIZEOF(*(new_tape->files)));
136         new_tape->files[0] = file;
137         new_tape->partnum = alloc(SIZEOF(*(new_tape->partnum)));
138         new_tape->partnum[0] = partnum;
139         new_tape->numfiles = 1;
140         new_tape->isafile = isafile;
141     }
142
143     /* first instance of anything, start our tapelist with it */
144     if(!tapelist){
145         tapelist = new_tape;
146     } else {
147         /* new tape, tack it onto the end of the list */
148         cur_tape = tapelist;
149         while (cur_tape->next != NULL)
150             cur_tape = cur_tape->next;
151         cur_tape->next = new_tape;
152     }
153
154     return(tapelist);
155 }
156
157 /*
158  * Backslash-escape all of the commas (and backslashes) in a label string.
159  */
160 char *
161 escape_label(
162     char *      label)
163 {
164     char *cooked_str, *temp_str;
165     int s_idx = 0, d_idx = 0;
166
167     if(!label) return(NULL);
168
169     temp_str = alloc(strlen(label) * 2);
170
171     do{
172         if(label[s_idx] == ',' || label[s_idx] == '\\' ||
173                 label[s_idx] == ';' || label[s_idx] == ':'){
174             temp_str[d_idx] = '\\';
175             d_idx++;
176         }
177         temp_str[d_idx] = label[s_idx];
178         s_idx++;
179         d_idx++;
180     } while(label[s_idx] != '\0');
181     temp_str[d_idx] = '\0';
182
183     cooked_str = stralloc(temp_str);
184     amfree(temp_str);
185     
186     return(cooked_str);
187 }
188
189 /*
190  * Strip out any escape characters (backslashes)
191  */
192 char *
193 unescape_label(
194     char *      label)
195 {
196     char *cooked_str, *temp_str;
197     int s_idx = 0, d_idx = 0, prev_esc = 0;
198     
199     if(!label) return(NULL);
200
201     temp_str = alloc(strlen(label));
202
203     do{
204         if(label[s_idx] == '\\' && !prev_esc){
205             s_idx++;
206             prev_esc = 1;
207             continue;
208         }
209         prev_esc = 0;
210         temp_str[d_idx] = label[s_idx];
211         s_idx++;
212         d_idx++;
213     } while(label[s_idx] != '\0');
214     temp_str[d_idx] = '\0';
215
216     cooked_str = stralloc(temp_str);
217     amfree(temp_str);
218     
219     return(cooked_str);
220 }
221
222 /*
223  * Convert a tapelist into a parseable string of tape labels and file numbers.
224  */
225 char *
226 marshal_tapelist(
227     tapelist_t *tapelist,
228     int         do_escape)
229 {
230     tapelist_t *cur_tape;
231     char *str = NULL;
232
233     for(cur_tape = tapelist; cur_tape; cur_tape = cur_tape->next){
234         char *esc_label;
235         char *files_str = NULL;
236         int c;
237
238         if(do_escape) esc_label = escape_label(cur_tape->label);
239         else esc_label = stralloc(cur_tape->label);
240
241         for(c = 0; c < cur_tape->numfiles ; c++){
242             char num_str[NUM_STR_SIZE];
243             g_snprintf(num_str, SIZEOF(num_str), "%lld",
244                         (long long)cur_tape->files[c]);
245             if (!files_str)
246                 files_str = stralloc(num_str);
247             else
248                 vstrextend(&files_str, ",", num_str, NULL);
249         }
250
251         if (!str)
252             str = vstralloc(esc_label, ":", files_str, NULL);
253         else
254             vstrextend(&str, ";", esc_label, ":", files_str, NULL);
255
256         amfree(esc_label);
257         amfree(files_str);
258     }
259
260     return(str);
261 }
262
263 /*
264  * Convert a previously str-ified and escaped list of tapes back into a
265  * tapelist structure.
266  */
267 tapelist_t *
268 unmarshal_tapelist_str(
269     char *      tapelist_str)
270 {
271     char *temp_label, *temp_filenum;
272     int l_idx, n_idx;
273     size_t input_length;
274     tapelist_t *tapelist = NULL;
275
276     if(!tapelist_str) return(NULL);
277
278     input_length = strlen(tapelist_str);
279
280     temp_label = alloc(input_length+1);
281     temp_filenum = alloc(input_length+1);
282
283     do{
284         /* first, read the label part */
285         memset(temp_label, '\0', input_length+1);
286         l_idx = 0;
287         while(*tapelist_str != ':' && *tapelist_str != '\0'){
288             if(*tapelist_str == '\\')
289                 tapelist_str++; /* skip escapes */
290             temp_label[l_idx] = *tapelist_str;
291             if(*tapelist_str == '\0')
292                 break; /* bad format, should kvetch */
293             tapelist_str++;
294             l_idx++;
295         }
296         if(*tapelist_str != '\0')
297             tapelist_str++;
298         tapelist = append_to_tapelist(tapelist, temp_label, (off_t)-1, -1, 0);
299
300         /* now read the list of file numbers */
301         while(*tapelist_str != ';' && *tapelist_str != '\0'){
302             off_t filenum;
303
304             memset(temp_filenum, '\0', input_length+1);
305             n_idx = 0;
306             while(*tapelist_str != ';' && *tapelist_str != ',' &&
307                     *tapelist_str != '\0'){
308                 temp_filenum[n_idx] = *tapelist_str; 
309                 tapelist_str++;
310                 n_idx++;
311             }
312             filenum = OFF_T_ATOI(temp_filenum);
313
314             tapelist = append_to_tapelist(tapelist, temp_label, filenum, -1, 0);
315             if(*tapelist_str != '\0' && *tapelist_str != ';')
316                 tapelist_str++;
317         }
318         if(*tapelist_str != '\0')
319             tapelist_str++;
320
321     } while(*tapelist_str != '\0');
322
323     amfree(temp_label);
324     amfree(temp_filenum);
325
326     return(tapelist);
327 }
328
329 /*
330  * Free up a list of tapes
331  */
332 void
333 free_tapelist(
334     tapelist_t *        tapelist)
335 {
336     tapelist_t *cur_tape;
337     tapelist_t *prev = NULL;
338
339     for(cur_tape = tapelist ; cur_tape ; cur_tape = cur_tape->next){
340         amfree(cur_tape->label);
341         amfree(cur_tape->files);
342         amfree(cur_tape->partnum);
343         amfree(prev);
344         prev = cur_tape;
345     }
346     amfree(prev);
347 }