]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/dvd.c
97ecf6444cde3b2d38e850141efb61c1e502d81b
[bacula/bacula] / bacula / src / stored / dvd.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2005-2010 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    sm_check(__FILE__, __LINE__, false);
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    sm_check(__FILE__, __LINE__, false);
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       sm_check(__FILE__, __LINE__, false);
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    sm_check(__FILE__, __LINE__, false);
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       sm_check(__FILE__, __LINE__, false);
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    sm_check(__FILE__, __LINE__, false);
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    sm_check(__FILE__, __LINE__, false);
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 #ifdef neeeded
365       Dmsg2(400, "num_dvd_parts=%d part=%d\n", dev->num_dvd_parts, dev->part);
366       make_spooled_dvd_filename(dev, archive_name);   /* makes spool name */
367       
368       /* Check if the next part exists in spool directory . */
369       Dmsg1(100, "Check if part on spool: %s\n", archive_name.c_str());
370       if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
371          Dmsg1(29, "======= Part %s is in the way, deleting it...\n", archive_name.c_str());
372          /* Then try to unlink it */
373          if (unlink(archive_name.c_str()) < 0) {
374             berrno be;
375             dev->set_part_spooled(false);
376             dev->dev_errno = errno;
377             Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"), 
378                    archive_name.c_str(), be.bstrerror());
379             return -1;
380          }
381       }
382 #endif
383    }
384
385    Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->getVolCatName(), 
386          dev->openmode);
387
388    /* Open next part.  Note, this sets part_size for part opened. */
389    if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
390       return -1;
391    } 
392    dev->set_labeled();                   /* all next parts are "labeled" */
393    
394    return dev->fd();
395 }
396
397 /*
398  * Open the first part file.
399  *  - Close the fd
400  *  - Reopen the device
401  */
402 static bool dvd_open_first_part(DCR *dcr, int mode)
403 {
404    DEVICE *dev = dcr->dev;
405
406    Dmsg5(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_dvd_parts=%d append=%d\n", dev->print_name(), 
407          dev->getVolCatName(), dev->openmode, dev->num_dvd_parts, dev->can_append());
408
409
410    dev->close_part(dcr);
411
412    Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->getVolCatName(), 
413          mode);
414    Dmsg0(100, "Set part=1\n");
415    dev->part = 1;
416    dev->part_start = 0;
417
418    if (dev->open(dcr, mode) < 0) {
419       Dmsg0(400, "open dev() failed\n");
420       return false;
421    }
422    Dmsg2(400, "Leave open_first_part state=%s append=%d\n", dev->is_open()?"open":"not open", dev->can_append());
423    
424    return true;
425 }
426
427
428 /* 
429  * Do an lseek on a DVD handling all the different parts
430  */
431 boffset_t lseek_dvd(DCR *dcr, boffset_t offset, int whence)
432 {
433    DEVICE *dev = dcr->dev;
434    boffset_t pos;
435    char ed1[50], ed2[50];
436    
437    Dmsg5(400, "Enter lseek_dvd fd=%d off=%s w=%d part=%d nparts=%d\n", dev->fd(),
438       edit_int64(offset, ed1), whence, dev->part, dev->num_dvd_parts);
439
440    switch(whence) {
441    case SEEK_SET:
442       Dmsg2(400, "lseek_dvd SEEK_SET to %s (part_start=%s)\n",
443          edit_int64(offset, ed1), edit_uint64(dev->part_start, ed2));
444       if ((uint64_t)offset >= dev->part_start) {
445          if ((uint64_t)offset == dev->part_start || 
446              (uint64_t)offset < dev->part_start+dev->part_size) {
447             /* We are staying in the current part, just seek */
448 #if defined(HAVE_WIN32)
449             pos = _lseeki64(dev->fd(), offset-dev->part_start, SEEK_SET);
450 #else
451             pos = lseek(dev->fd(), offset-dev->part_start, SEEK_SET);
452 #endif
453             if (pos < 0) {
454                return pos;
455             } else {
456                return pos + dev->part_start;
457             }
458          } else {
459             /* Load next part, and start again */
460             Dmsg0(100, "lseek open next part\n");
461             if (dvd_open_next_part(dcr) < 0) {
462                Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
463                return -1;
464             }
465             Dmsg2(100, "Recurse lseek after open next part=%d num_part=%d\n",
466                dev->part, dev->num_dvd_parts);
467             return lseek_dvd(dcr, offset, SEEK_SET);
468          }
469       } else {
470          /*
471           * pos < dev->part_start :
472           * We need to access a previous part, 
473           * so just load the first one, and seek again
474           * until the right one is loaded
475           */
476          Dmsg0(100, "lseek open first part\n");
477          if (!dvd_open_first_part(dcr, dev->openmode)) {
478             Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
479             return -1;
480          }
481          Dmsg2(100, "Recurse lseek after open first part=%d num_part=%d\n",
482                dev->part, dev->num_dvd_parts);
483          return lseek_dvd(dcr, offset, SEEK_SET); /* system lseek */
484       }
485       break;
486    case SEEK_CUR:
487       Dmsg1(400, "lseek_dvd SEEK_CUR to %s\n", edit_int64(offset, ed1));
488       if ((pos = lseek(dev->fd(), 0, SEEK_CUR)) < 0) {
489          Dmsg0(400, "Seek error.\n");
490          return pos;                  
491       }
492       pos += dev->part_start;
493       if (offset == 0) {
494          Dmsg1(400, "lseek_dvd SEEK_CUR returns %s\n", edit_uint64(pos, ed1));
495          return pos;
496       } else { 
497          Dmsg1(400, "do lseek_dvd SEEK_SET %s\n", edit_uint64(pos, ed1));
498          return lseek_dvd(dcr, pos, SEEK_SET);
499       }
500       break;
501    case SEEK_END:
502       Dmsg1(400, "lseek_dvd SEEK_END to %s\n", edit_int64(offset, ed1));
503       /*
504        * Bacula does not use offsets for SEEK_END
505        *  Also, Bacula uses seek_end only when it wants to
506        *  append to the volume, so for a dvd that means
507        *  that the volume must be spooled since the DVD
508        *  itself is read-only (as currently implemented).
509        */
510       if (offset > 0) { /* Not used by bacula */
511          Dmsg1(400, "lseek_dvd SEEK_END called with an invalid offset %s\n", 
512             edit_uint64(offset, ed1));
513          errno = EINVAL;
514          return -1;
515       }
516       /* If we are already on a spooled part and have the
517        *  right part number, simply seek
518        */
519       if (dev->is_part_spooled() && dev->part > dev->num_dvd_parts) {
520          if ((pos = lseek(dev->fd(), 0, SEEK_END)) < 0) {
521             return pos;   
522          } else {
523             Dmsg1(400, "lseek_dvd SEEK_END returns %s\n", 
524                   edit_uint64(pos + dev->part_start, ed1));
525             return pos + dev->part_start;
526          }
527       } else {
528          /*
529           * Load the first part, then load the next until we reach the last one.
530           * This is the only way to be sure we compute the right file address.
531           *
532           * Save previous openmode, and open all but last part read-only 
533           * (useful for DVDs) 
534           */
535          int modesave = dev->openmode;
536          if (!dvd_open_first_part(dcr, OPEN_READ_ONLY)) {
537             Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
538             return -1;
539          }
540          if (dev->num_dvd_parts > 0) {
541             while (dev->part < dev->num_dvd_parts) {
542                if (dvd_open_next_part(dcr) < 0) {
543                   Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
544                   return -1;
545                }
546             }
547             dev->openmode = modesave;
548             if (dvd_open_next_part(dcr) < 0) {
549                Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
550                return -1;
551             }
552          }
553          return lseek_dvd(dcr, 0, SEEK_END);
554       }
555       break;
556    default:
557       Dmsg0(400, "Seek call error.\n");
558       errno = EINVAL;
559       return -1;
560    }
561 }
562
563 bool dvd_close_job(DCR *dcr)
564 {
565    DEVICE *dev = dcr->dev;
566    JCR *jcr = dcr->jcr;
567    bool ok = true;
568
569    /*
570     * If the device is a dvd and WritePartAfterJob
571     * is set to yes, open the next part, so, in case of a device
572     * that requires mount, it will be written to the device.
573     */
574    if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
575       Dmsg1(400, "Writing last part=%d write_partafter_job is set.\n",
576          dev->part);
577       if (dev->part < dev->num_dvd_parts+1) {
578          Jmsg3(jcr, M_FATAL, 0, _("Error writing. Current part less than total number of parts (%d/%d, device=%s)\n"),
579                dev->part, dev->num_dvd_parts, dev->print_name());
580          dev->dev_errno = EIO;
581          ok = false;
582       }
583       
584       if (ok && !dvd_write_part(dcr)) {
585          Jmsg2(jcr, M_FATAL, 0, _("Unable to write last on %s: ERR=%s\n"),
586                dev->print_name(), dev->bstrerror());
587          dev->dev_errno = EIO;
588          ok = false;
589       }
590    }
591    return ok;
592 }
593
594 void dvd_remove_empty_part(DCR *dcr) 
595 {
596    DEVICE *dev = dcr->dev;
597
598    /* Remove the last part file if it is empty */
599    if (dev->is_dvd() && dev->num_dvd_parts > 0) {
600       struct stat statp;
601       uint32_t part_save = dev->part;
602       POOL_MEM archive_name(PM_FNAME);
603       int status;
604
605       dev->part = dev->num_dvd_parts;
606       make_spooled_dvd_filename(dev, archive_name);
607       /* Check that the part file is empty */
608       status = stat(archive_name.c_str(), &statp);
609       if (status == 0 && statp.st_size == 0) {
610          Dmsg3(100, "Unlink empty part in close call make_dvd_filename. part=%d num=%d vol=%s\n", 
611                 part_save, dev->num_dvd_parts, dev->getVolCatName());
612          Dmsg1(100, "unlink(%s)\n", archive_name.c_str());
613          unlink(archive_name.c_str());
614          if (part_save == dev->part) {
615             dev->set_part_spooled(false);  /* no spooled part left */
616          }
617       } else if (status < 0) {                         
618          if (part_save == dev->part) {
619             dev->set_part_spooled(false);  /* spool doesn't exit */
620          }
621       }       
622       dev->part = part_save;               /* restore part number */
623    }
624 }
625
626 bool truncate_dvd(DCR *dcr) 
627 {
628    DEVICE* dev = dcr->dev;
629
630    dev->clear_freespace_ok();             /* need to update freespace */
631    dev->close_part(dcr);
632
633    if (!dev->unmount(1)) {
634       Dmsg0(400, "truncate_dvd: Failed to unmount DVD\n");
635       return false;
636    }
637
638    /* If necessary, delete its spool file. */
639    if (dev->is_part_spooled()) {
640       POOL_MEM archive_name(PM_FNAME);
641       /* Delete spool file */
642       make_spooled_dvd_filename(dev, archive_name);
643       unlink(archive_name.c_str());
644       dev->set_part_spooled(false);
645    }
646
647    /* Set num_dvd_parts to zero (on disk) */
648    dev->part = 0;
649    dev->num_dvd_parts = 0;
650    dcr->VolCatInfo.VolCatParts = 0;
651    dev->VolCatInfo.VolCatParts = 0;
652    
653    Dmsg0(400, "truncate_dvd: Opening first part (1)...\n");
654    
655    dev->truncating = true;
656    /* This creates a zero length spool file and sets part=1 */
657    if (!dvd_open_first_part(dcr, CREATE_READ_WRITE)) {
658       Dmsg0(400, "truncate_dvd: Error while opening first part (1).\n");
659       dev->truncating = false;
660       return false;
661    }
662
663    dev->close_part(dcr);
664    
665    Dmsg0(400, "truncate_dvd: Opening first part (2)...\n");
666    
667    /* 
668     * Now actually truncate the DVD which is done by writing
669     *  a zero length part to the DVD/
670     */
671    if (!dvd_write_part(dcr)) {
672       Dmsg0(400, "truncate_dvd: Error while writing to DVD.\n");
673       dev->truncating = false;
674       return false;
675    }
676    dev->truncating = false;
677    
678    /* Set num_dvd_parts to zero (on disk) */
679    dev->part = 0;
680    dev->num_dvd_parts = 0;
681    dcr->VolCatInfo.VolCatParts = 0;
682    dev->VolCatInfo.VolCatParts = 0;
683    /* Clear the size of the volume */
684    dev->VolCatInfo.VolCatBytes = 0;
685    dcr->VolCatInfo.VolCatBytes = 0;
686
687    /* Update catalog */
688    if (!dir_update_volume_info(dcr, false, true)) {
689       return false;
690    }
691    
692    return true;
693 }
694
695 /*
696  * Checks if we can write on a non-blank DVD: meaning that it just have been
697  * truncated (there is only one zero-sized file on the DVD).
698  *  
699  * Note!  Normally if we can mount the device, which should be the case
700  *   when we get here, it is not a blank DVD.  Hence we check if
701  *   if all files are of zero length (i.e. no data), in which case we allow it.
702  *
703  */
704 bool check_can_write_on_non_blank_dvd(DCR *dcr) 
705 {
706    DEVICE* dev = dcr->dev;
707    DIR* dp;
708    struct dirent *entry, *result;
709    int name_max;
710    struct stat filestat;
711    bool ok = true;
712       
713    name_max = pathconf(".", _PC_NAME_MAX);
714    if (name_max < 1024) {
715       name_max = 1024;
716    }
717    
718    if (!(dp = opendir(dev->device->mount_point))) {
719       berrno be;
720       dev->dev_errno = errno;
721       Dmsg3(29, "check_can_write_on_non_blank_dvd: failed to open dir %s (dev=%s), ERR=%s\n", 
722             dev->device->mount_point, dev->print_name(), be.bstrerror());
723       return false;
724    }
725    
726    entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
727    for ( ;; ) {
728       if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
729          dev->dev_errno = EIO;
730          Dmsg2(129, "check_can_write_on_non_blank_dvd: no more files in dir %s (dev=%s)\n", 
731                dev->device->mount_point, dev->print_name());
732          break;
733       } else {
734          Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n", 
735                result->d_name, dev->getVolCatName());
736          if (strcmp(result->d_name, ".") && strcmp(result->d_name, "..") &&
737              strcmp(result->d_name, ".keep")) {
738             /* Found a file, checking it is empty */
739             POOL_MEM filename(PM_FNAME);
740             pm_strcpy(filename, dev->device->mount_point);
741             if (!IsPathSeparator(filename.c_str()[strlen(filename.c_str())-1])) {
742                pm_strcat(filename, "/");
743             }
744             pm_strcat(filename, result->d_name);
745             if (stat(filename.c_str(), &filestat) < 0) {
746                berrno be;
747                dev->dev_errno = errno;
748                Dmsg2(29, "check_can_write_on_non_blank_dvd: cannot stat file (file=%s), ERR=%s\n", 
749                   filename.c_str(), be.bstrerror());
750                ok = false;
751                break;
752             }
753             Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %lld\n", 
754                filename.c_str(), filestat.st_size);
755             if (filestat.st_size != 0) {
756                ok = false;
757                break;
758             }
759          }
760       }
761    }
762    free(entry);
763    closedir(dp);
764    
765    Dmsg1(29, "OK  can_write_on_non_blank_dvd: OK=%d\n", ok);
766    return ok;
767 }
768
769 /* 
770  * Mount a DVD device, then scan to find out how many parts
771  *  there are.
772  */
773 int find_num_dvd_parts(DCR *dcr)
774 {
775    DEVICE *dev = dcr->dev;
776    int num_parts = 0;
777
778    if (!dev->is_dvd()) {
779       return 0;
780    }
781    
782    if (dev->mount(1)) {
783       DIR* dp;
784       struct dirent *entry, *result;
785       int name_max;
786       int len = strlen(dcr->getVolCatName());
787
788       /* Now count the number of parts */
789       name_max = pathconf(".", _PC_NAME_MAX);
790       if (name_max < 1024) {
791          name_max = 1024;
792       }
793          
794       if (!(dp = opendir(dev->device->mount_point))) {
795          berrno be;
796          dev->dev_errno = errno;
797          Dmsg3(29, "find_num_dvd_parts: failed to open dir %s (dev=%s), ERR=%s\n", 
798                dev->device->mount_point, dev->print_name(), be.bstrerror());
799          goto get_out;
800       }
801       
802       entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
803
804       Dmsg1(100, "Looking for Vol=%s\n", dcr->getVolCatName());
805       for ( ;; ) {
806          int flen;
807          bool ignore;
808          if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
809             dev->dev_errno = EIO;
810             Dmsg2(129, "find_num_dvd_parts: failed to find suitable file in dir %s (dev=%s)\n", 
811                   dev->device->mount_point, dev->print_name());
812             break;
813          }
814          flen = strlen(result->d_name);
815          ignore = true;
816          if (flen >= len) {
817             result->d_name[len] = 0;
818             if (strcmp(dcr->getVolCatName(), result->d_name) == 0) {
819                num_parts++;
820                Dmsg1(100, "find_num_dvd_parts: found part: %s\n", result->d_name);
821                ignore = false;
822             }
823          }
824          if (ignore) {
825             Dmsg2(129, "find_num_dvd_parts: ignoring %s in %s\n", 
826                   result->d_name, dev->device->mount_point);
827          }
828       }
829       free(entry);
830       closedir(dp);
831       Dmsg1(29, "find_num_dvd_parts = %d\n", num_parts);
832    }
833    
834 get_out:
835    dev->set_freespace_ok();
836    if (dev->is_mounted()) {
837       dev->unmount(0);
838    }
839    return num_parts;
840 }