Imported Upstream version 2.5.1
[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] = " OFF_T_FMT "\n",
68                      cur_tape, file, (OFF_T_FMT_TYPE)cur_tape->files[file]));
69         }
70         count++;
71     }
72     dbprintf(("  %p count     = %d\n", tapelist, count));
73 }
74
75 /*
76  * Add a tape entry with the given label to the given tapelist, creating a new
77  * tapelist if handed a NULL one.  Squashes duplicates.
78  */
79 tapelist_t *
80 append_to_tapelist(
81     tapelist_t *tapelist,
82     char *      label,
83     off_t       file,
84     int         isafile)
85 {
86     tapelist_t *new_tape, *cur_tape;
87     int c;
88
89     dbprintf(("append_to_tapelist(tapelist=%p, label='%s', , file="
90                 OFF_T_FMT ", isafile=%d)\n",
91                 tapelist, label, (OFF_T_FMT_TYPE)file, isafile));
92
93     /* see if we have this tape already, and if so just add to its file list */
94     for(cur_tape = tapelist; cur_tape; cur_tape = cur_tape->next) {
95         if(strcmp(label, cur_tape->label) == 0) {
96             int d_idx = 0;
97             off_t *newfiles;
98
99             if(file >= (off_t)0) {
100                 newfiles = alloc(SIZEOF(*newfiles) *
101                                  (cur_tape->numfiles + 1));
102                 for(c = 0; c < cur_tape->numfiles ; c++) {
103                     if(cur_tape->files[c] > file && c == d_idx) {
104                         newfiles[d_idx] = file;
105                         d_idx++;
106                     }
107                     newfiles[d_idx] = cur_tape->files[c];
108                     d_idx++;
109                 }
110                 if(c == d_idx)
111                     newfiles[d_idx] = file;
112                 cur_tape->numfiles++;
113                 amfree(cur_tape->files);
114                 cur_tape->files = newfiles;
115             }
116             dump_tapelist(tapelist);
117             return(tapelist);
118         }
119     }
120
121     new_tape = alloc(SIZEOF(tapelist_t));
122     memset(new_tape, 0, SIZEOF(tapelist_t));
123     new_tape->label = stralloc(label);
124     if(file >= (off_t)0){
125         new_tape->files = alloc(SIZEOF(*(new_tape->files)));
126         new_tape->files[0] = file;
127         new_tape->numfiles = 1;
128         new_tape->isafile = isafile;
129     }
130
131     /* first instance of anything, start our tapelist with it */
132     if(!tapelist){
133         tapelist = new_tape;
134     } else {
135         /* new tape, tack it onto the end of the list */
136         cur_tape = tapelist;
137         while (cur_tape->next != NULL)
138             cur_tape = cur_tape->next;
139         cur_tape->next = new_tape;
140     }
141
142     dump_tapelist(tapelist);
143     return(tapelist);
144 }
145
146 /*
147  * Backslash-escape all of the commas (and backslashes) in a label string.
148  */
149 char *
150 escape_label(
151     char *      label)
152 {
153     char *cooked_str, *temp_str;
154     int s_idx = 0, d_idx = 0;
155
156     if(!label) return(NULL);
157
158     temp_str = alloc(strlen(label) * 2);
159
160     do{
161         if(label[s_idx] == ',' || label[s_idx] == '\\' ||
162                 label[s_idx] == ';' || label[s_idx] == ':'){
163             temp_str[d_idx] = '\\';
164             d_idx++;
165         }
166         temp_str[d_idx] = label[s_idx];
167         s_idx++;
168         d_idx++;
169     } while(label[s_idx] != '\0');
170     temp_str[d_idx] = '\0';
171
172     cooked_str = stralloc(temp_str);
173     amfree(temp_str);
174     
175     return(cooked_str);
176 }
177
178 /*
179  * Strip out any escape characters (backslashes)
180  */
181 char *
182 unescape_label(
183     char *      label)
184 {
185     char *cooked_str, *temp_str;
186     int s_idx = 0, d_idx = 0, prev_esc = 0;
187     
188     if(!label) return(NULL);
189
190     temp_str = alloc(strlen(label));
191
192     do{
193         if(label[s_idx] == '\\' && !prev_esc){
194             s_idx++;
195             prev_esc = 1;
196             continue;
197         }
198         prev_esc = 0;
199         temp_str[d_idx] = label[s_idx];
200         s_idx++;
201         d_idx++;
202     } while(label[s_idx] != '\0');
203     temp_str[d_idx] = '\0';
204
205     cooked_str = stralloc(temp_str);
206     amfree(temp_str);
207     
208     return(cooked_str);
209 }
210
211 /*
212  * Convert a tapelist into a parseable string of tape labels and file numbers.
213  */
214 char *
215 marshal_tapelist(
216     tapelist_t *tapelist,
217     int         do_escape)
218 {
219     tapelist_t *cur_tape;
220     char *str = NULL;
221
222     for(cur_tape = tapelist; cur_tape; cur_tape = cur_tape->next){
223         char *esc_label;
224         char *files_str = NULL;
225         int c;
226
227         if(do_escape) esc_label = escape_label(cur_tape->label);
228         else esc_label = stralloc(cur_tape->label);
229
230         for(c = 0; c < cur_tape->numfiles ; c++){
231             char num_str[NUM_STR_SIZE];
232             snprintf(num_str, SIZEOF(num_str), OFF_T_FMT,
233                         (OFF_T_FMT_TYPE)cur_tape->files[c]);
234             if (!files_str)
235                 files_str = stralloc(num_str);
236             else
237                 vstrextend(&files_str, ",", num_str, NULL);
238         }
239
240         if (!str)
241             str = vstralloc(esc_label, ":", files_str, NULL);
242         else
243             vstrextend(&str, ";", esc_label, ":", files_str, NULL);
244
245         amfree(esc_label);
246         amfree(files_str);
247     }
248
249     return(str);
250 }
251
252 /*
253  * Convert a previously str-ified and escaped list of tapes back into a
254  * tapelist structure.
255  */
256 tapelist_t *
257 unmarshal_tapelist_str(
258     char *      tapelist_str)
259 {
260     char *temp_label, *temp_filenum;
261     int l_idx, n_idx;
262     size_t input_length;
263     tapelist_t *tapelist = NULL;
264
265     if(!tapelist_str) return(NULL);
266
267     input_length = strlen(tapelist_str);
268
269     temp_label = alloc(input_length+1);
270     temp_filenum = alloc(input_length+1);
271
272     do{
273         /* first, read the label part */
274         memset(temp_label, '\0', input_length+1);
275         l_idx = 0;
276         while(*tapelist_str != ':' && *tapelist_str != '\0'){
277             if(*tapelist_str == '\\')
278                 tapelist_str++; /* skip escapes */
279             temp_label[l_idx] = *tapelist_str;
280             if(*tapelist_str == '\0')
281                 break; /* bad format, should kvetch */
282             tapelist_str++;
283             l_idx++;
284         }
285         if(*tapelist_str != '\0')
286             tapelist_str++;
287         tapelist = append_to_tapelist(tapelist, temp_label, (off_t)-1, 0);
288
289         /* now read the list of file numbers */
290         while(*tapelist_str != ';' && *tapelist_str != '\0'){
291             off_t filenum;
292
293             memset(temp_filenum, '\0', input_length+1);
294             n_idx = 0;
295             while(*tapelist_str != ';' && *tapelist_str != ',' &&
296                     *tapelist_str != '\0'){
297                 temp_filenum[n_idx] = *tapelist_str; 
298                 tapelist_str++;
299                 n_idx++;
300             }
301             filenum = OFF_T_ATOI(temp_filenum);
302
303             tapelist = append_to_tapelist(tapelist, temp_label, filenum, 0);
304             if(*tapelist_str != '\0' && *tapelist_str != ';')
305                 tapelist_str++;
306         }
307         if(*tapelist_str != '\0')
308             tapelist_str++;
309
310     } while(*tapelist_str != '\0');
311
312     amfree(temp_label);
313     amfree(temp_filenum);
314
315     return(tapelist);
316 }
317
318 /*
319  * Free up a list of tapes
320  */
321 void
322 free_tapelist(
323     tapelist_t *        tapelist)
324 {
325     tapelist_t *cur_tape;
326     tapelist_t *prev = NULL;
327
328     for(cur_tape = tapelist ; cur_tape ; cur_tape = cur_tape->next){
329         amfree(cur_tape->label);
330         amfree(cur_tape->files);
331         amfree(prev);
332         prev = cur_tape;
333     }
334     amfree(prev);
335 }