]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/dvd.c
kes Apply dvd find volume patch from Richard Mortimer.
[bacula/bacula] / bacula / src / stored / dvd.c
1 /*
2  *
3  *   dvd.c  -- Routines specific to DVD devices (and
4  *             possibly other removable hard media). 
5  *
6  *    Nicolas Boichat, MMV
7  *
8  *   Version $Id$
9  */
10 /*
11    Copyright (C) 2005-2006 Kern Sibbald
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License
15    version 2 as amended with additional clauses defined in the
16    file LICENSE in the main source directory.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
21    the file LICENSE for additional details.
22
23  */
24
25 #include "bacula.h"
26 #include "stored.h"
27
28 /* Forward referenced functions */
29 static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name);
30
31 /* 
32  * Write the current volume/part filename to archive_name.
33  */
34 void make_mounted_dvd_filename(DEVICE *dev, POOL_MEM &archive_name) 
35 {
36    pm_strcpy(archive_name, dev->device->mount_point);
37    add_file_and_part_name(dev, archive_name);
38 }
39
40 void make_spooled_dvd_filename(DEVICE *dev, POOL_MEM &archive_name)
41 {
42    /* Use the working directory if spool directory is not defined */
43    if (dev->device->spool_directory) {
44       pm_strcpy(archive_name, dev->device->spool_directory);
45    } else {
46       pm_strcpy(archive_name, working_directory);
47    }
48    add_file_and_part_name(dev, archive_name);
49 }      
50
51 static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name)
52 {
53    char partnumber[20];
54
55    if (archive_name.c_str()[strlen(archive_name.c_str())-1] != '/') {
56       pm_strcat(archive_name, "/");
57    }
58
59    pm_strcat(archive_name, dev->VolCatInfo.VolCatName);
60    /* if part > 1, append .# to the filename (where # is the part number) */
61    if (dev->part > 1) {
62       pm_strcat(archive_name, ".");
63       bsnprintf(partnumber, sizeof(partnumber), "%d", dev->part);
64       pm_strcat(archive_name, partnumber);
65    }
66    Dmsg2(400, "Exit add_file_part_name: arch=%s, part=%d\n",
67                   archive_name.c_str(), dev->part);
68 }  
69
70 /* Update the free space on the device */
71 bool DEVICE::update_freespace() 
72 {
73    POOL_MEM ocmd(PM_FNAME);
74    POOLMEM* results;
75    char* icmd;
76    int timeout;
77    uint64_t free;
78    char ed1[50];
79    bool ok = false;
80    int status;
81
82    if (!is_dvd() || is_freespace_ok()) {
83       return true;
84    }
85    
86    /* The device must be mounted in order to dvd-freespace to work */
87    mount(1);
88    
89    sm_check(__FILE__, __LINE__, false);
90    icmd = device->free_space_command;
91    
92    if (!icmd) {
93       free_space = 0;
94       free_space_errno = 0;
95       clear_freespace_ok();              /* No valid freespace */
96       clear_media();
97       Dmsg2(29, "ERROR: update_free_space_dev: free_space=%s, free_space_errno=%d (!icmd)\n", 
98             edit_uint64(free_space, ed1), free_space_errno);
99       Mmsg(errmsg, _("No FreeSpace command defined.\n"));
100       return false;
101    }
102    
103    edit_mount_codes(ocmd, icmd);
104    
105    Dmsg1(29, "update_freespace: cmd=%s\n", ocmd.c_str());
106
107    results = get_pool_memory(PM_MESSAGE);
108    
109    /* Try at most 3 times to get the free space on the device. This should perhaps be configurable. */
110    timeout = 3;
111    
112    while (1) {
113       berrno be;
114       Dmsg1(20, "Run freespace prog=%s\n", ocmd.c_str());
115       status = run_program_full_output(ocmd.c_str(), max_open_wait/2, results);
116       Dmsg2(500, "Freespace status=%d result=%s\n", status, results);
117       if (status == 0) {
118          free = str_to_int64(results);
119          Dmsg1(400, "Free space program run: Freespace=%s\n", results);
120          if (free >= 0) {
121             free_space = free;
122             free_space_errno = 0;
123             set_freespace_ok();     /* have valid freespace */
124             set_media();
125             Mmsg(errmsg, "");
126             ok = true;
127             break;
128          }
129       }
130       free_space = 0;
131       free_space_errno = EPIPE;
132       clear_freespace_ok();         /* no valid freespace */
133       Mmsg2(errmsg, _("Cannot run free space command. Results=%s ERR=%s\n"), 
134             results, be.strerror(status));
135       
136       if (--timeout > 0) {
137          Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
138             "free_space_errno=%d ERR=%s\n", print_name(), 
139                edit_uint64(free_space, ed1), free_space_errno, 
140                errmsg);
141          bmicrosleep(1, 0);
142          continue;
143       }
144
145       dev_errno = free_space_errno;
146       Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
147          "free_space_errno=%d ERR=%s\n",
148             print_name(), edit_uint64(free_space, ed1),
149             free_space_errno, errmsg);
150       break;
151    }
152    
153    free_pool_memory(results);
154    Dmsg4(29, "leave update_freespace: free_space=%s freespace_ok=%d free_space_errno=%d have_media=%d\n", 
155       edit_uint64(free_space, ed1), !!is_freespace_ok(), free_space_errno, !!have_media());
156    sm_check(__FILE__, __LINE__, false);
157    return ok;
158 }
159
160 /*
161  * Note!!!! Part numbers now begin at 1. The part number is
162  *  suppressed from the first part, which is just the Volume
163  *  name. Each subsequent part is the Volumename.partnumber.
164  *
165  * Write a part (Vol, Vol.2, ...) from the spool to the DVD   
166  * This routine does not update the part number, so normally, you
167  *  should call open_next_part()
168  *
169  * It is also called from truncate_dvd to "blank" the medium, as
170  *  well as from block.c when the DVD is full to write the last part.
171  */
172 bool dvd_write_part(DCR *dcr)
173 {
174    DEVICE *dev = dcr->dev;
175    POOL_MEM archive_name(PM_FNAME);
176    
177    /*
178     * Don't write empty part files.
179     * This is only useful when growisofs does not support write beyond
180     * the 4GB boundary.
181     * Example :
182     *   - 3.9 GB on the volume, dvd-freespace reports 0.4 GB free
183     *   - Write 0.2 GB on the volume, Bacula thinks it could still
184     *     append data, it creates a new empty part.
185     *   - dvd-freespace reports 0 GB free, as the 4GB boundary has
186     *     been crossed
187     *   - Bacula thinks he must finish to write to the device, so it
188     *     tries to write the last part (0-byte), but dvd-writepart fails...
189     *
190     * There is one exception: when recycling a volume, we write a blank part
191     * file, so, then, we need to accept to write it.
192     */
193    if (dev->part_size == 0 && !dev->truncating) {
194       Dmsg2(29, "dvd_write_part: device is %s, won't write blank part %d\n", dev->print_name(), dev->part);
195       /* Delete spool file */
196       make_spooled_dvd_filename(dev, archive_name);
197       unlink(archive_name.c_str());
198       dev->set_part_spooled(false);
199       Dmsg1(29, "========= unlink(%s)\n", archive_name.c_str());
200       sm_check(__FILE__, __LINE__, false);
201       return true;
202    }
203    
204    POOL_MEM ocmd(PM_FNAME);
205    POOL_MEM results(PM_MESSAGE);
206    char* icmd;
207    int status;
208    int timeout;
209    char ed1[50];
210    
211    dev->clear_freespace_ok();             /* need to update freespace */
212
213    sm_check(__FILE__, __LINE__, false);
214    Dmsg3(29, "dvd_write_part: device is %s, part is %d, is_mounted=%d\n", dev->print_name(), dev->part, dev->is_mounted());
215    icmd = dev->device->write_part_command;
216    
217    dev->edit_mount_codes(ocmd, icmd);
218       
219    /*
220     * original line follows
221     * timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
222     * I modified this for a longer timeout; pre-formatting, blanking and
223     * writing can take quite a while
224     */
225
226    /* Explanation of the timeout value, when writing the first part,
227     *  by Arno Lehmann :
228     * 9 GB, write speed 1x: 6990 seconds (almost 2 hours...)
229     * Overhead: 900 seconds (starting, initializing, finalizing,probably 
230     *   reloading 15 minutes)
231     * Sum: 15780.
232     * A reasonable last-exit timeout would be 16000 seconds. Quite long - 
233     * almost 4.5 hours, but hopefully, that timeout will only ever be needed 
234     * in case of a serious emergency.
235     */
236
237    if (dev->part == 1) {
238       timeout = 16000;
239    } else {
240       timeout = dev->max_open_wait + (dev->part_size/(1350*1024/4));
241    }
242
243    Dmsg2(20, "Write part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
244    status = run_program_full_output(ocmd.c_str(), timeout, results.c_str());
245    Dmsg2(20, "Write part status=%d result=%s\n", status, results.c_str());
246
247    dev->blank_dvd = false;
248    if (status != 0) {
249       Jmsg2(dcr->jcr, M_FATAL, 0, _("Error writing part %d to the DVD: ERR=%s\n"),
250          dev->part, results.c_str());
251       Mmsg1(dev->errmsg, _("Error while writing current part to the DVD: %s"), 
252             results.c_str());
253       Dmsg1(100, "%s\n", dev->errmsg);
254       dev->dev_errno = EIO;
255       if (!dev->truncating) {
256          mark_volume_in_error(dcr);
257       }
258       sm_check(__FILE__, __LINE__, false);
259       return false;
260    }
261    Jmsg(dcr->jcr, M_INFO, 0, _("Part %d (%lld bytes) written to DVD.\n"), dev->part, dev->part_size);
262    Dmsg3(400, "dvd_write_part: Part %d (%lld bytes) written to DVD\nResults: %s\n",
263             dev->part, dev->part_size, results.c_str());
264     
265    dev->num_dvd_parts++;            /* there is now one more part on DVD */
266    dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
267    dcr->VolCatInfo.VolCatParts = dev->num_dvd_parts;
268    Dmsg1(100, "Update num_parts=%d\n", dev->num_dvd_parts);
269
270    /* Delete spool file */
271    make_spooled_dvd_filename(dev, archive_name);
272    unlink(archive_name.c_str());
273    dev->set_part_spooled(false);
274    Dmsg1(29, "========= unlink(%s)\n", archive_name.c_str());
275    sm_check(__FILE__, __LINE__, false);
276    
277    /* growisofs umounted the device, so remount it (it will update the free space) */
278    dev->clear_mounted();
279    dev->mount(1);
280    Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"), 
281       edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
282    sm_check(__FILE__, __LINE__, false);
283    return true;
284 }
285
286 /*
287  * Open the next part file.
288  *  - Close the fd
289  *  - Increment part number 
290  *  - Reopen the device
291  */
292 int dvd_open_next_part(DCR *dcr)
293 {
294    DEVICE *dev = dcr->dev;
295
296    Dmsg6(29, "Enter: == open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n", 
297       dev->part, dev->num_dvd_parts, dev->print_name(),
298          dev->VolCatInfo.VolCatName, dev->openmode, dev->file_addr);
299    if (!dev->is_dvd()) {
300       Dmsg1(100, "Device %s is not dvd!!!!\n", dev->print_name()); 
301       return -1;
302    }
303    
304    /* When appending, do not open a new part if the current is empty */
305    if (dev->can_append() && (dev->part > dev->num_dvd_parts) && 
306        (dev->part_size == 0)) {
307       Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
308       return dev->fd;
309    }
310
311    dev->close_part(dcr);               /* close current part */
312    
313    /*
314     * If we have a spooled part open, write it to the
315     *  DVD before opening the next part.
316     */
317    if (dev->is_part_spooled()) {
318       Dmsg2(100, "Before open next write previous. part=%d num_parts=%d\n",
319          dev->part, dev->num_dvd_parts);
320       if (!dvd_write_part(dcr)) {
321          Dmsg0(29, "Error in dvd_write part.\n");
322          return -1;
323       }
324    }
325      
326    dev->part_start += dev->part_size;
327    dev->part++;
328    Dmsg2(29, "Inc part=%d num_dvd_parts=%d\n", dev->part, dev->num_dvd_parts);
329
330    /* Are we working on a part past what is written in the DVD? */
331    if (dev->num_dvd_parts < dev->part) {
332       POOL_MEM archive_name(PM_FNAME);
333       struct stat buf;
334       /* 
335        * First check what is on DVD.  If our part is there, we
336        *   are in trouble, so bail out.
337        * NB: This is however not a problem if we are writing the first part.
338        * It simply means that we are over writing an existing volume...
339        */
340       if (dev->num_dvd_parts > 0) {
341          make_mounted_dvd_filename(dev, archive_name);   /* makes dvd name */
342          Dmsg1(100, "Check if part on DVD: %s\n", archive_name.c_str());
343          if (stat(archive_name.c_str(), &buf) == 0) {
344             /* bad news bail out */
345             dev->set_part_spooled(false);
346             Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
347                archive_name.c_str());
348             return -1;
349          }
350       }
351
352 #ifdef neeeded
353       Dmsg2(400, "num_dvd_parts=%d part=%d\n", dev->num_dvd_parts, dev->part);
354       make_spooled_dvd_filename(dev, archive_name);   /* makes spool name */
355       
356       /* Check if the next part exists in spool directory . */
357       Dmsg1(100, "Check if part on spool: %s\n", archive_name.c_str());
358       if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
359          Dmsg1(29, "======= Part %s is in the way, deleting it...\n", archive_name.c_str());
360          /* Then try to unlink it */
361          if (unlink(archive_name.c_str()) < 0) {
362             berrno be;
363             dev->set_part_spooled(false);
364             dev->dev_errno = errno;
365             Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"), 
366                    archive_name.c_str(), be.strerror());
367             return -1;
368          }
369       }
370 #endif
371    }
372
373    Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName, 
374          dev->openmode);
375
376    /* Open next part.  Note, this sets part_size for part opened. */
377    if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
378       return -1;
379    } 
380    dev->set_labeled();                   /* all next parts are "labeled" */
381    
382    return dev->fd;
383 }
384
385 /*
386  * Open the first part file.
387  *  - Close the fd
388  *  - Reopen the device
389  */
390 static bool dvd_open_first_part(DCR *dcr, int mode)
391 {
392    DEVICE *dev = dcr->dev;
393
394    Dmsg5(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_dvd_parts=%d append=%d\n", dev->print_name(), 
395          dev->VolCatInfo.VolCatName, dev->openmode, dev->num_dvd_parts, dev->can_append());
396
397
398    dev->close_part(dcr);
399
400    Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName, 
401          mode);
402    Dmsg0(100, "Set part=1\n");
403    dev->part = 1;
404    dev->part_start = 0;
405
406    if (dev->open(dcr, mode) < 0) {
407       Dmsg0(400, "open dev() failed\n");
408       return false;
409    }
410    Dmsg2(400, "Leave open_first_part state=%s append=%d\n", dev->is_open()?"open":"not open", dev->can_append());
411    
412    return true;
413 }
414
415
416 /* 
417  * Do an lseek on a DVD handling all the different parts
418  */
419 off_t lseek_dvd(DCR *dcr, off_t offset, int whence)
420 {
421    DEVICE *dev = dcr->dev;
422    off_t pos;
423    char ed1[50], ed2[50];
424    
425    Dmsg5(400, "Enter lseek_dvd fd=%d off=%s w=%d part=%d nparts=%d\n", dev->fd,
426       edit_int64(offset, ed1), whence, dev->part, dev->num_dvd_parts);
427
428    switch(whence) {
429    case SEEK_SET:
430       Dmsg2(400, "lseek_dvd SEEK_SET to %s (part_start=%s)\n",
431          edit_int64(offset, ed1), edit_uint64(dev->part_start, ed2));
432       if ((uint64_t)offset >= dev->part_start) {
433          if ((uint64_t)offset == dev->part_start || 
434              (uint64_t)offset < dev->part_start+dev->part_size) {
435             /* We are staying in the current part, just seek */
436             if ((pos = lseek(dev->fd, offset-dev->part_start, SEEK_SET)) < 0) {
437                return pos;
438             } else {
439                return pos + dev->part_start;
440             }
441          } else {
442             /* Load next part, and start again */
443             Dmsg0(100, "lseek open next part\n");
444             if (dvd_open_next_part(dcr) < 0) {
445                Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
446                return -1;
447             }
448             Dmsg2(100, "Recurse lseek after open next part=%d num_part=%d\n",
449                dev->part, dev->num_dvd_parts);
450             return lseek_dvd(dcr, offset, SEEK_SET);
451          }
452       } else {
453          /*
454           * pos < dev->part_start :
455           * We need to access a previous part, 
456           * so just load the first one, and seek again
457           * until the right one is loaded
458           */
459          Dmsg0(100, "lseek open first part\n");
460          if (!dvd_open_first_part(dcr, dev->openmode)) {
461             Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
462             return -1;
463          }
464          Dmsg2(100, "Recurse lseek after open first part=%d num_part=%d\n",
465                dev->part, dev->num_dvd_parts);
466          return lseek_dvd(dcr, offset, SEEK_SET); /* system lseek */
467       }
468       break;
469    case SEEK_CUR:
470       Dmsg1(400, "lseek_dvd SEEK_CUR to %s\n", edit_int64(offset, ed1));
471       if ((pos = lseek(dev->fd, (off_t)0, SEEK_CUR)) < 0) {
472          Dmsg0(400, "Seek error.\n");
473          return pos;                  
474       }
475       pos += dev->part_start;
476       if (offset == 0) {
477          Dmsg1(400, "lseek_dvd SEEK_CUR returns %s\n", edit_uint64(pos, ed1));
478          return pos;
479       } else { 
480          Dmsg1(400, "do lseek_dvd SEEK_SET %s\n", edit_uint64(pos, ed1));
481          return lseek_dvd(dcr, pos, SEEK_SET);
482       }
483       break;
484    case SEEK_END:
485       Dmsg1(400, "lseek_dvd SEEK_END to %s\n", edit_int64(offset, ed1));
486       /*
487        * Bacula does not use offsets for SEEK_END
488        *  Also, Bacula uses seek_end only when it wants to
489        *  append to the volume, so for a dvd that means
490        *  that the volume must be spooled since the DVD
491        *  itself is read-only (as currently implemented).
492        */
493       if (offset > 0) { /* Not used by bacula */
494          Dmsg1(400, "lseek_dvd SEEK_END called with an invalid offset %s\n", 
495             edit_uint64(offset, ed1));
496          errno = EINVAL;
497          return -1;
498       }
499       /* If we are already on a spooled part and have the
500        *  right part number, simply seek
501        */
502       if (dev->is_part_spooled() && dev->part > dev->num_dvd_parts) {
503          if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) {
504             return pos;   
505          } else {
506             Dmsg1(400, "lseek_dvd SEEK_END returns %s\n", 
507                   edit_uint64(pos + dev->part_start, ed1));
508             return pos + dev->part_start;
509          }
510       } else {
511          /*
512           * Load the first part, then load the next until we reach the last one.
513           * This is the only way to be sure we compute the right file address.
514           *
515           * Save previous openmode, and open all but last part read-only 
516           * (useful for DVDs) 
517           */
518          int modesave = dev->openmode;
519          if (!dvd_open_first_part(dcr, OPEN_READ_ONLY)) {
520             Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
521             return -1;
522          }
523          if (dev->num_dvd_parts > 0) {
524             while (dev->part < dev->num_dvd_parts) {
525                if (dvd_open_next_part(dcr) < 0) {
526                   Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
527                   return -1;
528                }
529             }
530             dev->openmode = modesave;
531             if (dvd_open_next_part(dcr) < 0) {
532                Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
533                return -1;
534             }
535          }
536          return lseek_dvd(dcr, 0, SEEK_END);
537       }
538       break;
539    default:
540       Dmsg0(400, "Seek call error.\n");
541       errno = EINVAL;
542       return -1;
543    }
544 }
545
546 bool dvd_close_job(DCR *dcr)
547 {
548    DEVICE *dev = dcr->dev;
549    JCR *jcr = dcr->jcr;
550    bool ok = true;
551
552    /*
553     * If the device is a dvd and WritePartAfterJob
554     * is set to yes, open the next part, so, in case of a device
555     * that requires mount, it will be written to the device.
556     */
557    if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
558       Dmsg1(400, "Writing last part=%d write_partafter_job is set.\n",
559          dev->part);
560       if (dev->part < dev->num_dvd_parts+1) {
561          Jmsg3(jcr, M_FATAL, 0, _("Error writing. Current part less than total number of parts (%d/%d, device=%s)\n"),
562                dev->part, dev->num_dvd_parts, dev->print_name());
563          dev->dev_errno = EIO;
564          ok = false;
565       }
566       
567       if (ok && !dvd_write_part(dcr)) {
568          Jmsg2(jcr, M_FATAL, 0, _("Unable to write last on %s: ERR=%s\n"),
569                dev->print_name(), dev->bstrerror());
570          dev->dev_errno = EIO;
571          ok = false;
572       }
573    }
574    return ok;
575 }
576
577 void dvd_remove_empty_part(DCR *dcr) 
578 {
579    DEVICE *dev = dcr->dev;
580
581    /* Remove the last part file if it is empty */
582    if (dev->is_dvd() && dev->num_dvd_parts > 0) {
583       struct stat statp;
584       uint32_t part_save = dev->part;
585       POOL_MEM archive_name(PM_FNAME);
586       int status;
587
588       dev->part = dev->num_dvd_parts;
589       make_spooled_dvd_filename(dev, archive_name);
590       /* Check that the part file is empty */
591       status = stat(archive_name.c_str(), &statp);
592       if (status == 0 && statp.st_size == 0) {
593          Dmsg3(100, "Unlink empty part in close call make_dvd_filename. part=%d num=%d vol=%s\n", 
594                 part_save, dev->num_dvd_parts, dev->VolCatInfo.VolCatName);
595          Dmsg1(100, "unlink(%s)\n", archive_name.c_str());
596          unlink(archive_name.c_str());
597          if (part_save == dev->part) {
598             dev->set_part_spooled(false);  /* no spooled part left */
599          }
600       } else if (status < 0) {                         
601          if (part_save == dev->part) {
602             dev->set_part_spooled(false);  /* spool doesn't exit */
603          }
604       }       
605       dev->part = part_save;               /* restore part number */
606    }
607 }
608
609 bool truncate_dvd(DCR *dcr) 
610 {
611    DEVICE* dev = dcr->dev;
612
613    dev->clear_freespace_ok();             /* need to update freespace */
614    dev->close_part(dcr);
615
616    if (!dev->unmount(1)) {
617       Dmsg0(400, "truncate_dvd: Failed to unmount DVD\n");
618       return false;
619    }
620
621    /* If necessary, delete its spool file. */
622    if (dev->is_part_spooled()) {
623       POOL_MEM archive_name(PM_FNAME);
624       /* Delete spool file */
625       make_spooled_dvd_filename(dev, archive_name);
626       unlink(archive_name.c_str());
627       dev->set_part_spooled(false);
628    }
629
630    /* Set num_dvd_parts to zero (on disk) */
631    dev->part = 0;
632    dev->num_dvd_parts = 0;
633    dcr->VolCatInfo.VolCatParts = 0;
634    dev->VolCatInfo.VolCatParts = 0;
635    
636    Dmsg0(400, "truncate_dvd: Opening first part (1)...\n");
637    
638    dev->truncating = true;
639    /* This creates a zero length spool file and sets part=1 */
640    if (!dvd_open_first_part(dcr, CREATE_READ_WRITE)) {
641       Dmsg0(400, "truncate_dvd: Error while opening first part (1).\n");
642       dev->truncating = false;
643       return false;
644    }
645
646    dev->close_part(dcr);
647    
648    Dmsg0(400, "truncate_dvd: Opening first part (2)...\n");
649    
650    /* 
651     * Now actually truncate the DVD which is done by writing
652     *  a zero length part to the DVD/
653     */
654    if (!dvd_write_part(dcr)) {
655       Dmsg0(400, "truncate_dvd: Error while writing to DVD.\n");
656       dev->truncating = false;
657       return false;
658    }
659    dev->truncating = false;
660    
661    /* Set num_dvd_parts to zero (on disk) */
662    dev->part = 0;
663    dev->num_dvd_parts = 0;
664    dcr->VolCatInfo.VolCatParts = 0;
665    dev->VolCatInfo.VolCatParts = 0;
666    /* Clear the size of the volume */
667    dev->VolCatInfo.VolCatBytes = 0;
668    dcr->VolCatInfo.VolCatBytes = 0;
669
670    /* Update catalog */
671    if (!dir_update_volume_info(dcr, false)) {
672       return false;
673    }
674    
675    return true;
676 }
677
678 /*
679  * Checks if we can write on a non-blank DVD: meaning that it just have been
680  * truncated (there is only one zero-sized file on the DVD).
681  *  
682  * Note!  Normally if we can mount the device, which should be the case
683  *   when we get here, it is not a blank DVD.  Hence we check if
684  *   if all files are of zero length (i.e. no data), in which case we allow it.
685  *
686  */
687 bool check_can_write_on_non_blank_dvd(DCR *dcr) 
688 {
689    DEVICE* dev = dcr->dev;
690    DIR* dp;
691    struct dirent *entry, *result;
692    int name_max;
693    struct stat filestat;
694    bool ok = true;
695       
696    name_max = pathconf(".", _PC_NAME_MAX);
697    if (name_max < 1024) {
698       name_max = 1024;
699    }
700    
701    if (!(dp = opendir(dev->device->mount_point))) {
702       berrno be;
703       dev->dev_errno = errno;
704       Dmsg3(29, "check_can_write_on_non_blank_dvd: failed to open dir %s (dev=%s), ERR=%s\n", 
705             dev->device->mount_point, dev->print_name(), be.strerror());
706       return false;
707    }
708    
709    entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
710    for ( ;; ) {
711       if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
712          dev->dev_errno = EIO;
713          Dmsg2(129, "check_can_write_on_non_blank_dvd: no more files in dir %s (dev=%s)\n", 
714                dev->device->mount_point, dev->print_name());
715          break;
716       } else {
717          Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n", 
718                result->d_name, dev->VolCatInfo.VolCatName);
719          if (strcmp(result->d_name, ".") && strcmp(result->d_name, "..") &&
720              strcmp(result->d_name, ".keep")) {
721             /* Found a file, checking it is empty */
722             POOL_MEM filename(PM_FNAME);
723             pm_strcpy(filename, dev->device->mount_point);
724             if (filename.c_str()[strlen(filename.c_str())-1] != '/') {
725                pm_strcat(filename, "/");
726             }
727             pm_strcat(filename, result->d_name);
728             if (stat(filename.c_str(), &filestat) < 0) {
729                berrno be;
730                dev->dev_errno = errno;
731                Dmsg2(29, "check_can_write_on_non_blank_dvd: cannot stat file (file=%s), ERR=%s\n", 
732                   filename.c_str(), be.strerror());
733                ok = false;
734                break;
735             }
736             Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %lld\n", 
737                filename.c_str(), filestat.st_size);
738             if (filestat.st_size != 0) {
739                ok = false;
740                break;
741             }
742          }
743       }
744    }
745    free(entry);
746    closedir(dp);
747    
748    Dmsg1(29, "OK  can_write_on_non_blank_dvd: OK=%d\n", ok);
749    return ok;
750 }
751
752 /* 
753  * Mount a DVD device, then scan to find out how many parts
754  *  there are.
755  */
756 int find_num_dvd_parts(DCR *dcr)
757 {
758    DEVICE *dev = dcr->dev;
759    int num_parts = 0;
760
761    if (!dev->is_dvd()) {
762       return 0;
763    }
764    
765    if (dev->mount(1)) {
766       DIR* dp;
767       struct dirent *entry, *result;
768       int name_max;
769       int len = strlen(dcr->VolCatInfo.VolCatName);
770
771       /* Now count the number of parts */
772       name_max = pathconf(".", _PC_NAME_MAX);
773       if (name_max < 1024) {
774          name_max = 1024;
775       }
776          
777       if (!(dp = opendir(dev->device->mount_point))) {
778          berrno be;
779          dev->dev_errno = errno;
780          Dmsg3(29, "find_num_dvd_parts: failed to open dir %s (dev=%s), ERR=%s\n", 
781                dev->device->mount_point, dev->print_name(), be.strerror());
782          goto get_out;
783       }
784       
785       entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
786
787       Dmsg1(100, "Looking for Vol=%s\n", dcr->VolCatInfo.VolCatName);
788       for ( ;; ) {
789          int flen;
790          bool ignore;
791          if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
792             dev->dev_errno = EIO;
793             Dmsg2(129, "find_num_dvd_parts: failed to find suitable file in dir %s (dev=%s)\n", 
794                   dev->device->mount_point, dev->print_name());
795             break;
796          }
797          flen = strlen(result->d_name);
798          ignore = true;
799          if (flen >= len) {
800             result->d_name[len] = 0;
801             if (strcmp(dcr->VolCatInfo.VolCatName, result->d_name) == 0) {
802                num_parts++;
803                Dmsg1(100, "find_num_dvd_parts: found part: %s\n", result->d_name);
804                ignore = false;
805             }
806          }
807          if (ignore) {
808             Dmsg2(129, "find_num_dvd_parts: ignoring %s in %s\n", 
809                   result->d_name, dev->device->mount_point);
810          }
811       }
812       free(entry);
813       closedir(dp);
814       Dmsg1(29, "find_num_dvd_parts = %d\n", num_parts);
815    }
816    
817 get_out:
818    dev->set_freespace_ok();
819    if (dev->is_mounted()) {
820       dev->unmount(0);
821    }
822    return num_parts;
823 }