"Fossies" - the Fresh Open Source Software Archive 
Member "xorriso-1.5.4/libburn/sg-freebsd-port.c" (30 Jan 2021, 23296 Bytes) of package /linux/misc/xorriso-1.5.4.pl02.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "sg-freebsd-port.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
1.5.2_vs_1.5.4.
1 /* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
2
3 /*
4 Copyright (c) 2006 - 2011 Thomas Schmitt <scdbackup@gmx.net>
5 Provided under GPL version 2 or later.
6 */
7
8
9 /* THIS CODE IS NOT FUNCTIONAL YET !!! */
10
11
12 /*
13
14 This is the main operating system dependent SCSI part of libburn. It implements
15 the transport level aspects of SCSI control and command i/o.
16
17 Present implementation: FreeBSD CAM (untested)
18
19
20 PORTING:
21
22 Porting libburn typically will consist of adding a new operating system case
23 to the following switcher files:
24 os.h Operating system specific libburn definitions and declarations.
25 sg.c Operating system dependent transport level modules.
26 and of deriving the following system specific files from existing examples:
27 os-*.h Included by os.h. You will need some general system knowledge
28 about signals and knowledge about the storage object needs of your
29 transport level module sg-*.c.
30
31 sg-*.c This source module. You will need special system knowledge about
32 how to detect all potentially available drives, how to open them,
33 eventually how to exclusively reserve them, how to perform
34 SCSI transactions, how to inquire the (pseudo-)SCSI driver.
35 You will not need to care about CD burning, MMC or other high-level
36 SCSI aspects.
37
38 Said sg-*.c operations are defined by a public function interface, which has
39 to be implemented in a way that provides libburn with the desired services:
40
41 sg_id_string() returns an id string of the SCSI transport adapter.
42 It may be called before initialization but then may
43 return only a preliminary id.
44
45 sg_initialize() performs global initialization of the SCSI transport
46 adapter and eventually needed operating system
47 facilities. Checks for compatibility of supporting
48 software components.
49
50 sg_shutdown() performs global finalizations and releases globally
51 acquired resources.
52
53 sg_give_next_adr() iterates over the set of potentially useful drive
54 address strings.
55
56 scsi_enumerate_drives() brings all available, not-whitelist-banned, and
57 accessible drives into libburn's list of drives.
58
59 sg_dispose_drive() finalizes adapter specifics of struct burn_drive
60 on destruction. Releases resources which were acquired
61 underneath scsi_enumerate_drives().
62
63 sg_drive_is_open() tells whether libburn has the given drive in use.
64
65 sg_grab() opens the drive for SCSI commands and ensures
66 undisturbed access.
67
68 sg_release() closes a drive opened by sg_grab()
69
70 sg_issue_command() sends a SCSI command to the drive, receives reply,
71 and evaluates whether the command succeeded or shall
72 be retried or finally failed.
73
74 sg_obtain_scsi_adr() tries to obtain SCSI address parameters.
75
76
77 burn_os_is_2k_seekrw() tells whether the given path leads to a file object
78 that can be used in 2 kB granularity by lseek(2),
79 read(2), and possibly write(2) if not read-only.
80 E.g. a USB stick or a hard disk.
81
82 burn_os_stdio_capacity() estimates the emulated media space of stdio-drives.
83
84 burn_os_open_track_src() opens a disk file in a way that offers best
85 throughput with file reading and/or SCSI write command
86 transmission.
87
88 burn_os_alloc_buffer() allocates a memory area that is suitable for file
89 descriptors issued by burn_os_open_track_src().
90 The buffer size may be rounded up for alignment
91 reasons.
92
93 burn_os_free_buffer() delete a buffer obtained by burn_os_alloc_buffer().
94
95
96 Porting hints are marked by the text "PORTING:".
97 Send feedback to libburn-hackers@pykix.org .
98
99 */
100
101 #ifdef HAVE_CONFIG_H
102 #include "../config.h"
103 #endif
104
105
106 /** PORTING : ------- OS dependent headers and definitions ------ */
107
108 #include <errno.h>
109 #include <unistd.h>
110 #include <stdio.h>
111 #include <sys/types.h>
112 #include <sys/stat.h>
113 #include <fcntl.h>
114 #include <sys/ioctl.h>
115 #include <stdlib.h>
116 #include <string.h>
117 #include <sys/poll.h>
118 #include <camlib.h>
119 #include <cam/scsi/scsi_message.h>
120 #include <cam/scsi/scsi_pass.h>
121
122 #include <err.h> /* XXX */
123
124
125 /* ts A70909 */
126 #include <sys/statvfs.h>
127
128
129 /** PORTING : ------ libburn portable headers and definitions ----- */
130
131 #include "transport.h"
132 #include "drive.h"
133 #include "sg.h"
134 #include "spc.h"
135 #include "mmc.h"
136 #include "sbc.h"
137 #include "debug.h"
138 #include "toc.h"
139 #include "util.h"
140
141 #include "libdax_msgs.h"
142 extern struct libdax_msgs *libdax_messenger;
143
144
145 /* is in portable part of libburn */
146 int burn_drive_is_banned(char *device_address);
147
148
149
150 /* ------------------------------------------------------------------------ */
151 /* ts A61115: Private functions. Port only if needed by public functions */
152 /* (Public functions are listed below) */
153 /* ------------------------------------------------------------------------ */
154
155
156 /* Helper function for scsi_give_next_adr() */
157 static int sg_init_enumerator(burn_drive_enumerator_t *idx)
158 {
159 idx->skip_device = 0;
160
161 if ((idx->fd = open(XPT_DEVICE, O_RDWR)) == -1) {
162 warn("couldn't open %s", XPT_DEVICE);
163 return -1;
164 }
165
166 memset(&(idx->ccb), 0, sizeof(union ccb));
167
168 idx->ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
169 idx->ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
170 idx->ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
171
172 idx->ccb.ccb_h.func_code = XPT_DEV_MATCH;
173 idx->bufsize = sizeof(struct dev_match_result) * 100;
174 idx->ccb.cdm.match_buf_len = idx->bufsize;
175 idx->ccb.cdm.matches = (struct dev_match_result *)
176 calloc(1, idx->bufsize);
177 if (idx->ccb.cdm.matches == NULL) {
178 warnx("cannot allocate memory for matches");
179 close(idx->fd);
180 return -1;
181 }
182 idx->ccb.cdm.num_matches = 0;
183 idx->i = idx->ccb.cdm.num_matches; /* to trigger buffer load */
184
185 /*
186 * We fetch all nodes, since we display most of them in the default
187 * case, and all in the verbose case.
188 */
189 idx->ccb.cdm.num_patterns = 0;
190 idx->ccb.cdm.pattern_buf_len = 0;
191
192 return 1;
193 }
194
195
196 /* Helper function for scsi_give_next_adr() */
197 static int sg_next_enumeration_buffer(burn_drive_enumerator_t *idx)
198 {
199 /*
200 * We do the ioctl multiple times if necessary, in case there are
201 * more than 100 nodes in the EDT.
202 */
203 if (ioctl(idx->fd, CAMIOCOMMAND, &(idx->ccb)) == -1) {
204 warn("error sending CAMIOCOMMAND ioctl");
205 return -1;
206 }
207
208 if ((idx->ccb.ccb_h.status != CAM_REQ_CMP)
209 || ((idx->ccb.cdm.status != CAM_DEV_MATCH_LAST)
210 && (idx->ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
211 warnx("got CAM error %#x, CDM error %d\n",
212 idx->ccb.ccb_h.status, idx->ccb.cdm.status);
213 return -1;
214 }
215 return 1;
216 }
217
218
219 static int sg_close_drive(struct burn_drive * d)
220 {
221 if (d->cam != NULL) {
222 cam_close_device(d->cam);
223 d->cam = NULL;
224 }
225 return 0;
226 }
227
228
229 /* ----------------------------------------------------------------------- */
230 /* PORTING: Private functions which contain publicly needed functionality. */
231 /* Their portable part must be performed. So it is probably best */
232 /* to replace the non-portable part and to call these functions */
233 /* in your port, too. */
234 /* ----------------------------------------------------------------------- */
235
236
237 /** Wraps a detected drive into libburn structures and hands it over to
238 libburn drive list.
239 */
240 static void enumerate_common(char *fname, int bus_no, int host_no,
241 int channel_no, int target_no, int lun_no)
242 {
243 int ret;
244 struct burn_drive out;
245
246 /* General libburn drive setup */
247 burn_setup_drive(&out, fname);
248
249 /* This transport adapter uses SCSI-family commands and models
250 (seems the adapter would know better than its boss, if ever) */
251 ret = burn_scsi_setup_drive(&out, bus_no, host_no, channel_no,
252 target_no, lun_no, 0);
253 if (ret<=0)
254 return;
255
256 /* PORTING: ------------------- non portable part --------------- */
257
258 /* Operating system adapter is CAM */
259 /* Adapter specific handles and data */
260 out.cam = NULL;
261
262 /* PORTING: ---------------- end of non portable part ------------ */
263
264 /* Adapter specific functions with standardized names */
265 out.grab = sg_grab;
266 out.release = sg_release;
267 out.drive_is_open = sg_drive_is_open;
268 out.issue_command = sg_issue_command;
269 /* Finally register drive and inquire drive information */
270 burn_drive_finish_enum(&out);
271 }
272
273
274 /* ts A61115 */
275 /* ------------------------------------------------------------------------ */
276 /* PORTING: Public functions. These MUST be ported. */
277 /* ------------------------------------------------------------------------ */
278
279
280 /** Returns the id string of the SCSI transport adapter and eventually
281 needed operating system facilities.
282 This call is usable even if sg_initialize() was not called yet. In that
283 case a preliminary constant message might be issued if detailed info is
284 not available yet.
285 @param msg returns id string
286 @param flag unused yet, submit 0
287 @return 1 = success, <=0 = failure
288 */
289 int sg_id_string(char msg[1024], int flag)
290 {
291 strcpy(msg, "internal FreeBSD CAM adapter sg-freebsd-port");
292 return 1;
293 }
294
295
296 /** Performs global initialization of the SCSI transport adapter and eventually
297 needed operating system facilities. Checks for compatibility supporting
298 software components.
299 @param msg returns ids and/or error messages of eventual helpers
300 @param flag unused yet, submit 0
301 @return 1 = success, <=0 = failure
302 */
303 int sg_initialize(char msg[1024], int flag)
304 {
305 return sg_id_string(msg, 0);
306 }
307
308
309 /** Performs global finalization of the SCSI transport adapter and eventually
310 needed operating system facilities. Releases globally acquired resources.
311 @param flag unused yet, submit 0
312 @return 1 = success, <=0 = failure
313 */
314 int sg_shutdown(int flag)
315 {
316 return 1;
317 }
318
319
320 /** Finalizes BURN_OS_TRANSPORT_DRIVE_ELEMENTS, the components of
321 struct burn_drive which are defined in os-*.h.
322 The eventual initialization of those components was made underneath
323 scsi_enumerate_drives().
324 This will be called when a burn_drive gets disposed.
325 @param d the drive to be finalized
326 @param flag unused yet, submit 0
327 @return 1 = success, <=0 = failure
328 */
329 int sg_dispose_drive(struct burn_drive *d, int flag)
330 {
331 return 1;
332 }
333
334
335 /** Returns the next index number and the next enumerated drive address.
336 The enumeration has to cover all available and accessible drives. It is
337 allowed to return addresses of drives which are not available but under
338 some (even exotic) circumstances could be available. It is on the other
339 hand allowed, only to hand out addresses which can really be used right
340 in the moment of this call. (This implementation chooses the latter.)
341 @param idx An opaque handle. Make no own theories about it.
342 @param adr Takes the reply
343 @param adr_size Gives maximum size of reply including final 0
344 @param initialize 1 = start new,
345 0 = continue, use no other values for now
346 -1 = finish
347 @return 1 = reply is a valid address , 0 = no further address available
348 -1 = severe error (e.g. adr_size too small)
349 */
350 int sg_give_next_adr(burn_drive_enumerator_t *idx,
351 char adr[], int adr_size, int initialize)
352 {
353 int ret;
354
355 if (initialize == 1) {
356 ret = sg_init_enumerator(idx);
357 if (ret<=0)
358 return ret;
359 } else if (initialize == -1) {
360 if(idx->fd != -1)
361 close(idx->fd);
362 idx->fd = -1;
363 return 0;
364 }
365
366
367 try_item:; /* This spaghetti loop keeps the number of tabs small */
368
369 /* Loop content from old scsi_enumerate_drives() */
370
371 while (idx->i >= idx->ccb.cdm.num_matches) {
372 ret = sg_next_enumeration_buffer(idx);
373 if (ret<=0)
374 return -1;
375 if (!((idx->ccb.ccb_h.status == CAM_REQ_CMP)
376 && (idx->ccb.cdm.status == CAM_DEV_MATCH_MORE)) )
377 return 0;
378 idx->i = 0;
379 }
380
381 switch (idx->ccb.cdm.matches[idx->i].type) {
382 case DEV_MATCH_BUS:
383 break;
384 case DEV_MATCH_DEVICE: {
385 struct device_match_result* result;
386
387 result = &(idx->ccb.cdm.matches[i].result.device_result);
388 if (result->flags & DEV_RESULT_UNCONFIGURED)
389 idx->skip_device = 1;
390 else
391 idx->skip_device = 0;
392 break;
393 }
394 case DEV_MATCH_PERIPH: {
395 struct periph_match_result* result;
396 char buf[64];
397
398 result = &(idx->ccb.cdm.matches[i].result.periph_result);
399 if (idx->skip_device ||
400 strcmp(result->periph_name, "pass") == 0)
401 break;
402 snprintf(buf, sizeof (buf), "/dev/%s%d",
403 result->periph_name, result->unit_number);
404 if(adr_size <= strlen(buf))
405 return -1;
406 strcpy(adr, buf);
407
408 /* Found next enumerable address */
409 return 1;
410
411 }
412 default:
413 /* printf(stderr, "unknown match type\n"); */
414 break;
415 }
416
417 (idx->i)++;
418 goto try_item; /* Regular function exit is return 1 above */
419 }
420
421
422 /** Brings all available, not-whitelist-banned, and accessible drives into
423 libburn's list of drives.
424 */
425 int scsi_enumerate_drives(void)
426 {
427 burn_drive_enumerator_t idx;
428 int initialize = 1, ret;
429 char buf[64];
430
431 while(1) {
432 ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
433 initialize = 0;
434 if (ret <= 0)
435 break;
436 if (burn_drive_is_banned(buf))
437 continue;
438 enumerate_common(buf, idx.result->path_id, idx.result->path_id,
439 0, idx.result->target_id,
440 idx.result->target_lun);
441 }
442 sg_give_next_adr(&idx, buf, sizeof(buf), -1);
443 return 1;
444 }
445
446
447 /** Tells whether libburn has the given drive in use or exclusively reserved.
448 If it is "open" then libburn will eventually call sg_release() on it when
449 it is time to give up usage and reservation.
450 */
451 /** Published as burn_drive.drive_is_open() */
452 int sg_drive_is_open(struct burn_drive * d)
453 {
454 return (d->cam != NULL);
455 }
456
457
458 /** Opens the drive for SCSI commands and - if burn activities are prone
459 to external interference on your system - obtains an exclusive access lock
460 on the drive. (Note: this is not physical tray locking.)
461 A drive that has been opened with sg_grab() will eventually be handed
462 over to sg_release() for closing and unreserving.
463 */
464 int sg_grab(struct burn_drive *d)
465 {
466 struct cam_device *cam;
467
468 if(d->cam != NULL) {
469 d->released = 0;
470 return 1;
471 }
472
473 cam = cam_open_device(d->devname, O_RDWR);
474 if (cam == NULL) {
475 libdax_msgs_submit(libdax_messenger, d->global_index,
476 0x00020003,
477 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
478 "Could not grab drive", 0/*os_errno*/, 0);
479 return 0;
480 }
481 d->cam = cam;
482 fcntl(cam->fd, F_SETOWN, getpid());
483 d->released = 0;
484 return 1;
485 }
486
487
488 /** PORTING: Is mainly about the call to sg_close_drive() and whether it
489 implements the demanded functionality.
490 */
491 /** Gives up the drive for SCSI commands and releases eventual access locks.
492 (Note: this is not physical tray locking.)
493 */
494 int sg_release(struct burn_drive *d)
495 {
496 if (d->cam == NULL)
497 return 0;
498 sg_close_drive(d);
499 return 0;
500 }
501
502
503 /** Sends a SCSI command to the drive, receives reply and evaluates whether
504 the command succeeded or shall be retried or finally failed.
505 Returned SCSI errors shall not lead to a return value indicating failure.
506 The callers get notified by c->error. An SCSI failure which leads not to
507 a retry shall be notified via scsi_notify_error().
508 The Libburn_log_sg_commandS facility might be of help when problems with
509 a drive have to be examined. It shall stay disabled for normal use.
510 @return: 1 success , <=0 failure
511 */
512 int sg_issue_command(struct burn_drive *d, struct command *c)
513 {
514 int done = 0;
515 int err;
516 union ccb *ccb;
517
518 if (d->cam == NULL) {
519 c->error = 0;
520 return 0;
521 }
522
523 c->error = 0;
524
525 ccb = cam_getccb(d->cam);
526 cam_fill_csio(&ccb->csio,
527 1, /* retries */
528 NULL, /* cbfncp */
529 CAM_DEV_QFRZDIS, /* flags */
530 MSG_SIMPLE_Q_TAG, /* tag_action */
531 NULL, /* data_ptr */
532 0, /* dxfer_len */
533 sizeof (ccb->csio.sense_data), /* sense_len */
534 0, /* cdb_len */
535 30*1000); /* timeout */
536 switch (c->dir) {
537 case TO_DRIVE:
538 ccb->csio.ccb_h.flags |= CAM_DIR_OUT;
539 break;
540 case FROM_DRIVE:
541 ccb->csio.ccb_h.flags |= CAM_DIR_IN;
542 break;
543 case NO_TRANSFER:
544 ccb->csio.ccb_h.flags |= CAM_DIR_NONE;
545 break;
546 }
547
548 ccb->csio.cdb_len = c->oplen;
549 memcpy(&ccb->csio.cdb_io.cdb_bytes, &c->opcode, c->oplen);
550
551 if (c->page) {
552 ccb->csio.data_ptr = c->page->data;
553 if (c->dir == FROM_DRIVE) {
554 ccb->csio.dxfer_len = BUFFER_SIZE;
555 /* touch page so we can use valgrind */
556 memset(c->page->data, 0, BUFFER_SIZE);
557 } else {
558
559 /* ts A61115: removed a ssert() */
560 if(c->page->bytes <= 0)
561 return 0;
562
563 ccb->csio.dxfer_len = c->page->bytes;
564 }
565 } else {
566 ccb->csio.data_ptr = NULL;
567 ccb->csio.dxfer_len = 0;
568 }
569
570 /* ts B90523 : Record effective transfer length request for debugging*/
571 c->dxfer_len = ccb->csio.dxfer_len;
572
573 do {
574 memset(&ccb->csio.sense_data, 0, sizeof(ccb->csio.sense_data));
575 err = cam_send_ccb(d->cam, ccb);
576 if (err == -1) {
577 libdax_msgs_submit(libdax_messenger,
578 d->global_index, 0x0002010c,
579 LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
580 "Failed to transfer command to drive",
581 errno, 0);
582 cam_freeccb(ccb);
583 sg_close_drive(d);
584 d->released = 1;
585 d->busy = BURN_DRIVE_IDLE;
586 c->error = 1;
587 return -1;
588 }
589 /* XXX */
590 memcpy(c->sense, &ccb->csio.sense_data, ccb->csio.sense_len);
591 c->sense_len = ccb->csio.sense_len;
592 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
593 if (!c->retry) {
594 c->error = 1;
595 cam_freeccb(ccb);
596 return 1;
597 }
598 switch (scsi_error(d, c->sense, 0)) {
599 case RETRY:
600 done = 0;
601 break;
602 case FAIL:
603 done = 1;
604 c->error = 1;
605 break;
606 }
607 } else {
608 done = 1;
609 }
610 if (!done)
611 spc_register_retry(c);
612 } while (!done);
613 cam_freeccb(ccb);
614 return 1;
615 }
616
617
618 /** Tries to obtain SCSI address parameters.
619 @return 1 is success , 0 is failure
620 */
621 int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
622 int *target_no, int *lun_no)
623 {
624 burn_drive_enumerator_t idx;
625 int initialize = 1, ret;
626 char buf[64];
627 struct periph_match_result* result;
628
629 while(1) {
630 ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
631 initialize = 0;
632 if (ret <= 0)
633 break;
634 if (strcmp(path, buf) != 0)
635 continue;
636 result = &(idx->ccb.cdm.matches[i].result.periph_result);
637 *bus_no = result->path_id;
638 *host_no = result->path_id;
639 *channel_no = 0;
640 *target_no = result->target_id
641 *lun_no = result->target_lun;
642 sg_give_next_adr(&idx, buf, sizeof(buf), -1);
643 return 1;
644 }
645 sg_give_next_adr(&idx, buf, sizeof(buf), -1);
646 return (0);
647 }
648
649
650 /** Tells whether a text is a persistent address as listed by the enumeration
651 functions.
652 */
653 int sg_is_enumerable_adr(char* adr)
654 {
655 burn_drive_enumerator_t idx;
656 int initialize = 1, ret;
657 char buf[64];
658
659 while(1) {
660 ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
661 initialize = 0;
662 if (ret <= 0)
663 break;
664 if (strcmp(adr, buf) == 0) {
665 sg_give_next_adr(&idx, buf, sizeof(buf), -1);
666 return 1;
667 }
668 }
669 sg_give_next_adr(&idx, buf, sizeof(buf), -1);
670 return (0);
671 }
672
673
674 /* ts B00115 */
675 /* Return 1 if the given path leads to a regular file or a device that can be
676 seeked, written, and read with 2 kB granularity.
677 */
678 int burn_os_is_2k_seekrw(char *path, int flag)
679 {
680 struct stat stbuf;
681 char *spt;
682 int i, e;
683
684 if (stat(path, &stbuf) == -1)
685 return 0;
686 if (S_ISREG(stbuf.st_mode))
687 return 1;
688 if (!S_ISCHR(stbuf.st_mode))
689 return 0;
690 spt = strrchr(path, '/');
691 if (spt == NULL)
692 spt = path;
693 else
694 spt++;
695 e = strlen(spt);
696 for (i = strlen(spt) - 1; i > 0; i--)
697 if (spt[i] >= '0' && spt[i] <= '9')
698 e = i;
699 if (strncmp(spt, "da", e) == 0) /* SCSI disk. E.g. USB stick. */
700 return 1;
701 if (strncmp(spt, "cd", e) == 0) /* SCSI CD drive might be writeable. */
702 return 1;
703 if (strncmp(spt, "ad", e) == 0) /* IDE hard drive */
704 return 1;
705 if (strncmp(spt, "acd", e) == 0) /* IDE CD drive might be writeable */
706 return 1;
707 if (strncmp(spt, "fd", e) == 0) /* Floppy disk */
708 return 1;
709 if (strncmp(spt, "fla", e) == 0) /* Flash drive */
710 return 1;
711 return 0;
712 }
713
714
715 /* ts A70909 */
716 /** Estimate the potential payload capacity of a file address.
717 @param path The address of the file to be examined. If it does not
718 exist yet, then the directory will be inquired.
719 @param bytes This value gets modified if an estimation is possible
720 @return -2 = cannot perform necessary operations on file object
721 -1 = neither path nor dirname of path exist
722 0 = could not estimate size capacity of file object
723 1 = estimation has been made, bytes was set
724 */
725 int burn_os_stdio_capacity(char *path, off_t write_start, off_t *bytes)
726 {
727 struct stat stbuf;
728 struct statvfs vfsbuf;
729 char *testpath = NULL, *cpt;
730 off_t add_size = 0;
731 int fd, ret;
732
733 BURN_ALLOC_MEM(testpath, char, 4096);
734 testpath[0] = 0;
735 if (stat(path, &stbuf) == -1) {
736 strcpy(testpath, path);
737 cpt = strrchr(testpath, '/');
738 if(cpt == NULL)
739 strcpy(testpath, ".");
740 else if(cpt == testpath)
741 testpath[1] = 0;
742 else
743 *cpt = 0;
744 if (stat(testpath, &stbuf) == -1)
745 {ret = -1; goto ex;}
746
747 #ifdef Libburn_if_this_was_linuX
748
749 } else if(S_ISBLK(stbuf.st_mode)) {
750 int open_mode = O_RDWR, fd, ret;
751 long blocks;
752
753 blocks = *bytes / 512;
754 if(burn_sg_open_o_excl)
755 open_mode |= O_EXCL;
756 fd = open(path, open_mode);
757 if (fd == -1)
758 {ret = -2; goto ex;}
759 ret = ioctl(fd, BLKGETSIZE, &blocks);
760 close(fd);
761 if (ret == -1)
762 {ret = -2; goto ex;}
763 *bytes = ((off_t) blocks) * (off_t) 512;
764
765 #endif /* Libburn_if_this_was_linuX */
766
767
768 } else if(S_ISCHR(stbuf.st_mode)) {
769 fd = open(path, O_RDONLY);
770 if (fd == -1)
771 {ret = -2; goto ex;}
772 ret = ioctl(fd, DIOCGMEDIASIZE, &add_size);
773 close(fd);
774 if (ret == -1)
775 {ret = -2; goto ex;}
776 *bytes = add_size;
777 } else if(S_ISREG(stbuf.st_mode)) {
778 add_size = burn_sparse_file_addsize(write_start, &stbuf);
779 strcpy(testpath, path);
780 } else
781 {ret = 0; goto ex;}
782
783 if (testpath[0]) {
784 if (statvfs(testpath, &vfsbuf) == -1)
785 {ret = -2; goto ex;}
786 *bytes = add_size + ((off_t) vfsbuf.f_frsize) *
787 (off_t) vfsbuf.f_bavail;
788 }
789 ret = 1;
790 ex:
791 BURN_FREE_MEM(testpath);
792 return ret;
793 }
794
795
796 /* ts A91122 : an interface to open(O_DIRECT) or similar OS tricks. */
797
798 #ifdef Libburn_read_o_direcT
799
800 /* No special O_DIRECT-like precautions are implemented here */
801
802 #endif /* Libburn_read_o_direcT */
803
804
805 int burn_os_open_track_src(char *path, int open_flags, int flag)
806 {
807 int fd;
808
809 fd = open(path, open_flags);
810 return fd;
811 }
812
813
814 void *burn_os_alloc_buffer(size_t amount, int flag)
815 {
816 void *buf = NULL;
817
818 buf = calloc(1, amount);
819 return buf;
820 }
821
822
823 int burn_os_free_buffer(void *buffer, size_t amount, int flag)
824 {
825 if (buffer == NULL)
826 return 0;
827 free(buffer);
828 return 1;
829 }
830