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