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