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