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