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