UDFclient.0.8.8004075500001470000000000000000001307042673500126165ustar reinoudwheelUDFclient.0.8.8/uscsi_sense.c010064400001470000000000001056751307041400500153620ustar reinoudwheel/* $NetBSD: scsipi_verbose.c,v 1.27 2005/05/29 22:00:50 christos Exp $ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Charles M. Hannum. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Small changes made by Reinoud Zandijk */ /* * SCSI sense interpretation. Lifted from src/sys/dev/scsipi/scsipi_verbose.c, * and modified for userland. */ #include #include #include #include #include "uscsilib.h" static const char *sense_keys[16] = { "No Additional Sense", "Recovered Error", "Not Ready", "Media Error", "Hardware Error", "Illegal Request", "Unit Attention", "Write Protected", "Blank Check", "Vendor Unique", "Copy Aborted", "Aborted Command", "Equal Error", "Volume Overflow", "Miscompare Error", "Reserved" }; /* * The current version of this list can be obtained from * */ static const struct { unsigned char asc; unsigned char ascq; const char *description; } adesc[] = { { 0x00, 0x00, "No Additional Sense Information" }, { 0x00, 0x01, "Filemark Detected" }, { 0x00, 0x02, "End-Of-Partition/Medium Detected" }, { 0x00, 0x03, "Setmark Detected" }, { 0x00, 0x04, "Beginning-Of-Partition/Medium Detected" }, { 0x00, 0x05, "End-Of-Data Detected" }, { 0x00, 0x06, "I/O Process Terminated" }, { 0x00, 0x11, "Audio Play Operation In Progress" }, { 0x00, 0x12, "Audio Play Operation Paused" }, { 0x00, 0x13, "Audio Play Operation Successfully Completed" }, { 0x00, 0x14, "Audio Play Operation Stopped Due to Error" }, { 0x00, 0x15, "No Current Audio Status To Return" }, { 0x00, 0x16, "Operation In Progress" }, { 0x00, 0x17, "Cleaning Requested" }, { 0x00, 0x18, "Erase Operation In Progress" }, { 0x00, 0x19, "Locate Operation In Progress" }, { 0x00, 0x1A, "Rewind Operation In Progress" }, { 0x00, 0x1B, "Set Capacity Operation In Progess" }, { 0x00, 0x1C, "Verify Operation In Progress" }, { 0x01, 0x00, "No Index/Sector Signal" }, { 0x02, 0x00, "No Seek Complete" }, { 0x03, 0x00, "Peripheral Device Write Fault" }, { 0x03, 0x01, "No Write Current" }, { 0x03, 0x02, "Excessive Write Errors" }, { 0x04, 0x00, "Logical Unit Not Ready, Cause Not Reportable" }, { 0x04, 0x01, "Logical Unit Is in Process Of Becoming Ready" }, { 0x04, 0x02, "Logical Unit Not Ready, Initialization Command Required" }, { 0x04, 0x03, "Logical Unit Not Ready, Manual Intervention Required" }, { 0x04, 0x04, "Logical Unit Not Ready, Format In Progress" }, { 0x04, 0x05, "Logical Unit Not Ready, Rebuild In Progress" }, { 0x04, 0x06, "Logical Unit Not Ready, Recalculation In Progress" }, { 0x04, 0x07, "Logical Unit Not Ready, Operation In Progress" }, { 0x04, 0x08, "Logical Unit Not Ready, Long Write In Progress" }, { 0x04, 0x09, "Logical Unit Not Ready, Self-Test In Progress" }, { 0x04, 0x0A, "Logical Unit Not Accessible, Asymmetric Access State " "Transition" }, { 0x04, 0x0B, "Logical Unit Not Accessible, Target Port In Standby State" }, { 0x04, 0x0C, "Logical Unit Not Accessible, Target Port In Unavailable State" }, { 0x04, 0x10, "Logical Unit Not Ready, Auxiliary Memory Not Accessible" }, { 0x04, 0x11, "Logical Unit Not Ready, Notify (Enable_Spinup) Required" }, { 0x05, 0x00, "Logical Unit Does Not Respond To Selection" }, { 0x06, 0x00, "No Reference Position Found" }, { 0x07, 0x00, "Multiple Peripheral Devices Selected" }, { 0x08, 0x00, "Logical Unit Communication Failure" }, { 0x08, 0x01, "Logical Unit Communication Timeout" }, { 0x08, 0x02, "Logical Unit Communication Parity Error" }, { 0x08, 0x03, "Logical Unit Communication CRC Error" }, { 0x08, 0x04, "Unreachable Copy Target" }, { 0x09, 0x00, "Track Following Error" }, { 0x09, 0x01, "Tracking Servo Failure" }, { 0x09, 0x02, "Focus Servo Failure" }, { 0x09, 0x03, "Spindle Servo Failure" }, { 0x09, 0x04, "Head Select Fault" }, { 0x0A, 0x00, "Error Log Overflow" }, { 0x0B, 0x00, "Warning" }, { 0x0B, 0x01, "Warning - Specified Temperature Exceeded" }, { 0x0B, 0x02, "Warning - Enclosure Degraded" }, { 0x0C, 0x00, "Write Error" }, { 0x0C, 0x01, "Write Error - Recovered with Auto Reallocation" }, { 0x0C, 0x02, "Write Error - Auto Reallocate Failed" }, { 0x0C, 0x03, "Write Error - Recommend Reassignment" }, { 0x0C, 0x04, "Compression Check Miscompare Error" }, { 0x0C, 0x05, "Data Expansion Occurred During Compression" }, { 0x0C, 0x06, "Block Not Compressible" }, { 0x0C, 0x07, "Write Error - Recovery Needed" }, { 0x0C, 0x08, "Write Error - Recovery Failed" }, { 0x0C, 0x09, "Write Error - Loss Of Streaming" }, { 0x0C, 0x0A, "Write Error - Padding Blocks Added" }, { 0x0C, 0x0B, "Auxiliary Memory Write Error" }, { 0x0C, 0x0C, "Write Error - Unexpected Unsolicited Data" }, { 0x0C, 0x0D, "Write Error - Not Enough Unsolicited Data" }, { 0x0D, 0x00, "Error Detected By Third Party Temporary Initiator" }, { 0x0D, 0x01, "Third Party Device Failure" }, { 0x0D, 0x02, "Copy Target Device Not Reachable" }, { 0x0D, 0x03, "Incorrect Copy Target Device Type" }, { 0x0D, 0x04, "Copy Target Device Data Underrun" }, { 0x0D, 0x05, "Copy Target Device Data Overrun" }, { 0x0E, 0x00, "Invalid Information Unit" }, { 0x0E, 0x01, "Information Unit Too Short" }, { 0x0E, 0x02, "Information Unit Too Long" }, { 0x10, 0x00, "ID CRC Or ECC Error" }, { 0x11, 0x00, "Unrecovered Read Error" }, { 0x11, 0x01, "Read Retries Exhausted" }, { 0x11, 0x02, "Error Too Long To Correct" }, { 0x11, 0x03, "Multiple Read Errors" }, { 0x11, 0x04, "Unrecovered Read Error - Auto Reallocate Failed" }, { 0x11, 0x05, "L-EC Uncorrectable Error" }, { 0x11, 0x06, "CIRC Unrecovered Error" }, { 0x11, 0x07, "Data Re-synchronization Error" }, { 0x11, 0x08, "Incomplete Block Read" }, { 0x11, 0x09, "No Gap Found" }, { 0x11, 0x0A, "Miscorrected Error" }, { 0x11, 0x0B, "Uncorrected Read Error - Recommend Reassignment" }, { 0x11, 0x0C, "Uncorrected Read Error - Recommend Rewrite the Data" }, { 0x11, 0x0D, "De-Compression CRC Error" }, { 0x11, 0x0E, "Cannot Decompress Using Declared Algorithm" }, { 0x11, 0x0F, "Error Reading UPC/EAN Number" }, { 0x11, 0x10, "Error Reading ISRC Number" }, { 0x11, 0x11, "Read Error - Loss Of Streaming" }, { 0x11, 0x12, "Auxiliary Memory Read Error" }, { 0x11, 0x13, "Read Error - Failed Retransmission Request" }, { 0x12, 0x00, "Address Mark Not Found for ID Field" }, { 0x13, 0x00, "Address Mark Not Found for Data Field" }, { 0x14, 0x00, "Recorded Entity Not Found" }, { 0x14, 0x01, "Record Not Found" }, { 0x14, 0x02, "Filemark or Setmark Not Found" }, { 0x14, 0x03, "End-Of-Data Not Found" }, { 0x14, 0x04, "Block Sequence Error" }, { 0x14, 0x05, "Record Not Found - Recommend Reassignment" }, { 0x14, 0x06, "Record Not Found - Data Auto-Reallocated" }, { 0x14, 0x07, "Locate Operation Failure" }, { 0x15, 0x00, "Random Positioning Error" }, { 0x15, 0x01, "Mechanical Positioning Error" }, { 0x15, 0x02, "Positioning Error Detected By Read of Medium" }, { 0x16, 0x00, "Data Synchronization Mark Error" }, { 0x16, 0x01, "Data Sync Error - Data Rewritten" }, { 0x16, 0x02, "Data Sync Error - Recommend Rewrite" }, { 0x16, 0x03, "Data Sync Error - Data Auto-Reallocated" }, { 0x16, 0x04, "Data Sync Error - Recommend Reassignment" }, { 0x17, 0x00, "Recovered Data With No Error Correction Applied" }, { 0x17, 0x01, "Recovered Data With Retries" }, { 0x17, 0x02, "Recovered Data With Positive Head Offset" }, { 0x17, 0x03, "Recovered Data With Negative Head Offset" }, { 0x17, 0x04, "Recovered Data With Retries and/or CIRC Applied" }, { 0x17, 0x05, "Recovered Data Using Previous Sector ID" }, { 0x17, 0x06, "Recovered Data Without ECC - Data Auto-Reallocated" }, { 0x17, 0x07, "Recovered Data Without ECC - Recommend Reassignment" }, { 0x17, 0x08, "Recovered Data Without ECC - Recommend Rewrite" }, { 0x17, 0x09, "Recovered Data Without ECC - Data Rewritten" }, { 0x18, 0x00, "Recovered Data With Error Correction Applied" }, { 0x18, 0x01, "Recovered Data With Error Correction & Retries Applied" }, { 0x18, 0x02, "Recovered Data - Data Auto-Reallocated" }, { 0x18, 0x03, "Recovered Data With CIRC" }, { 0x18, 0x04, "Recovered Data With LEC" }, { 0x18, 0x05, "Recovered Data - Recommend Reassignment" }, { 0x18, 0x06, "Recovered Data - Recommend Rewrite" }, { 0x18, 0x07, "Recovered Data With ECC - Data Rewritten" }, { 0x18, 0x08, "Recovered Data With Linking" }, { 0x19, 0x00, "Defect List Error" }, { 0x19, 0x01, "Defect List Not Available" }, { 0x19, 0x02, "Defect List Error in Primary List" }, { 0x19, 0x03, "Defect List Error in Grown List" }, { 0x1A, 0x00, "Parameter List Length Error" }, { 0x1B, 0x00, "Synchronous Data Transfer Error" }, { 0x1C, 0x00, "Defect List Not Found" }, { 0x1C, 0x01, "Primary Defect List Not Found" }, { 0x1C, 0x02, "Grown Defect List Not Found" }, { 0x1D, 0x00, "Miscompare During Verify Operation" }, { 0x1E, 0x00, "Recovered ID with ECC Correction" }, { 0x1F, 0x00, "Partial Defect List Transfer" }, { 0x20, 0x00, "Invalid Command Operation Code" }, { 0x20, 0x01, "Access Denied - Initiator Pending-Enrolled" }, { 0x20, 0x02, "Access Denied - No Access Rights" }, { 0x20, 0x03, "Access Denied - Invalid Mgmt ID Key" }, { 0x20, 0x04, "Illegal Command While In Write Capable State" }, { 0x20, 0x06, "Illegal Command While In Explicit Address Mode" }, { 0x20, 0x07, "Illegal Command While In Implicit Address Mode" }, { 0x20, 0x08, "Access Denied - Enrollment Conflict" }, { 0x20, 0x09, "Access Denied - Invalid LU Identifer" }, { 0x20, 0x0A, "Access Denied - Invalid Proxy Token" }, { 0x20, 0x0B, "Access Denied - ACL LUN Conflict" }, { 0x21, 0x00, "Logical Block Address Out of Range" }, { 0x21, 0x01, "Invalid Element Address" }, { 0x21, 0x02, "Invalid Address For Write" }, { 0x22, 0x00, "Illegal Function (Use 20 00, 24 00, or 26 00)" }, { 0x24, 0x00, "Illegal Field in CDB" }, { 0x24, 0x01, "CDB Decryption Error" }, { 0x24, 0x04, "Security Audit Value Frozen" }, { 0x24, 0x05, "Security Working Key Frozen" }, { 0x24, 0x06, "Nonce Not Unique" }, { 0x24, 0x07, "Nonce Timestamp Out Of Range" }, { 0x25, 0x00, "Logical Unit Not Supported" }, { 0x26, 0x00, "Invalid Field In Parameter List" }, { 0x26, 0x01, "Parameter Not Supported" }, { 0x26, 0x02, "Parameter Value Invalid" }, { 0x26, 0x03, "Threshold Parameters Not Supported" }, { 0x26, 0x04, "Invalid Release Of Persistent Reservation" }, { 0x26, 0x05, "Data Decryption Error" }, { 0x26, 0x06, "Too Many Target Descriptors" }, { 0x26, 0x07, "Unsupported Target Descriptor Type Code" }, { 0x26, 0x08, "Too Many Segment Descriptors" }, { 0x26, 0x09, "Unsupported Segment Descriptor Type Code" }, { 0x26, 0x0A, "Unexpected Inexact Segment" }, { 0x26, 0x0B, "Inline Data Length Exceeded" }, { 0x26, 0x0C, "Invalid Operation For Copy Source Or Destination" }, { 0x26, 0x0D, "Copy Segment Granularity Violation" }, { 0x26, 0x0E, "Invalid Parameter While Port Is Enabled" }, { 0x27, 0x00, "Write Protected" }, { 0x27, 0x01, "Hardware Write Protected" }, { 0x27, 0x02, "Logical Unit Software Write Protected" }, { 0x27, 0x03, "Associated Write Protect" }, { 0x27, 0x04, "Persistent Write Protect" }, { 0x27, 0x05, "Permanent Write Protect" }, { 0x27, 0x06, "Conditional Write Protect" }, { 0x28, 0x00, "Not Ready To Ready Transition (Medium May Have Changed)" }, { 0x28, 0x01, "Import Or Export Element Accessed" }, { 0x29, 0x00, "Power On, Reset, or Bus Device Reset Occurred" }, { 0x29, 0x01, "Power On Occurred" }, { 0x29, 0x02, "SCSI Bus Reset Occurred" }, { 0x29, 0x03, "Bus Device Reset Function Occurred" }, { 0x29, 0x04, "Device Internal Reset" }, { 0x29, 0x05, "Transceiver Mode Changed To Single-Ended" }, { 0x29, 0x06, "Transceiver Mode Changed To LVD" }, { 0x29, 0x07, "I_T Nexus Loss Occurred" }, { 0x2A, 0x00, "Parameters Changed" }, { 0x2A, 0x01, "Mode Parameters Changed" }, { 0x2A, 0x02, "Log Parameters Changed" }, { 0x2A, 0x03, "Reservations Preempted" }, { 0x2A, 0x04, "Reservations Released" }, { 0x2A, 0x05, "Registrations Preempted" }, { 0x2A, 0x06, "Asymmetric Access State Changed" }, { 0x2A, 0x07, "Implicit Asymmetric Access State Transition Failed" }, { 0x2B, 0x00, "Copy Cannot Execute Since Host Cannot Disconnect" }, { 0x2C, 0x00, "Command Sequence Error" }, { 0x2C, 0x01, "Too Many Windows Specified" }, { 0x2C, 0x02, "Invalid Combination of Windows Specified" }, { 0x2C, 0x03, "Current Program Area Is Not Empty" }, { 0x2C, 0x04, "Current Program Area Is Empty" }, { 0x2C, 0x05, "Illegal Power Condition Request" }, { 0x2C, 0x06, "Persistent Prevent Conflict" }, { 0x2C, 0x07, "Previous Busy Status" }, { 0x2C, 0x08, "Previous Task Set Full Status" }, { 0x2C, 0x09, "Previous Reservation Conflict Status" }, { 0x2C, 0x0A, "Partition or Collection Contains User Objects" }, { 0x2D, 0x00, "Overwrite Error On Update In Place" }, { 0x2E, 0x00, "Insufficient Time For Operation" }, { 0x2F, 0x00, "Commands Cleared By Another Initiator" }, { 0x30, 0x00, "Incompatible Medium Installed" }, { 0x30, 0x01, "Cannot Read Medium - Unknown Format" }, { 0x30, 0x02, "Cannot Read Medium - Incompatible Format" }, { 0x30, 0x03, "Cleaning Cartridge Installed" }, { 0x30, 0x04, "Cannot Write Medium - Unknown Format" }, { 0x30, 0x05, "Cannot Write Medium - Incompatible Format" }, { 0x30, 0x06, "Cannot Format Medium - Incompatible Medium" }, { 0x30, 0x07, "Cleaning Failure" }, { 0x30, 0x08, "Cannot Write - Application Code Mismatch" }, { 0x30, 0x09, "Current Session Not Fixated For Append" }, { 0x30, 0x0A, "Cleaning Request Rejected" }, { 0x30, 0x10, "Medium Not Formatted" }, { 0x31, 0x00, "Medium Format Corrupted" }, { 0x31, 0x01, "Format Command Failed" }, { 0x31, 0x02, "Zoned Formatting Failed Due To Spare Linking" }, { 0x32, 0x00, "No Defect Spare Location Available" }, { 0x32, 0x01, "Defect List Update Failure" }, { 0x33, 0x00, "Tape Length Error" }, { 0x34, 0x00, "Enclosure Failure" }, { 0x35, 0x00, "Enclosure Services Failure" }, { 0x35, 0x01, "Unsupported Enclosure Function" }, { 0x35, 0x02, "Enclosure Services Unavailable" }, { 0x35, 0x03, "Enclosure Services Transfer Failed" }, { 0x35, 0x04, "Enclosure Services Transfer Refused" }, { 0x36, 0x00, "Ribbon, Ink, or Toner Failure" }, { 0x37, 0x00, "Rounded Parameter" }, { 0x39, 0x00, "Saving Parameters Not Supported" }, { 0x3A, 0x00, "Medium Not Present" }, { 0x3A, 0x01, "Medium Not Present - Tray Closed" }, { 0x3A, 0x02, "Medium Not Present - Tray Open" }, { 0x3A, 0x03, "Medium Not Present - Loadable" }, { 0x3A, 0x04, "Medium Not Present - Medium Auxiliary Memory Accessible" }, { 0x3B, 0x00, "Sequential Positioning Error" }, { 0x3B, 0x01, "Tape Position Error At Beginning-of-Medium" }, { 0x3B, 0x02, "Tape Position Error At End-of-Medium" }, { 0x3B, 0x03, "Tape or Electronic Vertical Forms Unit Not Ready" }, { 0x3B, 0x04, "Slew Failure" }, { 0x3B, 0x05, "Paper Jam" }, { 0x3B, 0x06, "Failed To Sense Top-Of-Form" }, { 0x3B, 0x07, "Failed To Sense Bottom-Of-Form" }, { 0x3B, 0x08, "Reposition Error" }, { 0x3B, 0x09, "Read Past End Of Medium" }, { 0x3B, 0x0A, "Read Past Beginning Of Medium" }, { 0x3B, 0x0B, "Position Past End Of Medium" }, { 0x3B, 0x0C, "Position Past Beginning Of Medium" }, { 0x3B, 0x0D, "Medium Destination Element Full" }, { 0x3B, 0x0E, "Medium Source Element Empty" }, { 0x3B, 0x0F, "End Of Medium Reached" }, { 0x3B, 0x11, "Medium Magazine Not Accessible" }, { 0x3B, 0x12, "Medium Magazine Removed" }, { 0x3B, 0x13, "Medium Magazine Inserted" }, { 0x3B, 0x14, "Medium Magazine Locked" }, { 0x3B, 0x15, "Medium Magazine Unlocked" }, { 0x3B, 0x16, "Mechanical Positioning Or Changer Error" }, { 0x3D, 0x00, "Invalid Bits In IDENTIFY Message" }, { 0x3E, 0x00, "Logical Unit Has Not Self-Configured Yet" }, { 0x3E, 0x01, "Logical Unit Failure" }, { 0x3E, 0x02, "Timeout On Logical Unit" }, { 0x3E, 0x03, "Logical Unit Failed Self-Test" }, { 0x3E, 0x04, "Logical Unit Unable To Update Self-Test Log" }, { 0x3F, 0x00, "Target Operating Conditions Have Changed" }, { 0x3F, 0x01, "Microcode Has Been Changed" }, { 0x3F, 0x02, "Changed Operating Definition" }, { 0x3F, 0x03, "INQUIRY Data Has Changed" }, { 0x3F, 0x04, "Component Device Attached" }, { 0x3F, 0x05, "Device Identifier Changed" }, { 0x3F, 0x06, "Redundancy Group Created Or Modified" }, { 0x3F, 0x07, "Redundancy Group Deleted" }, { 0x3F, 0x08, "Spare Created Or Modified" }, { 0x3F, 0x09, "Spare Deleted" }, { 0x3F, 0x0A, "Volume Set Created Or Modified" }, { 0x3F, 0x0B, "Volume Set Deleted" }, { 0x3F, 0x0C, "Volume Set Deassigned" }, { 0x3F, 0x0D, "Volume Set Reassigned" }, { 0x3F, 0x0E, "Reported LUNs Data Has Changed" }, { 0x3F, 0x0F, "Echo Buffer Overwritten" }, { 0x3F, 0x10, "Medium Loadable" }, { 0x3F, 0x11, "Medium Auxiliary Memory Accessible" }, { 0x40, 0x00, "RAM FAILURE (Should Use 40 NN)" }, { 0x41, 0x00, "Data Path FAILURE (Should Use 40 NN)" }, { 0x42, 0x00, "Power-On or Self-Test FAILURE (Should Use 40 NN)" }, { 0x43, 0x00, "Message Error" }, { 0x44, 0x00, "Internal Target Failure" }, { 0x45, 0x00, "Select Or Reselect Failure" }, { 0x46, 0x00, "Unsuccessful Soft Reset" }, { 0x47, 0x00, "SCSI Parity Error" }, { 0x47, 0x01, "Data Phase CRC Error Detected" }, { 0x47, 0x02, "SCSI Parity Error Detected During ST Data Phase" }, { 0x47, 0x03, "Information Unit iuCRC Error Detected" }, { 0x47, 0x04, "Asynchronous Information Protection Error Detected" }, { 0x47, 0x05, "Protocol Service CRC Error" }, { 0x47, 0x7F, "Some Commands Cleared by iSCSI Protocol Event" }, { 0x48, 0x00, "INITIATOR DETECTED ERROR Message Received" }, { 0x49, 0x00, "Invalid Message Error" }, { 0x4A, 0x00, "Command Phase Error" }, { 0x4B, 0x00, "Data Phase Error" }, { 0x4B, 0x01, "Illegal Target Port Transfer Tag Received" }, { 0x4B, 0x02, "Too Much Write Data" }, { 0x4B, 0x03, "ACK/NAK Timeout" }, { 0x4B, 0x04, "NAK Reveived" }, { 0x4B, 0x05, "Data Offset Error" }, { 0x4B, 0x06, "Initiator Response Timeout" }, { 0x4C, 0x00, "Logical Unit Failed Self-Configuration" }, { 0x4D, 0x00, "Tagged Overlapped Commands (NN = Queue Tag)" }, { 0x4E, 0x00, "Overlapped Commands Attempted" }, { 0x50, 0x00, "Write Append Error" }, { 0x50, 0x01, "Write Append Position Error" }, { 0x50, 0x02, "Position Error Related To Timing" }, { 0x51, 0x00, "Erase Failure" }, { 0x51, 0x01, "Erase Failure - Incomplete Erase Operation Detected" }, { 0x52, 0x00, "Cartridge Fault" }, { 0x53, 0x00, "Media Load or Eject Failed" }, { 0x53, 0x01, "Unload Tape Failure" }, { 0x53, 0x02, "Medium Removal Prevented" }, { 0x54, 0x00, "SCSI To Host System Interface Failure" }, { 0x55, 0x00, "System Resource Failure" }, { 0x55, 0x01, "System Buffer Full" }, { 0x55, 0x02, "Insufficient Reservation Resources" }, { 0x55, 0x03, "Insufficient Resources" }, { 0x55, 0x04, "Insufficient Registration Resources" }, { 0x55, 0x05, "Insufficient Access Control Resources" }, { 0x55, 0x06, "Auxiliary Memory Out Of Space" }, { 0x57, 0x00, "Unable To Recover Table-Of-Contents" }, { 0x58, 0x00, "Generation Does Not Exist" }, { 0x59, 0x00, "Updated Block Read" }, { 0x5A, 0x00, "Operator Request or State Change Input (Unspecified)" }, { 0x5A, 0x01, "Operator Medium Removal Requested" }, { 0x5A, 0x02, "Operator Selected Write Protect" }, { 0x5A, 0x03, "Operator Selected Write Permit" }, { 0x5B, 0x00, "Log Exception" }, { 0x5B, 0x01, "Threshold Condition Met" }, { 0x5B, 0x02, "Log Counter At Maximum" }, { 0x5B, 0x03, "Log List Codes Exhausted" }, { 0x5C, 0x00, "RPL Status Change" }, { 0x5C, 0x01, "Spindles Synchronized" }, { 0x5C, 0x02, "Spindles Not Synchronized" }, { 0x5D, 0x00, "Failure Prediction Threshold Exceeded" }, { 0x5D, 0x01, "Media Failure Prediction Threshold Exceeded" }, { 0x5D, 0x02, "Logical Unit Failure Prediction Threshold Exceeded" }, { 0x5D, 0x03, "Spare Area Exhaustion Prediction Threshold Exceeded" }, { 0x5D, 0x10, "Hardware Impending Failure General Hard Drive Failure" }, { 0x5D, 0x11, "Hardware Impending Failure Drive Error Rate Too High" }, { 0x5D, 0x12, "Hardware Impending Failure Data Error Rate Too High" }, { 0x5D, 0x13, "Hardware Impending Failure Seek Error Rate Too High" }, { 0x5D, 0x14, "Hardware Impending Failure Too Many Block Reassigns" }, { 0x5D, 0x15, "Hardware Impending Failure Access Times Too High" }, { 0x5D, 0x16, "Hardware Impending Failure Start Unit Times Too High" }, { 0x5D, 0x17, "Hardware Impending Failure Channel Parametrics" }, { 0x5D, 0x18, "Hardware Impending Failure Controller Detected" }, { 0x5D, 0x19, "Hardware Impending Failure Throughput Performance" }, { 0x5D, 0x1A, "Hardware Impending Failure Seek Time Performance" }, { 0x5D, 0x1B, "Hardware Impending Failure Spin-Up Retry Count" }, { 0x5D, 0x1C, "Hardware Impending Failure Drive Calibration Retry Count" }, { 0x5D, 0x20, "Controller Impending Failure General Hard Drive Failure" }, { 0x5D, 0x21, "Controller Impending Failure Drive Error Rate Too High" }, { 0x5D, 0x22, "Controller Impending Failure Data Error Rate Too High" }, { 0x5D, 0x23, "Controller Impending Failure Seek Error Rate Too High" }, { 0x5D, 0x24, "Controller Impending Failure Too Many Block Reassigns" }, { 0x5D, 0x25, "Controller Impending Failure Access Times Too High" }, { 0x5D, 0x26, "Controller Impending Failure Start Unit Times Too High" }, { 0x5D, 0x27, "Controller Impending Failure Channel Parametrics" }, { 0x5D, 0x28, "Controller Impending Failure Controller Detected" }, { 0x5D, 0x29, "Controller Impending Failure Throughput Performance" }, { 0x5D, 0x2A, "Controller Impending Failure Seek Time Performance" }, { 0x5D, 0x2B, "Controller Impending Failure Spin-Up Retry Count" }, { 0x5D, 0x2C, "Controller Impending Failure Drive Calibration Retry Count" }, { 0x5D, 0x30, "Data Channel Impending Failure General Hard Drive Failure" }, { 0x5D, 0x31, "Data Channel Impending Failure Drive Error Rate Too High" }, { 0x5D, 0x32, "Data Channel Impending Failure Data Error Rate Too High" }, { 0x5D, 0x33, "Data Channel Impending Failure Seek Error Rate Too High" }, { 0x5D, 0x34, "Data Channel Impending Failure Too Many Block Reassigns" }, { 0x5D, 0x35, "Data Channel Impending Failure Access Times Too High" }, { 0x5D, 0x36, "Data Channel Impending Failure Start Unit Times Too High" }, { 0x5D, 0x37, "Data Channel Impending Failure Channel Parametrics" }, { 0x5D, 0x38, "Data Channel Impending Failure Controller Detected" }, { 0x5D, 0x39, "Data Channel Impending Failure Throughput Performance" }, { 0x5D, 0x3A, "Data Channel Impending Failure Seek Time Performance" }, { 0x5D, 0x3B, "Data Channel Impending Failure Spin-Up Retry Count" }, { 0x5D, 0x3C, "Data Channel Impending Failure Drive Calibration Retry Count" }, { 0x5D, 0x40, "Servo Impending Failure General Hard Drive Failure" }, { 0x5D, 0x41, "Servo Impending Failure Drive Error Rate Too High" }, { 0x5D, 0x42, "Servo Impending Failure Data Error Rate Too High" }, { 0x5D, 0x43, "Servo Impending Failure Seek Error Rate Too High" }, { 0x5D, 0x44, "Servo Impending Failure Too Many Block Reassigns" }, { 0x5D, 0x45, "Servo Impending Failure Access Times Too High" }, { 0x5D, 0x46, "Servo Impending Failure Start Unit Times Too High" }, { 0x5D, 0x47, "Servo Impending Failure Channel Parametrics" }, { 0x5D, 0x48, "Servo Impending Failure Controller Detected" }, { 0x5D, 0x49, "Servo Impending Failure Throughput Performance" }, { 0x5D, 0x4A, "Servo Impending Failure Seek Time Performance" }, { 0x5D, 0x4B, "Servo Impending Failure Spin-Up Retry Count" }, { 0x5D, 0x4C, "Servo Impending Failure Drive Calibration Retry Count" }, { 0x5D, 0x50, "Spindle Impending Failure General Hard Drive Failure" }, { 0x5D, 0x51, "Spindle Impending Failure Drive Error Rate Too High" }, { 0x5D, 0x52, "Spindle Impending Failure Data Error Rate Too High" }, { 0x5D, 0x53, "Spindle Impending Failure Seek Error Rate Too High" }, { 0x5D, 0x54, "Spindle Impending Failure Too Many Block Reassigns" }, { 0x5D, 0x55, "Spindle Impending Failure Access Times Too High" }, { 0x5D, 0x56, "Spindle Impending Failure Start Unit Times Too High" }, { 0x5D, 0x57, "Spindle Impending Failure Channel Parametrics" }, { 0x5D, 0x58, "Spindle Impending Failure Controller Detected" }, { 0x5D, 0x59, "Spindle Impending Failure Throughput Performance" }, { 0x5D, 0x5A, "Spindle Impending Failure Seek Time Performance" }, { 0x5D, 0x5B, "Spindle Impending Failure Spin-Up Retry Count" }, { 0x5D, 0x5C, "Spindle Impending Failure Drive Calibration Retry Count" }, { 0x5D, 0x60, "Firmware Impending Failure General Hard Drive Failure" }, { 0x5D, 0x61, "Firmware Impending Failure Drive Error Rate Too High" }, { 0x5D, 0x62, "Firmware Impending Failure Data Error Rate Too High" }, { 0x5D, 0x63, "Firmware Impending Failure Seek Error Rate Too High" }, { 0x5D, 0x64, "Firmware Impending Failure Too Many Block Reassigns" }, { 0x5D, 0x65, "Firmware Impending Failure Access Times Too High" }, { 0x5D, 0x66, "Firmware Impending Failure Start Unit Times Too High" }, { 0x5D, 0x67, "Firmware Impending Failure Channel Parametrics" }, { 0x5D, 0x68, "Firmware Impending Failure Controller Detected" }, { 0x5D, 0x69, "Firmware Impending Failure Throughput Performance" }, { 0x5D, 0x6A, "Firmware Impending Failure Seek Time Performance" }, { 0x5D, 0x6B, "Firmware Impending Failure Spin-Up Retry Count" }, { 0x5D, 0x6C, "Firmware Impending Failure Drive Calibration Retry Count" }, { 0x5D, 0xFF, "Failure Prediction Threshold Exceeded (False)" }, { 0x5E, 0x00, "Low Power Condition On" }, { 0x5E, 0x01, "Idle Condition Activated By Timer" }, { 0x5E, 0x02, "Standby Condition Activated By Timer" }, { 0x5E, 0x03, "Idle Condition Activated By Command" }, { 0x5E, 0x04, "Standby Condition Activated By Command" }, { 0x5E, 0x41, "Power State Change To Active" }, { 0x5E, 0x42, "Power State Change To Idle" }, { 0x5E, 0x43, "Power State Change To Standby" }, { 0x5E, 0x45, "Power State Change To Sleep" }, { 0x5E, 0x47, "Power State Change To Device Control" }, { 0x60, 0x00, "Lamp Failure" }, { 0x61, 0x00, "Video Acquisition Error" }, { 0x61, 0x01, "Unable To Acquire Video" }, { 0x61, 0x02, "Out Of Focus" }, { 0x62, 0x00, "Scan Head Positioning Error" }, { 0x63, 0x00, "End Of User Area Encountered On This Track" }, { 0x63, 0x01, "Packet Does Not Fit In Available Space" }, { 0x64, 0x00, "Illegal Mode For This Track" }, { 0x64, 0x01, "Invalid Packet Size" }, { 0x65, 0x00, "Voltage Fault" }, { 0x66, 0x00, "Automatic Document Feeder Cover Up" }, { 0x66, 0x01, "Automatic Document Feeder Lift Up" }, { 0x66, 0x02, "Document Jam In Automatic Document Feeder" }, { 0x66, 0x03, "Document Misfeed In Automatic Document Feeder" }, { 0x67, 0x00, "Configuration Failure" }, { 0x67, 0x01, "Configuration Of Incapable Logical Units Failed" }, { 0x67, 0x02, "Add Logical Unit Failed" }, { 0x67, 0x03, "Modification Of Logical Unit Failed" }, { 0x67, 0x04, "Exchange Of Logical Unit Failed" }, { 0x67, 0x05, "Remove Of Logical Unit Failed" }, { 0x67, 0x06, "Attachment Of Logical Unit Failed" }, { 0x67, 0x07, "Creation of Logical Unit Failed" }, { 0x67, 0x08, "Assign Failure Occurred" }, { 0x67, 0x09, "Multiply Assigned Logical Unit" }, { 0x67, 0x0A, "Set Target Port Groups Command Failed" }, { 0x68, 0x00, "Logical Unit Not Configured" }, { 0x69, 0x00, "Data Loss On Logical Unit" }, { 0x69, 0x01, "Multiple Logical Unit Failures" }, { 0x69, 0x02, "Parity/Data Mismatch" }, { 0x6A, 0x00, "Informational, Refer To Log" }, { 0x6B, 0x00, "State Change Has Occurred" }, { 0x6B, 0x01, "Redundancy Level Got Better" }, { 0x6B, 0x02, "Redundancy Level Got Worse" }, { 0x6C, 0x00, "Rebuild Failure Occurred" }, { 0x6D, 0x00, "Recalculate Failure Occurred" }, { 0x6E, 0x00, "Command To Logical Unit Failed" }, { 0x6F, 0x00, "Copy Protection Key Exchange Failure - Authentication Failure" }, { 0x6F, 0x01, "Copy Protection Key Exchange Failure - Key Not Present" }, { 0x6F, 0x02, "Copy Protection Key Exchange Failure - Key Not Established" }, { 0x6F, 0x03, "Read Of Scrambled Sector Without Authentication" }, { 0x6F, 0x04, "Media Region Code Is Mismatched To Logical Unit Region" }, { 0x6F, 0x05, "Drive Region Must Be Permanent/Region Reset Count Error" }, { 0x70, 0x00, "Decompression Exception Short Algorithm ID Of NN" }, { 0x71, 0x00, "Decompression Exception Long Algorithm ID" }, { 0x72, 0x00, "Session Fixation Error" }, { 0x72, 0x01, "Session Fixation Error Writing Lead-In" }, { 0x72, 0x02, "Session Fixation Error Writing Lead-Out" }, { 0x72, 0x03, "Session Fixation Error - Incomplete Track In Session" }, { 0x72, 0x04, "Empty Or Partially Written Reserved Track" }, { 0x72, 0x05, "No More Track Reservations Allowed" }, { 0x73, 0x00, "CD Control Error" }, { 0x73, 0x01, "Power Calibration Area Almost Full" }, { 0x73, 0x02, "Power Calibration Area Is Full" }, { 0x73, 0x03, "Power Calibration Area Error" }, { 0x73, 0x04, "Program Memory Area Update Failure" }, { 0x73, 0x05, "Program Memory Area Is Full" }, { 0x73, 0x06, "RMA/PMA Is Almost Full" }, { 0x00, 0x00, NULL } }; /* needs to move to a compat.c one day */ #ifdef NO_STRLCPY size_t strlcpy(char *dst, const char *src, size_t size) { snprintf(dst, size, "%s", src); return strlen(src); } #endif static void asc2ascii(u_char asc, u_char ascq, char *result, size_t l) { int i = 0; while (adesc[i].description != NULL) { if (adesc[i].asc == asc && adesc[i].ascq == ascq) break; i++; } if (adesc[i].description == NULL) { if (asc == 0x40 && ascq != 0) (void) snprintf(result, l, "Diagnostic Failure on Component 0x%02x", ascq & 0xff); else (void) snprintf(result, l, "ASC 0x%02x ASCQ 0x%02x", asc & 0xff, ascq & 0xff); } else { (void) strlcpy(result, adesc[i].description, l); } } void uscsi_print_sense_data(uint8_t *s, int slen, int verbosity) { int32_t info; int i, j, k; char *sbs; /* * Basics - print out SENSE KEY */ printf(" SENSE KEY: %s", uscsi_decode_sense(s, 0)); /* * Print out, unqualified but aligned, FMK, EOM and ILI status. */ if (s[2] & 0xe0) { char pad; printf("\n "); pad = ' '; if (s[2] & SSD_FILEMARK) { printf("%c Filemark Detected", pad); pad = ','; } if (s[2] & SSD_EOM) { printf("%c EOM Detected", pad); pad = ','; } if (s[2] & SSD_ILI) printf("%c Incorrect Length Indicator Set", pad); } /* * Now we should figure out, based upon device type, how * to format the information field. Unfortunately, that's * not convenient here, so we'll print it as a signed * 32 bit integer. */ info = (s[3] << 24) | (s[4] << 16) | (s[5] << 8) | s[6]; if (info) printf("\n INFO FIELD: %d", info); /* * Now we check additional length to see whether there is * more information to extract. */ /* enough for command specific information? */ if (((unsigned int) s[7]) < 4) { printf("\n"); return; } info = (s[8] << 24) | (s[9] << 16) | (s[10] << 8) | s[11]; if (info) printf("\n COMMAND INFO: %d (0x%x)", info, info); /* * Decode ASC && ASCQ info, plus FRU, plus the rest... */ sbs = uscsi_decode_sense(s, 1); if (sbs) printf("\n ASC/ASCQ: %s", sbs); if (s[14] != 0) printf("\n FRU CODE: 0x%x", s[14] & 0xff); sbs = uscsi_decode_sense(s, 3); if (sbs) printf("\n SKSV: %s", sbs); printf("\n"); if (verbosity == 0) { printf("\n"); return; } /* * Now figure whether we should print any additional informtion. * * Where should we start from? If we had SKSV data, * start from offset 18, else from offset 15. * * From that point until the end of the buffer, check for any * nonzero data. If we have some, go back and print the lot, * otherwise we're done. */ if (sbs) i = 18; else i = 15; for (j = i; j < slen; j++) if (s[j]) break; if (j == slen) return; printf("\n Additional Sense Information (byte %d out...):\n", i); if (i == 15) { printf("\n\t%2d:", i); k = 7; } else { printf("\n\t%2d:", i); k = 2; j -= 2; } while (j > 0) { if (i >= slen) break; if (k == 8) { k = 0; printf("\n\t%2d:", i); } printf(" 0x%02x", s[i] & 0xff); k++; j--; i++; } printf("\n\n"); } char * uscsi_decode_sense(void *sinfo, int flag) { unsigned char *snsbuf; unsigned char skey; static char rqsbuf[132]; skey = 0; snsbuf = (unsigned char *) sinfo; if (flag == 0 || flag == 2 || flag == 3) skey = snsbuf[2] & 0xf; if (flag == 0) { /* Sense Key Only */ (void) strlcpy(rqsbuf, sense_keys[skey], sizeof(rqsbuf)); return (rqsbuf); } else if (flag == 1) { /* ASC/ASCQ Only */ asc2ascii(snsbuf[12], snsbuf[13], rqsbuf, sizeof(rqsbuf)); return (rqsbuf); } else if (flag == 2) { /* Sense Key && ASC/ASCQ */ auto char localbuf[64]; asc2ascii(snsbuf[12], snsbuf[13], localbuf, sizeof(localbuf)); (void) snprintf(rqsbuf, sizeof(rqsbuf), "%s, %s", sense_keys[skey], localbuf); return (rqsbuf); } else if (flag == 3 && snsbuf[7] >= 9 && (snsbuf[15] & 0x80)) { /* * SKSV Data */ switch (skey) { case SKEY_ILLEGAL_REQUEST: if (snsbuf[15] & 0x8) (void)snprintf(rqsbuf, sizeof(rqsbuf), "Error in %s, Offset %d, bit %d", (snsbuf[15] & 0x40)? "CDB" : "Parameters", (snsbuf[16] & 0xff) << 8 | (snsbuf[17] & 0xff), snsbuf[15] & 0x7); else (void)snprintf(rqsbuf, sizeof(rqsbuf), "Error in %s, Offset %d", (snsbuf[15] & 0x40)? "CDB" : "Parameters", (snsbuf[16] & 0xff) << 8 | (snsbuf[17] & 0xff)); return (rqsbuf); case SKEY_RECOVERED_ERROR: case SKEY_MEDIUM_ERROR: case SKEY_HARDWARE_ERROR: (void)snprintf(rqsbuf, sizeof(rqsbuf), "Actual Retry Count: %d", (snsbuf[16] & 0xff) << 8 | (snsbuf[17] & 0xff)); return (rqsbuf); case SKEY_NOT_READY: (void)snprintf(rqsbuf, sizeof(rqsbuf), "Progress Indicator: %d", (snsbuf[16] & 0xff) << 8 | (snsbuf[17] & 0xff)); return (rqsbuf); default: break; } } return (NULL); } void uscsi_print_sense(const char *name, u_char *req_cmd, int req_cmdlen, u_char *req_sense, int req_senselen_used, int verbosity) { int i; printf("%s: Check Condition on CDB:", name); for (i = 0; i < req_cmdlen; i++) printf(" %02x", req_cmd[i]); printf("\n"); uscsi_print_sense_data(req_sense, req_senselen_used, verbosity); } UDFclient.0.8.8/udf.h010066400001470000000000000636671307041400500136300ustar reinoudwheel/* $NetBSD$ */ /* * File "udf.h" is part of the UDFclient toolkit. * File $Id: udf.h,v 1.149 2015/08/05 18:26:30 reinoud Exp $ $Name: $ * * Copyright (c) 2003, 2004, 2005, 2006, 2011 * Reinoud Zandijk * All rights reserved. * * The UDFclient toolkit is distributed under the Clarified Artistic Licence. * A copy of the licence is included in the distribution as * `LICENCE.clearified.artistic' and a copy of the licence can also be * requested at the GNU foundantion's website. * * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef _UDF_H_ #define _UDF_H_ #include #include #include #include #include #include #include "dirhash.h" #ifdef NO_INT_FMTIO /* assume 32 bits :-/ */ #ifndef PRIu32 # define PRIu32 "u" # define PRIx32 "x" # define PRIu64 "lld" # define PRIx64 "llx" #endif #endif /* exported flags */ extern int udf_verbose; #define UDF_MNT_RDONLY 1 #define UDF_MNT_FORCE 2 #define UDF_MNT_BSWAP 4 #define UDF_VERBLEV_NONE 0 #define UDF_VERBLEV_ACTIONS 1 #define UDF_VERBLEV_TABLES 2 #define UDF_VERBLEV_MAX 3 /* constants to identify what kind of identifier we are dealing with */ #define UDF_REGID_DOMAIN 1 #define UDF_REGID_UDF 2 #define UDF_REGID_IMPLEMENTATION 3 #define UDF_REGID_APPLICATION 4 #define UDF_REGID_NAME 99 /* 99? */ /* RW content hint for allocation and other purposes */ #define UDF_C_DSCR 0 #define UDF_C_USERDATA 1 #define UDF_C_FIDS 2 #define UDF_C_NODE 3 /* Configuration */ #define UDF_MINFREE_LOGVOL (128*1024) /* max sector is 64kb, give 2 (sorry) slack; use with care */ #define UDF_LOOKUP_READAHEAD 64 /* rewrite lookahead; set lookahead 0 to disable */ /* misc. configuration; don't change unless you know what you're doing */ #define UDF_READWRITE_LINE_LENGTH 32 /* DONT change this! 32 sectors for CD-RW/DVD-RW fixed packets */ #define UDF_READWRITE_ALL_PRESENT 0xffffffff #define UDF_INODE_HASHBITS 10 #define UDF_INODE_HASHSIZE (1<= (level)) { op; } # define UDF_VERBOSE_TABLES(op) UDF_VERBOSE_LEVEL(UDF_VERBLEV_TABLES, op) # define UDF_VERBOSE_MAX(op) UDF_VERBOSE_LEVEL(UDF_VERBLEV_MAX, op) #else # define UDF_VERBOSE(op) # define UDF_VERBOSE_LEVEL(level, op) # define UDF_VERBOSE_TABLES(op) # define UDF_VERBOSE_MAX(op) #endif #define UDF_MUTEX(name) struct { \ pthread_mutex_t mutex;\ int locked;\ char *status;\ char *file;\ int line;\ } name #define UDF_MUTEX_INIT(name) { \ pthread_mutex_init(&(name)->mutex, 0); \ (name)->locked = 0; \ (name)->status = "initialised as " #name;\ (name)->file = __FILE__;\ (name)->line = __LINE__;\ } #define UDF_MUTEX_LOCK(name) { \ if (0 && (name)->locked) printf("Waiting for lock " #name " at line %d of file %s marked %s in %s at line %d\n", __LINE__, __FILE__, (name)->status, (name)->file, (name)->line);\ pthread_mutex_lock(&(name)->mutex);\ (name)->locked = 1; \ (name)->status = "locked as " #name;\ (name)->file = __FILE__;\ (name)->line = __LINE__;\ } #define UDF_MUTEX_TRYLOCK(name) { \ if (0) printf("Trying lock " #name " at line %d of file %s marked %s in %s at line %d\n", __LINE__, __FILE__, (name)->status, (name)->file, (name)->line);\ if (pthread_mutex_trylock(&(name)->mutex) != EBUSY) {\ (name)->locked = 1;\ (name)->status = "locked as " #name;\ (name)->file = __FILE__;\ (name)->line = __LINE__;\ };\ } #define UDF_MUTEX_UNLOCK(name) { \ if (0 && !(name)->locked) printf("Unlocking lock " #name " at line %d of file %s marked %s in %s at line %d\n", __LINE__, __FILE__, (name)->status, (name)->file, (name)->line);\ (name)->locked = 0; \ (name)->status = "unlocked as " #name;\ (name)->file = __FILE__;\ (name)->line = __LINE__;\ pthread_mutex_unlock(&(name)->mutex);\ } /* Predefines */ struct udf_node; struct udf_mountpoint; #include "osta.h" #include "ecma167-udf.h" #include "queue.h" #include "udf_discop.h" #include "udf_unix.h" #include "uio.h" #include /*---------------------------------------------------------------------*/ /* * Provides :: write action -> signal written OK or signal write error * NOTE: not used anymore but kept for convenience when write error resolution * is build. */ struct udf_wrcallback; typedef void (udf_wrcallback_func)(int reason, struct udf_wrcallback *wrcallback, int error, uint8_t *sectordata); struct udf_wrcallback { udf_wrcallback_func *function; struct udf_buf *udf_buf; /* associated buffer */ struct udf_node *udf_node; /* associated vnode */ uint32_t flags; /* some reserved flags but other bits are OK */ }; #define UDF_WRCALLBACK_REASON_PENDING 0 #define UDF_WRCALLBACK_REASON_ANULATE 1 #define UDF_WRCALLBACK_REASON_WRITTEN 2 #define UDF_WRCALLBACK_FLAG_DESCRIPTOR (1<<0) #define UDF_WRCALLBACK_FLAG_BUFFER (1<<1) /* * Provides :: ``allocentry'' an ordered list of allocation extents * */ struct udf_allocentry { uint32_t len; uint32_t lb_num; uint16_t vpart_num; uint8_t flags; TAILQ_ENTRY(udf_allocentry) next_alloc; }; #define UDF_SPACE_ALLOCATED 0 #define UDF_SPACE_FREED 1 #define UDF_SPACE_ALLOCATED_BUT_NOT_USED 1 #define UDF_SPACE_FREE 2 #define UDF_SPACE_REDIRECT 3 TAILQ_HEAD(udf_alloc_entries, udf_allocentry); /* * Provides :: ``inode'' or rather filing system dependent v_data node linked under vnode structure * */ struct udf_node { struct udf_mountpoint *mountpoint; /* foreign; provides logvol and fileset */ struct udf_log_vol *udf_log_vol; /* foreign; backup if its not associated to mountpoint */ int dirty; /* flags if (ext)fentry needs to be synced (safeguard) */ int hold; /* node is on hold i.e. don't recycle nor its buffers */ ino_t hashkey; /* for hashing to lookup inode by vpart & lbnum */ struct stat stat; /* holds unix file attributes/filestats */ struct udf_alloc_entries dscr_allocs; /* where my complete descriptor space is located */ uint8_t udf_filetype; /* filetype of this node; raw, block, char, softlink... */ uint8_t udf_filechar; /* udf file characteristics (vis, meta, ... */ uint16_t serial_num; /* serial number of this descriptor on disc */ uint16_t file_version_num; /* file version number of this descriptor on disc */ uint16_t udf_icbtag_flags; /* serial, setuid, setguid, stickybit etc */ uint16_t link_cnt; /* how many FID's are linked to this (ext)fentry */ uint64_t unique_id; /* unique file ID */ /* extended attributes and subfiles */ struct udf_alloc_entry *extattrfile_icb; /* associated extended attribute file */ struct udf_alloc_entry *streamdir_icb; /* associated streamdir */ /* internal in-node storage of extended attributes copy. */ uint8_t *extended_attr; uint32_t extended_attr_len; /* internal in-node storage of data copy */ uint8_t *intern_data; /* descriptor internal data */ uint32_t intern_len; /* length of descriptor internal data */ uint32_t intern_free; /* free space amount in the descriptor besides extattr. */ /* extents of discspace that make up this file/directory */ uint32_t addr_type; /* storage type of allocation descriptors */ uint32_t icb_len; /* length of an icb descriptor */ UDF_MUTEX(alloc_mutex); struct udf_alloc_entries alloc_entries; /* all associated vn_bufs for this node */ UDF_MUTEX(buf_mutex); struct udf_buf_queue vn_bufs; uint32_t v_numoutput; /* dir hasing */ struct dirhash *dir_hash; /* lists */ TAILQ_ENTRY(udf_node) next_dirty; /* next in dirty node list */ LIST_ENTRY(udf_node) next_node; /* next in hash node list */ }; TAILQ_HEAD(udf_node_list, udf_node); /*---------------------------------------------------------------------*/ /* * Provides :: mountpoint -> fileset descriptor and logical volume * */ struct udf_mountpoint { char *mount_name; /* identifier */ struct udf_log_vol *udf_log_vol; /* foreign */ struct fileset_desc *fileset_desc; /* fileset belonging to this mountpoint */ struct udf_node *rootdir_node; struct udf_node *streamdir_node; int writable; /* flags if its a writable fileset */ SLIST_ENTRY(udf_mountpoint) all_next; /* for overall mountpoint list */ SLIST_ENTRY(udf_mountpoint) logvol_next; /* for list of mountpoints in a logvol */ }; /* * Provides :: logvol_partition -> volumeset physical partition */ struct udf_part_mapping { uint32_t udf_part_mapping_type; uint32_t vol_seq_num; uint32_t udf_virt_part_num; uint32_t udf_phys_part_num; union udf_pmap *udf_pmap; /* foreign */ int data_writable; /* flags if its suited for data */ int metadata_writable; /* flags if its for meta-data */ /* supporting tables */ struct udf_sparing_table *sparing_table; /* virtual space */ struct udf_node *vat_udf_node; struct udf_vat *vat; uint8_t *vat_translation; uint32_t vat_entries; uint32_t vat_length; /* needs to be updated; metadata partition disabled for now */ struct udf_node *meta_file; struct udf_node *meta_mirror_file; struct udf_node *meta_bitmap_file; SLIST_ENTRY(udf_part_mapping) next_mapping; /* for list of partition mappings */ }; #define UDF_PART_MAPPING_ERROR 0 #define UDF_PART_MAPPING_PHYSICAL 1 #define UDF_PART_MAPPING_VIRTUAL 2 #define UDF_PART_MAPPING_SPARABLE 3 #define UDF_PART_MAPPING_META 4 #define UDF_PART_MAPPING_PSEUDO_RW 5 /* * Provides :: log_vol -> ... * :: MOUNTPOINTS :) */ struct udf_log_vol { int broken; /* primary volume this logical volume is recorded on */ struct udf_pri_vol *primary; /* foreign */ /* logical volume info */ struct logvol_desc *log_vol; uint32_t lb_size; /* constant over logvol in Ecma 167 */ uint32_t sector_size; /* constant over logvol in Ecma 167 */ /* logical volume integrity/VAT information */ uint32_t logvol_state; /* maintained */ uint16_t integrity_serial; uint32_t min_udf_readver; uint32_t min_udf_writever; uint32_t max_udf_writever; uint32_t num_files; /* maintained */ uint32_t num_directories; /* maintained */ uint64_t next_unique_id; /* maintained */ int writable; /* flags if its writable */ /* dirty nodes administration */ UDF_MUTEX(dirty_nodes_mutex); struct udf_node_list dirty_nodes; /* hash table to lookup ino_t -> udf_node */ LIST_HEAD(inodes, udf_node) udf_nodes[UDF_INODE_HASHSIZE]; /* estimated free space summation; from logvol integrity */ uint64_t total_space; uint64_t free_space; uint64_t await_alloc_space; /* consisting of */ uint32_t data_vpart, metadata_vpart; uint32_t num_mountpoints; /* display only */ SLIST_HEAD(mountpoints_list, udf_mountpoint) mountpoints; /* list of mountables in logvol */ uint32_t num_part_mappings; /* display only */ SLIST_HEAD(part_mappings_list, udf_part_mapping) part_mappings; /* list of partition mappings */ /* next in list */ SLIST_ENTRY(udf_log_vol) next_logvol; /* for list of logical volumes in a primary volume */ }; /* * Provides :: pri_vol -> [log_vol], [part],[ ...] * :: { volumeset -> [pri_vols] } */ struct udf_pri_vol { struct pri_vol_desc *pri_vol; struct udf_session *udf_session; struct impvol_desc *implemation; /* most likely reduntant */ struct udf_volumeset *volumeset; /* foreign ; nesissary? */ struct unalloc_sp_desc *unallocated; /* associated logical volumes */ SLIST_HEAD(logvols, udf_log_vol) log_vols; /* list of associated logical volumes */ STAILQ_ENTRY(udf_pri_vol) next_primary; /* for primary list in volumeset */ }; /* * Provides :: partion -> [partition info, session] */ struct udf_partition { struct part_desc *partition; struct udf_session *udf_session; /* foreign */ uint64_t part_offset; uint64_t part_length; UDF_MUTEX(partition_space_mutex); /* MUTEX for unalloc and freed space */ uint64_t free_unalloc_space; struct udf_alloc_entries unalloc_space_queue; /* authorative */ struct space_bitmap_desc *unalloc_space_bitmap; /* placeholder! does NOT have to be up-to-date */ uint64_t free_freed_space; struct udf_alloc_entries freed_space_queue; /* authorative */ struct space_bitmap_desc *freed_space_bitmap; /* placeholder! does NOT have to be up-to-date */ SLIST_ENTRY(udf_partition) next_partition; /* for partition list in volumeset */ }; /* * Provides :: volumeset -> [pri_vol] * :: [volumeset] */ struct udf_volumeset { int obsolete; uint32_t max_partnum; STAILQ_HEAD(primaries, udf_pri_vol) primaries; /* linked list of primary volumes associated */ SLIST_HEAD(parts, udf_partition) parts; /* linked list of partitions descriptors */ SLIST_ENTRY(udf_volumeset) next_volumeset; /* for volumeset list */ }; /* * Provides udf_session :: -> [(disc, anchor, tracknum)] */ struct udf_session { struct udf_discinfo *disc; struct anchor_vdp anchor; uint16_t session_num; uint32_t session_offset; uint32_t session_length; int writable; /* physical layer read/write cache */ UDF_MUTEX(session_cache_lock); /* SIMPLE cache */ uint32_t cache_line_r_start; uint32_t cache_line_r_present; uint8_t *cache_line_read; uint32_t cache_line_w_start; uint32_t cache_line_w_present; uint32_t cache_line_w_dirty; uint8_t *cache_line_write; struct udf_wrcallback cache_write_callbacks[UDF_READWRITE_LINE_LENGTH+1]; STAILQ_ENTRY(udf_session) next_session; /* sessions are added at tail to preserve order */ }; /*---------------------------------------------------------------------*/ /* exported functions */ extern int udf_check_tag(union dscrptr *dscr); extern int udf_check_tag_payload(union dscrptr *dscr); extern int udf_check_tag_presence(union dscrptr *dscr, int TAG); extern int udf_check_session_range(char *range); /* XXX new kernel like interface XXX */ extern int udf_read_file_part_uio(struct udf_node *udf_node, char *what, int cachehints, struct uio *data_uio); extern int udf_write_file_part_uio(struct udf_node *udf_node, char *what, int cachehints, struct uio *data_uio); extern void udf_dispose_udf_node(struct udf_node *udf_node); extern int udf_getattr(struct udf_node *udf_node, struct stat *stat); extern int udf_readdir(struct udf_node *udf_node, struct uio *result_uio, int *eof_res /* int *cookies, int ncookies */); //extern int udf_lookup_name_in_dir(struct udf_node *dir_node, struct udf_node **vnode, char *name); /* not fully VOP_LOOKUP yet */ extern int udf_lookup_name_in_dir(struct udf_node *dir_node, char *name, int namelen, struct long_ad *icb_loc, struct fileid_desc *fid, int *found); extern int udf_readin_udf_node(struct udf_node *dir_node, struct long_ad *udf_icbptr, struct fileid_desc *fid, struct udf_node **res_sub_node); extern int udf_sync_udf_node(struct udf_node *udf_node, char *why); /* writeout node */ extern int udf_truncate_node(struct udf_node *udf_node, uint64_t length /* ,ioflags */); extern int udf_remove_file(struct udf_node *parent_node, struct udf_node *udf_node, char *componentname); extern int udf_remove_directory(struct udf_node *dir_node, struct udf_node *udf_node, char *componentname); extern int udf_create_file(struct udf_node *dir_node, char *componentname, struct stat *stat, struct udf_node **new_node); extern int udf_create_directory(struct udf_node *dir_node, char *componentname, struct stat *stat, struct udf_node **new_node); extern int udf_rename(struct udf_node *old_parent, struct udf_node *rename_me, char *old_name, struct udf_node *new_parent, struct udf_node *present, char *new_name); extern int udf_unlink_node(struct udf_node *udf_node); extern int udf_read_session_sector(struct udf_session *udf_session, uint32_t sector, char *what, uint8_t *buffer, int prefetch_sectors, int rwflags); extern int udf_write_session_sector(struct udf_session *udf_session, uint32_t sector, char *what, uint8_t *source, int rwflags, struct udf_wrcallback *wrcallback); extern int udf_read_logvol_sector(struct udf_log_vol *udf_log_vol, uint32_t vpart_num, uint32_t lb_num, char *what, uint8_t *buffer, uint32_t prefetch_sectors, int rwflags); extern int udf_write_logvol_sector(struct udf_log_vol *udf_log_vol, uint32_t vpart_num, uint32_t lb_num, char *what, uint8_t *buffer, int rwflags, struct udf_wrcallback *wrcallback); /* call back */ extern int udf_writeout_file_buffer(struct udf_node *udf_node, char *what, int rwflags, struct udf_buf *buf_entry); /* special cases like VRS */ extern int udf_write_session_cache_sector(struct udf_session *udf_session, uint32_t sector, char *what, uint8_t *source, int flags, struct udf_wrcallback *wrcallback); /* device/disc opener, closer and read/write operations */ extern void udf_init(void); /* call me first! */ extern int udf_mount_disc(char *devname, char *range, uint32_t sector_size, int mnt_flags, struct udf_discinfo **disc); extern int udf_dismount_disc(struct udf_discinfo *disc); extern int udf_open_disc(char *devname, int discop_flags, struct udf_discinfo **disc); extern int udf_close_disc(struct udf_discinfo *disc); extern int udf_sync_disc(struct udf_discinfo *disc); extern int udf_sync_logvol(struct udf_log_vol *udf_log_vol); extern int udf_sync_caches(struct udf_log_vol *udf_log_vol); extern int udf_open_logvol(struct udf_log_vol *udf_log_vol); extern int udf_close_logvol(struct udf_log_vol *udf_log_vol); extern int udf_sync_logvol(struct udf_log_vol *udf_log_vol); /* readers/writers helper functions */ extern int udf_init_session_caches(struct udf_session *udf_session); extern int udf_writeout_udf_node(struct udf_node *udf_node, char *why); extern int udf_sync_space_tables(struct udf_log_vol *udf_log_vol); /* read comment on definition */ extern int udf_logvol_vpart_to_partition(struct udf_log_vol *udf_log_vol, uint32_t vpart_num, struct udf_part_mapping **udf_part_mapping_ptr, struct udf_partition **udf_partition_ptr); extern int udf_vpartoff_to_sessionoff(struct udf_log_vol *udf_log_vol, struct udf_part_mapping *udf_part_mapping, struct udf_partition *udf_partition, uint64_t offset, uint64_t *ses_off, uint64_t *trans_valid_len); extern int udf_read_session_descriptor(struct udf_session *udf_session, uint32_t lb_num, char *what, union dscrptr **dscr, uint32_t *length); extern int udf_read_logvol_descriptor(struct udf_log_vol *udf_log_vol, uint32_t vpart_num, uint32_t lb_num, char *what, union dscrptr **dscr, uint32_t *length); extern int udf_write_session_descriptor(struct udf_session *udf_session, uint32_t lb_num, char *what, union dscrptr *dscr, struct udf_wrcallback *wrcallback); extern int udf_write_partition_descriptor(struct udf_partition *udf_partition, uint32_t lb_num, char *what, union dscrptr *dscr, struct udf_wrcallback *wrcallback); extern int udf_write_logvol_descriptor(struct udf_log_vol *udf_log_vol, uint32_t vpart_num, uint32_t lb_num, char *what, union dscrptr *dscr, struct udf_wrcallback *wrcallback); /* exported text-dump functions */ extern void udf_dump_volume_name(char *prefix, struct udf_log_vol *udf_log_vol); extern void udf_dump_long_ad(char *prefix, struct long_ad *adr); extern void udf_dump_id(char *prefix, int len, char *id, struct charspec *chsp); extern void udf_to_unix_name(char *result, char *id, int len, struct charspec *chsp); /* exported descriptor creators */ extern int udf_validate_tag_sum(union dscrptr *dscr); extern int udf_validate_tag_and_crc_sums(union dscrptr *dscr); extern uint64_t udf_calc_tag_malloc_size(union dscrptr *dscr, uint32_t udf_sector_size); extern int udf_read_fid_stream(struct udf_node *dir_node, uint64_t *offset, struct fileid_desc *fid, struct dirent *dirent); extern void udf_resync_fid_stream(uint8_t *buffer, uint32_t *fid_pos, uint32_t max_fid_pos, int *fid_found); extern int udf_create_empty_anchor_volume_descriptor(uint32_t sector_size, uint16_t dscr_ver, uint32_t main_vds_loc, uint32_t reserve_vds_loc, uint32_t length, struct anchor_vdp **vdp); extern int udf_create_empty_primary_volume_descriptor(uint32_t sector_size, uint16_t dscr_ver, uint16_t serial, char *volset_id, char *privol_name, int vds_num, int max_vol_seq, struct pri_vol_desc **dscrptr); extern int udf_create_empty_partition_descriptor(uint32_t sector_size, uint16_t dscr_ver, uint16_t serial, uint16_t part_num, uint32_t access_type, uint32_t start_loc, uint32_t part_len, uint32_t space_bitmap_size, uint32_t unalloc_space_bitmap, struct part_desc **dscrptr); extern int udf_create_empty_unallocated_space_descriptor(uint32_t sector_size, uint16_t dscr_ver, uint16_t serial, struct unalloc_sp_desc **dscrptr); extern int udf_create_empty_implementation_use_volume_descriptor(uint32_t sector_size, uint16_t dscr_ver, uint16_t serial, char *logvol_name, struct impvol_desc **dscrptr); extern int udf_create_empty_logical_volume_descriptor(uint32_t sector_size, uint16_t dscr_ver, uint16_t serial, char *logvol_name, uint32_t lb_size, uint32_t integrity_start, uint32_t integrity_length, struct logvol_desc **dscrptr); extern int udf_create_empty_space_bitmap(uint32_t sector_size, uint16_t dscr_ver, uint32_t num_lbs, struct space_bitmap_desc **dscrptr); extern int udf_create_empty_terminator_descriptor(uint32_t sector_size, uint16_t dscr_ver, struct desc_tag **tag); extern int udf_create_empty_fileset_desc(uint32_t sector_size, uint16_t dscr_ver, uint32_t fileset_num, char *logvol_name, char *fileset_name, struct fileset_desc **dscrptr); extern void udf_add_physical_to_logvol(struct logvol_desc *logvol, uint16_t vol_seq_num, uint16_t phys_part_num); extern void udf_derive_new_logvol_integrity(struct udf_log_vol *udf_log_vol); /* time related creator functions */ extern void udf_set_timespec_now(struct timespec *timespec); extern void udf_set_timestamp_now(struct timestamp *timestamp); /* exported processing functions */ extern int udf_proc_pri_vol(struct udf_session *udf_session, struct udf_pri_vol **current, struct pri_vol_desc *incomming); extern int udf_proc_part(struct udf_pri_vol *primary, struct udf_partition **current, struct part_desc *incomming); extern int udf_proc_log_vol(struct udf_pri_vol *primary, struct udf_log_vol ** current, struct logvol_desc *incomming); extern int udf_proc_filesetdesc(struct udf_log_vol *udf_log_vol, struct fileset_desc *incomming); extern int udf_sync_space_bitmap(struct udf_alloc_entries *queue, struct space_bitmap_desc *sbd, uint32_t lb_size); /* exported builders */ extern int udf_init_udf_node(struct udf_mountpoint *mountpoint, struct udf_log_vol *udf_log_vol, char *what, struct udf_node **udf_nodeptr); extern void udf_insert_node_in_hash(struct udf_node *udf_node); extern int udf_allocate_udf_node_on_disc(struct udf_node *udf_node); extern void udf_node_mark_dirty(struct udf_node *udf_node); extern int udf_allocate_lbs(struct udf_log_vol *udf_log_vol, int content, uint32_t req_lbs, char *what, uint16_t *res_vpart_num, uint32_t *res_start_lb, uint32_t *res_num_lbs); extern int udf_node_allocate_lbs(struct udf_node *udf_node, int req_lbs, uint16_t *res_vpart_num, uint32_t *res_start_lb, uint32_t *res_num_lbs); extern int udf_release_lbs(struct udf_log_vol *udf_log_vol, uint16_t vpart_num, uint32_t lb_num, uint64_t size); extern int udf_node_release_extent(struct udf_node *udf_node, uint64_t from, uint64_t to); extern int udf_confirm_freespace(struct udf_log_vol *udf_log_vol, int content, uint64_t size); extern int udf_create_directory_entry(struct udf_node *dir_node, char *componentname, int filetype, int filechar, struct udf_node *refering, struct stat *stat, struct udf_node **new_node); extern int udf_unlink_node(struct udf_node *udf_node); extern uint64_t udf_increment_unique_id(struct udf_log_vol *udf_log_vol); /* exported (temp) allocentries */ extern void udf_merge_allocentry_queue(struct udf_alloc_entries *queue, uint32_t lb_size); extern int udf_cut_allocentry_queue(struct udf_alloc_entries *queue, uint32_t lb_size, uint64_t offset); extern void udf_dump_allocentry_queue(char *msg, struct udf_alloc_entries *queue, uint32_t lb_size); extern int udf_filepart_mark_extent(struct udf_node *udf_node, uint64_t data_offset, uint64_t data_length, int mark); extern int udf_splitup_allocentry_queue(struct udf_alloc_entries *queue, uint32_t lb_size, uint64_t data_offset, uint64_t data_length, struct udf_allocentry **res_firstae, struct udf_allocentry **res_lastae); extern int udf_mark_allocentry_queue(struct udf_alloc_entries *queue, uint32_t lb_size, uint64_t data_offset, uint64_t data_length, int mark, struct udf_allocentry **res_firstae, struct udf_allocentry **res_lastae); extern int udf_extent_properties(struct udf_alloc_entries *queue, uint32_t lb_size, uint64_t from, uint64_t to, int *res_all_allocated); /* statics inside udf */ SLIST_HEAD(discslist, udf_discinfo) udf_discs_list; SLIST_HEAD(volumeset_list, udf_volumeset) udf_volumeset_list; SLIST_HEAD(mountables_list, udf_mountpoint) udf_mountables; #endif /* _UDF_H_ */ UDFclient.0.8.8/LICENCE.clearified.artistic010064400001470000000000000144041307041400500175540ustar reinoudwheel The Clarified Artistic License Preamble: --------- The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: ------------ "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder as specified below. "Copyright Holder" is whoever is named in the copyright or copyrights for the package. "You" is you, if you're thinking about copying or distributing this Package. "Distribution fee" is a fee you charge for providing a copy of this Package to another party. "Freely Available" means that no fee is charged for the right to use the item, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. Licence: -------- 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain, or those made Freely Available, or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: 1. place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major network archive site allowing unrestricted access to them, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. 2. use the modified Package only within your corporation or organization. 3. rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. 4. make other distribution arrangements with the Copyright Holder. 5. permit and encourge anyone who receives a copy of the modified Package permission to make your modifications Freely Available in some specific way. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: 1. distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. 2. accompany the distribution with the machine-readable source of the Package with your modifications. 3. give non-standard executables non-standard names, and clearly document the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. 4. make other distribution arrangements with the Copyright Holder. 5. offer the machine-readable source of the Package, with your modifications, by mail order. 5. You may charge a distribution fee for any distribution of this Package. If you offer support for this Package, you may charge any fee you choose for that support. You may not charge a license fee for the right to use this Package itself. You may distribute this Package in aggregate with other (possibly commercial and possibly nonfree) programs as part of a larger (possibly commercial and possibly nonfree) software distribution, and charge license fees for other parts of that software distribution, provided that you do not advertise this Package as a product of your own. If the Package includes an interpreter, You may embed this Package's interpreter within an executable of yours (by linking); this shall be construed as a mere form of aggregation, provided that the complete Standard Version of the interpreter is so embedded. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whoever generated them, and may be sold commercially, and may be aggregated with this Package. If such scripts or library files are aggregated with this Package via the so-called "undump" or "unexec" methods of producing a binary executable image, then distribution of such an image shall neither be construed as a distribution of this Package nor shall it fall under the restrictions of Paragraphs 3 and 4, provided that you do not represent such an executable image as a Standard Version of this Package. 7. C subroutines (or comparably compiled subroutines in other languages) supplied by you and linked into this Package in order to emulate subroutines and variables of the language defined by this Package shall not be considered part of this Package, but are the equivalent of input as in Paragraph 6, provided these subroutines do not change the language in any way that would cause it to fail the regression tests for the language. 8. Aggregation of the Standard Version of the Package with a commercial distribution is always permitted provided that the use of this Package is embedded; that is, when no overt attempt is made to make this Package's interfaces visible to the end user of the commercial distribution. Such use shall not be construed as a distribution of this Package. 9. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. UDFclient.0.8.8/uscsilib_machdep.h010066400001470000000000000054061307041400500163330ustar reinoudwheel/* * File "cd_disect.c" is part of the UDFclient toolkit. * File $Id: uscsilib_machdep.h,v 1.3 2011/02/01 20:43:41 reinoud Exp $ $Name: $ * * Copyright (c) 2003, 2004, 2005, 2006, 2011 * Reinoud Zandijk * All rights reserved. * * The UDFclient toolkit is distributed under the Clarified Artistic Licence. * A copy of the licence is included in the distribution as * `LICENCE.clearified.artistic' and a copy of the licence can also be * requested at the GNU foundantion's website. * * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef _USCSILIB_MACHDEP_H_ #define _USCSILIB_MACHDEP_H_ #ifndef _DEV_SCSIPI_SCSIPI_ALL_H_ # define SSD_KEY 0x0F # define SSD_ILI 0x20 # define SSD_EOM 0x40 # define SSD_FILEMARK 0x80 # define SKEY_NO_SENSE 0x00 # define SKEY_RECOVERED_ERROR 0x01 # define SKEY_NOT_READY 0x02 # define SKEY_MEDIUM_ERROR 0x03 # define SKEY_HARDWARE_ERROR 0x04 # define SKEY_ILLEGAL_REQUEST 0x05 # define SKEY_UNIT_ATTENTION 0x06 # define SKEY_WRITE_PROTECT 0x07 # define SKEY_BLANK_CHECK 0x08 # define SKEY_VENDOR_UNIQUE 0x09 # define SKEY_COPY_ABORTED 0x0A # define SKEY_ABORTED_COMMAND 0x0B # define SKEY_EQUAL 0x0C # define SKEY_VOLUME_OVERFLOW 0x0D # define SKEY_MISCOMPARE 0x0E # define SKEY_RESERVED 0x0F #endif #ifndef SCSI # define SCSI_READCMD 0 # define SCSI_WRITECMD 0 struct scsi_addr; int scsilib_verbose; #endif #ifdef USCSI_SCSIPI # include # define SCSI_READCMD SCCMD_READ # define SCSI_WRITECMD SCCMD_WRITE # define SCSI_NODATACMD SCCMD_WRITE #endif #ifdef USCSI_LINUX_SCSI # include # define SCSI_READCMD SG_DXFER_FROM_DEV # define SCSI_WRITECMD SG_DXFER_TO_DEV # define SCSI_NODATACMD SC_DXFER_NONE #endif #ifdef USCSI_FREEBSD_CAM # include # include # define SCSI_READCMD 1 # define SCSI_WRITECMD 2 # define SCSI_NODATACMD 0 #endif #endif /* _USCSILIB_MACHDEP_H_ */ UDFclient.0.8.8/newfs_udf.c010066400001470000000000000626751307041400500150230ustar reinoudwheel/* $NetBSD$ */ /* * File "newfs_udf.c" is part of the UDFclient toolkit. * File $Id: newfs_udf.c,v 1.46 2017/01/18 14:23:35 reinoud Exp $ $Name: $ * * Copyright (c) 2004, 2005, 2006, 2011 * Reinoud Zandijk * All rights reserved. * * The UDFclient toolkit is distributed under the Clarified Artistic Licence. * A copy of the licence is included in the distribution as * `LICENCE.clearified.artistic' and a copy of the licence can also be * requested at the GNU foundantion's website. * * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include "udf.h" #include "udf_bswap.h" /* switches */ /* #define DEBUG(a) (a) */ #define DEBUG(a) if (0) { a; } /* include the dump parts ... in order to get a more sane splitting */ extern void udf_dump_descriptor(union dscrptr *dscrpt); extern void udf_dump_alive_sets(void); extern void udf_dump_root_dir(struct udf_mountpoint *mountpoint); extern void udf_dump_discinfo(struct udf_discinfo *disc); /* globals */ extern int udf_verbose; extern int uscsilib_verbose; /* UDF library dependencies for writing */ int udf_add_session_to_discinfo(struct udf_discinfo *disc, int session, struct anchor_vdp *avdp, int error); int udf_stop_writing_threads(struct udf_discinfo *disc); int udf_get_volumeset_space(struct udf_discinfo *disc); #ifndef MAX #define MAX(a,b) ((a)>(b)?(a):(b)) #define MIN(a,b) ((a)<(b)?(a):(b)) #endif /* * newfs * * Simple-UDF-disc-types recognized by this newfs program : */ #define DISC_TYPE_NORMAL 0 #define DISC_TYPE_VIRTUAL 1 #define DISC_TYPE_SPARABLE 2 #define DISC_TYPE_META 3 void newfs_test_callback(int reason, struct udf_wrcallback *wrcallback, int error, uint8_t *sectordata) { #if 0 DEBUG( printf("WRcallback called with sector data %p\n", sectordata); printf("\treason %d\n", reason); printf("\toffset %08d\n", (int) wrcallback->offset); printf("\tlb_num %08d\n", (int) wrcallback->lb_num); printf("\tlength %08d\n", (int) wrcallback->length); printf("\terror %d\n", (int) error); ); #else reason = reason; wrcallback = wrcallback; sectordata = sectordata; #endif if (error) { fprintf(stderr, "HELP! got writing error while writing; can't fix yet! (%s)\n", strerror(error)); return; } } void writeout_vds(struct udf_session *udf_session, uint16_t dscr_ver) { struct udf_wrcallback wrcallback; struct vrs_desc *vrs_desc; uint32_t pos, sector_size, dpos; uint32_t cnt; sector_size = udf_session->disc->sector_size; wrcallback.function = newfs_test_callback; /* Build ISO/Ecma-167 volume recognition sequence */ vrs_desc = calloc(1, 64*1024); assert(vrs_desc); /* working copy of one max sized ISO descriptor */ /* white out VRS */ pos = ((32*1024 + sector_size - 1) / sector_size); /* definition: first sector AFTER 32kb, minimum sector size 2048 */ dpos = (2048 + sector_size - 1) / sector_size; for (cnt = 0; cnt < 6*dpos; cnt++) { udf_write_session_sector(udf_session, pos + cnt, "blank VRS", (uint8_t *) vrs_desc, 0, &wrcallback); } /* write out VRS */ vrs_desc->struct_type = 0; vrs_desc->version = 1; pos = ((32*1024 + sector_size - 1) / sector_size); /* definition: first sector AFTER 32kb + descr*2048 */ #if 0 /* CD001 identifies bridge disc with ISO 9660 */ memcpy(vrs_desc->identifier, VRS_CD001, 5); udf_write_session_sector(udf_session, pos, "VRS CD001", (uint8_t *) vrs_desc, 0, &wrcallback); pos += dpos; #else memcpy(vrs_desc->identifier, VRS_BEA01, 5); udf_write_session_sector(udf_session, pos, "VRS BEA01", (uint8_t *) vrs_desc, 0, &wrcallback); pos += dpos; #endif if (dscr_ver == 2) { memcpy(vrs_desc->identifier, VRS_NSR02, 5); } else { memcpy(vrs_desc->identifier, VRS_NSR03, 5); } udf_write_session_sector(udf_session, pos, "VRS NSR[23]", (uint8_t *) vrs_desc, 0, &wrcallback); pos += dpos; memcpy(vrs_desc->identifier, VRS_TEA01, 5); udf_write_session_sector(udf_session, pos, "VRS TEA01", (uint8_t *) vrs_desc, 0, &wrcallback); pos += dpos; /* followed by at least one blank block blanked up */ free(vrs_desc); } /* * newfs_udf creates a new UDF filingsystem on a formatted disc. It is * restricted for now only create `simple' i.e. UDF specification discs. * * For now, only CD-RW/DVD+RW filingsystems are implemented. * * FIXME we ought to determine UDF version numbers in advance so it can * easiliy be incorporated when nessisary. * * XXX allocation of space could be done smarter XXX */ void newfs_udf(struct udf_discinfo *disc, uint16_t dscr_ver, char *volset_name, char *privol_name, char *logvol_name, int vds_num, int max_vol_seq, uint32_t lb_mult, int udf_type) { struct long_ad *fsd_loc; struct pri_vol_desc *primary; struct anchor_vdp *anchor; struct desc_tag *terminator; struct part_desc *partition; struct logvol_desc *logvol; struct unalloc_sp_desc *unallocsp; struct impvol_desc *implvol; struct space_bitmap_desc *unalloc_space_bitmap_descr; struct fileset_desc *fileset; struct udf_session *udf_session; struct udf_pri_vol *udf_pri_vol; struct udf_log_vol *udf_log_vol; struct udf_partition *udf_partition; struct udf_mountpoint *udf_mountpoint; struct udf_node *root_node, *dummy_node; struct udf_allocentry *dscr_entry; struct udf_wrcallback wrcallback; uint32_t bits; uint32_t bytes; uint32_t offset, pos, sector_size, lb_size; uint32_t anchor0, anchor1, anchor2, anchor2_rel; uint32_t lvd_length, lvd1_area, lvd2_area, end_lvd; uint32_t part_start, part_length, integrity_start, integrity_length; uint32_t unalloc_space_bitmap, space_bitmap_size; uint32_t start_lb_fsd, num_lbs_fsd; uint16_t serial, *udfver_pos, vpart_fsd; uint8_t *blank; uint32_t cnt; int error; if (!disc->recordable) { fprintf(stderr, "Can't create filingsystem on a non recordable disc\n"); return; } if (disc->sequential) { /* for sequential discs, close last track when nessisary */ fprintf(stderr, "No support yet for creating filingsystem on sequential recordables\n"); /* TODO recordable format */ return; } if (!disc->sequential && !disc->rewritable) { /* non sequential WORM; not tested, no specimen */ fprintf(stderr, "No support yet for non-sequential WORM devices\n"); /* TODO non sequential WORM format */ return; } /* TODO reuse parts of rewritable formatting for other types */ if (disc->rewritable) { /* plain rewritable CD-RW or DVD+RW/DVD-RW, file etc. */ switch (disc->disc_state) { case DISC_STATE_EMPTY: fprintf(stderr, "Disc is empty; please packet-format it before use\n"); return; default: case DISC_STATE_INCOMPLETE : fprintf(stderr, "Disc is not properly formatted; its interrupted at formatting time\n"); return; case DISC_STATE_FULL : case DISC_STATE_NOT_SERIAL : /* OK */ break; } if (udf_discinfo_is_cd_or_dvd(disc) && disc->last_session_state != SESSION_STATE_COMPLETE) { fprintf(stderr, "Disc is marked being not serial, full, but the last session is not marked closed; Most likely formatting problem, try formatting it again\n"); return; } if (disc->num_sessions > 1) { fprintf(stderr, "Can't handle multiple session rewritable discs yet\n"); return; } /* rewritable format */ printf("Creating a filingsystem on a recordable rewritable CD-RW or DVD+RW/DVD-RW or fixed length file\n"); /* initialse statics */ bzero(&wrcallback, sizeof(struct udf_wrcallback)); STAILQ_INIT(&disc->sessions); wrcallback.function = newfs_test_callback; /* NULL for no callbacks */ /* XXX wrcallback.structure = (void *) 0xdeadbeef; */ /* setup recording */ disc->udf_recording = 1; udf_discinfo_set_recording_parameters(disc, 0); /* Set up disc space and create decscriptors */ sector_size = disc->sector_size; lb_size = sector_size * lb_mult; /* express logical blocks as given multiple; normally 1 */ blank = calloc(1, lb_size); assert(blank); /* note that session_end[0] is the first sector NOT adressable so substract one */ serial = 0; /* primary starts at zero */ offset = 256; /* first offset at sector number 256 to allow for prepending loader etc. (use 512 for recordables) */ anchor0 = offset; anchor1 = disc->session_end[0] - 1; /* only one session on rewritables */ anchor2 = disc->session_end[0] - 256 - 1; /* possible anchor, rather not use it on rewritables without sparables... */ lvd_length = MAX(UDF_READWRITE_LINE_LENGTH, disc->packet_size[0]); lvd1_area = anchor0 + 1; lvd2_area = lvd1_area + lvd_length; end_lvd = lvd2_area + lvd_length; /* insert logical volume integrity sequence space if there is a logical volume */ integrity_start = 0; integrity_length = 0; if (logvol_name) { /* * Maybe the space is a bit biggish but it means that * 2 packet sized blocks can be scratched before the * media needs to be reformatted. Minimum a line * length to prevent multiple integrity descriptor * writes to mess up other disc info. */ integrity_start = end_lvd; integrity_length = MAX(UDF_READWRITE_LINE_LENGTH, 2*disc->packet_size[0]); assert(integrity_length * lb_size >= 8*1024); /* UDF req. */ end_lvd += integrity_length; } /* initial start of physical partion space */ part_start = end_lvd; /* partition size can be relative on anchor1 or anchor2; if on anchor1, anchor2 needs to be allocated */ part_length = (sector_size * (uint64_t) (anchor2 - part_start)) / lb_size - 1; /* reserve space for unallocated space bitmap */ bits = part_length; bytes = (bits + 7)/8; space_bitmap_size = (bytes + sizeof(struct space_bitmap_desc)-1); /* round space bitmap size to sector size */ /* FIXME: space bitmap recording on disc sector sizes or on lb_sizes? */ space_bitmap_size = ((space_bitmap_size + lb_size - 1) / lb_size) * lb_size; /* sanity check to see if it can be formatted */ if ((part_length <= 0) || (anchor1 <= 576)) { /* XXX for now XXX */ fprintf(stderr, "Too small a disc to be formatted with the UDF filingsystem\n"); return; } /* build the anchors */ error = udf_create_empty_anchor_volume_descriptor(sector_size, dscr_ver, lvd1_area, lvd2_area, lvd_length, &anchor); /* get udf_session structure */ assert(disc->num_sessions == 1); udf_add_session_to_discinfo(disc, 0, anchor, 0); /* inits complete session related structures */ udf_session = STAILQ_FIRST(&disc->sessions); assert(udf_session); /* create primary and partition descriptor */ unalloc_space_bitmap = 0; /* allocate it at the start */ error = udf_create_empty_primary_volume_descriptor(sector_size, dscr_ver, serial++, volset_name, privol_name, vds_num, max_vol_seq, &primary); error = udf_create_empty_partition_descriptor(sector_size, dscr_ver, serial++, 0, UDF_ACCESSTYPE_OVERWRITABLE, part_start, part_length, space_bitmap_size, unalloc_space_bitmap, &partition); /* process primary and partition */ udf_proc_pri_vol(udf_session, &udf_pri_vol, primary); udf_proc_part(udf_pri_vol, &udf_partition, partition); /* all space in the partition is marked `free' at start */ udf_mark_allocentry_queue(&udf_partition->unalloc_space_queue, lb_size, 0, (uint64_t) part_length * lb_size, UDF_SPACE_FREE, NULL, NULL); udf_partition->free_unalloc_space = (uint64_t) part_length * lb_size; /* create unallocated space descriptor and fill in its use in the partition space */ /* (could be done a bit smarter) */ error = udf_create_empty_space_bitmap(lb_size, dscr_ver, part_length, &unalloc_space_bitmap_descr); udf_partition->unalloc_space_bitmap = unalloc_space_bitmap_descr; udf_mark_allocentry_queue(&udf_partition->unalloc_space_queue, lb_size, (uint64_t) unalloc_space_bitmap * lb_size, space_bitmap_size, UDF_SPACE_ALLOCATED, NULL, NULL); udf_partition->free_unalloc_space -= space_bitmap_size; anchor2_rel = (anchor2*sector_size - part_start*sector_size) / lb_size; if (0) { if (anchor2_rel <= part_length) { /* overlap with anchor2 -> mark it in the unallocated space DESCRIPTOR, not in the unallocated space bitmap */ udf_mark_allocentry_queue(&udf_partition->unalloc_space_queue, lb_size, (uint64_t) anchor2_rel * lb_size, lb_size, UDF_SPACE_ALLOCATED, NULL, NULL); udf_partition->free_unalloc_space -= lb_size; } } printf("Free unallocated space on this volume %"PRIu64"\n", udf_partition->free_unalloc_space); /* sync unallocated space descriptor (will be updated later?) */ udf_sync_space_bitmap(&udf_partition->unalloc_space_queue, unalloc_space_bitmap_descr, lb_size); UDF_VERBOSE_MAX(udf_validate_tag_and_crc_sums((union dscrptr *) unalloc_space_bitmap_descr); udf_dump_descriptor((union dscrptr *) unalloc_space_bitmap_descr)); /* proceed with the other descriptors */ /* FIXME: space bitmap recording on disc sector sizes or on lb_sizes? */ error = udf_create_empty_unallocated_space_descriptor(sector_size, dscr_ver, serial++, &unallocsp); if (logvol_name) { /* wipe logical volume integrity descriptor sequence and `double check' ? */ for (cnt = 0; cnt < integrity_length; cnt++) { udf_write_session_sector(udf_session, integrity_start + cnt, "blank", (uint8_t *) blank, 0, &wrcallback); } /* create logical volume */ error = udf_create_empty_implementation_use_volume_descriptor(sector_size, dscr_ver, serial++, logvol_name, &implvol); assert(!error); error = udf_create_empty_logical_volume_descriptor(sector_size, dscr_ver, serial++, logvol_name, lb_size, integrity_start, integrity_length, &logvol); assert(!error); /* add partition mappings */ switch (udf_type) { default : case DISC_TYPE_NORMAL : /* add `normal' physical partition mapping */ udf_add_physical_to_logvol(logvol, 1, 0); break; case DISC_TYPE_VIRTUAL : /* XXX virtual on a cd-rw/dvd+rw? XXX */ udf_add_physical_to_logvol(logvol, 0, 0); /* udf_add_virtual_to_logvol( logvol, 1, 0); */ break; case DISC_TYPE_SPARABLE : /* udf_add_sparable_to_logvol(logvol, 0, 0); */ break; case DISC_TYPE_META : printf("No supported format type meta\n"); break; } udf_log_vol = NULL; udf_proc_log_vol(udf_pri_vol, &udf_log_vol, logvol); udf_derive_new_logvol_integrity(udf_log_vol); } /* and finish the sequence */ error = udf_create_empty_terminator_descriptor(sector_size, dscr_ver, &terminator); if (logvol_name) { /* allocate space for the filesets descriptor sequence */ error = udf_allocate_lbs(udf_log_vol, UDF_C_DSCR, /* length */ 1, "Fileset sequence", &vpart_fsd, &start_lb_fsd, &num_lbs_fsd); DEBUG(printf("DEBUG: fsd op lbnum %d, vpart %d\n", start_lb_fsd, vpart_fsd)); fsd_loc = &logvol->_lvd_use.fsd_loc; fsd_loc->len = udf_rw32(num_lbs_fsd * lb_size); fsd_loc->loc.lb_num = udf_rw32(start_lb_fsd); fsd_loc->loc.part_num = udf_rw16(vpart_fsd); /* create fileset(s) */ error = udf_create_empty_fileset_desc(lb_size, dscr_ver, /*filesetnr*/ 0, logvol_name, "fileset", &fileset); assert(fileset); udf_proc_filesetdesc(udf_log_vol, fileset); /* create empty root-dir node */ udf_mountpoint = SLIST_FIRST(&udf_mountables); udf_init_udf_node(udf_mountpoint, udf_log_vol, "Root", &root_node); udf_allocate_udf_node_on_disc(root_node); root_node->stat.st_size = 0; root_node->stat.st_blksize = root_node->udf_log_vol->lb_size; root_node->stat.st_blocks = 0; root_node->stat.st_mode = 0777 | S_IFDIR; root_node->udf_filetype = UDF_ICB_FILETYPE_DIRECTORY; root_node->unique_id = 0; /* UDF 2.3.6.5, 3.2.1.1. */ root_node->udf_log_vol->num_directories++; udf_insert_node_in_hash(root_node); udf_node_mark_dirty(root_node); /* note creation times */ #ifndef NO_STAT_BIRTHTIME udf_set_timespec_now(&root_node->stat.st_birthtimespec); #endif udf_set_timespec_now(&root_node->stat.st_atimespec); udf_set_timespec_now(&root_node->stat.st_ctimespec); udf_set_timespec_now(&root_node->stat.st_mtimespec); dscr_entry = TAILQ_FIRST(&root_node->dscr_allocs); fileset->rootdir_icb.loc.lb_num = udf_rw32(dscr_entry->lb_num); fileset->rootdir_icb.loc.part_num = udf_rw16(dscr_entry->vpart_num); fileset->rootdir_icb.len = udf_rw32(lb_size); /* FIXME type 4096? */ /* set all to writable or we're in trouble here */ udf_log_vol->logvol_state = UDF_INTEGRITY_OPEN; udf_log_vol->writable = 1; udf_mountpoint->writable = 1; /* create `..' directory entry; hardlinks have no stat */ error = udf_create_directory_entry(root_node, "..", UDF_ICB_FILETYPE_DIRECTORY, UDF_FILE_CHAR_DIR | UDF_FILE_CHAR_PAR, root_node, NULL, &dummy_node); assert(error == 0); /* adjust reference count for `root' since '..' points to it too but is not considered a link (ECMA 4/14.9.6, 4/8.8.3) */ root_node->link_cnt--; } /* set all UDF version numbers to one and the same version */ if (logvol_name) { /* Implementation use volume descritor's UDF version must be the same as the logical volume's UDF version it describes */ /* update/fill in the UDF version chosen */ udfver_pos = (uint16_t *) logvol->domain_id.id_suffix; *udfver_pos = udf_rw16(udf_log_vol->min_udf_writever); udfver_pos = (uint16_t *) implvol->impl_id.id_suffix; *udfver_pos = udf_rw16(udf_log_vol->min_udf_writever); /* FIXME only one fileset now */ udfver_pos = (uint16_t *) fileset->domain_id.id_suffix; *udfver_pos = udf_rw16(udf_log_vol->min_udf_writever); } /* Start to WRITE OUT data VRS and UDF structures */ writeout_vds(udf_session, dscr_ver); /* start writeout UDF structures */ #if 0 /* wipe space around anchor2 */ for (cnt=-20; cnt < 21; cnt++) { udf_write_session_sector(udf_session, anchor2 + cnt, "blank", (uint8_t *) blank, 0, &wrcallback); } #endif udf_write_session_descriptor(udf_session, anchor0, "Anchor", (union dscrptr*) anchor, &wrcallback); udf_write_session_descriptor(udf_session, anchor1, "Anchor", (union dscrptr*) anchor, &wrcallback); udf_write_session_descriptor(udf_session, anchor2, "Anchor", (union dscrptr*) anchor, &wrcallback); /* writeout volume space */ pos = lvd1_area; udf_write_session_descriptor(udf_session, pos++, "Primary", (union dscrptr*) primary, &wrcallback); udf_write_session_descriptor(udf_session, pos++, "Partiton", (union dscrptr*) partition, &wrcallback); udf_write_session_descriptor(udf_session, pos++, "Unalloc space", (union dscrptr*) unallocsp, &wrcallback); if (logvol_name) { udf_write_session_descriptor(udf_session, pos++, "Logvol", (union dscrptr*) logvol, &wrcallback); udf_write_session_descriptor(udf_session, pos++, "Impl. volume", (union dscrptr*) implvol, &wrcallback); } udf_write_session_descriptor(udf_session, pos++, "Terminator", (union dscrptr*) terminator, &wrcallback); pos = lvd2_area; udf_write_session_descriptor(udf_session, pos++, "Primary", (union dscrptr*) primary, &wrcallback); udf_write_session_descriptor(udf_session, pos++, "Partiton", (union dscrptr*) partition, &wrcallback); udf_write_session_descriptor(udf_session, pos++, "Unalloc space", (union dscrptr*) unallocsp, &wrcallback); if (logvol_name) { udf_write_session_descriptor(udf_session, pos++, "Logvol", (union dscrptr*) logvol, &wrcallback); udf_write_session_descriptor(udf_session, pos++, "Impl. volume", (union dscrptr*) implvol, &wrcallback); } udf_write_session_descriptor(udf_session, pos++, "Terminator", (union dscrptr*) terminator, &wrcallback); /* the unallocated space bitmap gets written out on sync/dismount */ if (logvol_name) { udf_write_logvol_descriptor(udf_log_vol, vpart_fsd, start_lb_fsd, "File set", (union dscrptr*) fileset, &wrcallback); } return; } /* * If we reach here, we obviously missed a class of recording devices, * better give a error and abort */ fprintf(stderr, "Internal error: unknown recording class of devices encountered; aborting\n"); return; } int usage(char *program) { fprintf(stderr, "Usage %s [options] devicename\n", program); fprintf(stderr, "Creates a filingsystem on file or a formatted disc\n"); fprintf(stderr, "-S volsetname use `volsetname as volume set name'\n" "-P primaryname use `primaryname' as primary volume name\n" "-L volumename use `volumename' as logical volume name (discname)\n" "-v volumenumber when part of a set use this volumenumber\n" "-m volumenumber maximum volumenumber in this set\n" "-2 alter descriptor version number (default 3)\n" "-s numsect create image with number of sectors (file only)\n" "-b blocksize use alternative sectorsize; use only on files/discs\n" "-B mult multiplier for logical sectors (NON-standard!!)\n" "-u level UDF system verbose level\n" "-D debug/verbose SCSI command errors\n" ); fprintf(stderr, "use `dd if=/dev/zero bs=64k of=discimage.cd count=...` to create a new discfile. `count` must be >= 19 (about 1.2Mb)\n"); fprintf(stderr, "or use the `-b' and `-s' flags to create a new discfile. blocksize needs to be a multiple of 512\n"); return 1; } int main(int argc, char *argv[]) { struct timeval time_of_day; struct udf_discinfo *disc; char *progname, *volset_name, *privol_name, *logvol_name; uint64_t volset_nr; uint32_t vds_num, max_vol_seq, dscr_ver; uint32_t alt_sector_size, alt_num_sect, lb_mult; off_t fsize; int flag, error, fhandle; progname = argv[0]; if (argc == 1) return usage(progname); volset_name = NULL; privol_name = NULL; logvol_name = NULL; vds_num = 1; max_vol_seq = 1; dscr_ver = 3; alt_sector_size = 0; alt_num_sect = 0; lb_mult = 1; while ((flag = getopt(argc, argv, "S:P:L:v:m:2s:b:B:u:D")) != -1) { switch (flag) { case 'S' : volset_name = strdup(optarg); break; case 'P' : privol_name = strdup(optarg); break; case 'L' : logvol_name = strdup(optarg); break; case 'v' : vds_num = atoi(optarg); break; case 'm' : max_vol_seq = atoi(optarg); break; case '2' : dscr_ver = 2; break; case 's' : alt_num_sect = atoi(optarg); break; case 'b' : alt_sector_size = atoi(optarg); break; case 'B' : printf("-B option to set logvol multiplier temporarely disabled\n"); /* lb_mult = atoi(optarg); */ break; case 'u' : udf_verbose = atoi(optarg); break; case 'D' : uscsilib_verbose = 1; break; default : return usage(progname); } } argv += optind; argc -= optind; if (argc < 1) return usage(progname); srandom(time(NULL)); if (!volset_name) { volset_name = malloc(128); (void)gettimeofday(&time_of_day, NULL); volset_nr = (uint64_t) random(); volset_nr |= ((uint64_t) time_of_day.tv_sec) << 32; sprintf(volset_name, "%0"PRIx64, volset_nr); } if (!privol_name) { privol_name = malloc(32); sprintf(privol_name, "%08lx", random()); } if (!logvol_name) { fprintf(stderr, "newfs_udf: no logical volume name passed; not creating logical volume descriptor\nYOU PROLLY DONT WANT THIS\n"); } if ((vds_num < 1) || (vds_num > max_vol_seq)) { fprintf(stderr, "Invalid volume seqence number or out of bounds\n"); return 1; } if ((dscr_ver < 2) || (dscr_ver > 3)) { fprintf(stderr," UDF upto version 2.50 only supports descriptor versions 2 and 3\n"); return 1; } /* just one device allowed */ SLIST_INIT(&udf_discs_list); printf("Opening device %s\n\n", *argv); error = udf_open_disc(*argv, /* discop_flags */ 0, &disc); if (error) { error = 0; if ((alt_num_sect > 0) && (alt_sector_size > 0)) { /* create a file */ fprintf(stderr, "Creating new disc image\n"); fsize = (off_t) alt_num_sect * alt_sector_size; fhandle = open(*argv, O_CREAT | O_TRUNC | O_RDWR, 0660); if (fhandle) { fsize = ftruncate(fhandle, fsize); if (fsize < 0) error = errno; close(fhandle); } else { error = errno; } } if (!error) { error = udf_open_disc(*argv, /* discop_flags */ 0, &disc); } if (error) { fprintf(stderr, "Can't open my device; bailing out : %s\n", strerror(error)); exit(1); } } SLIST_INSERT_HEAD(&udf_discs_list, disc, next_disc); /* better add it to the disc list */ /* try to set the alternative sector size */ if (alt_sector_size || alt_num_sect) { error = udf_discinfo_alter_perception(disc, alt_sector_size, alt_num_sect); if (error) { exit(0); } } udf_unix_init(); udf_start_unix_thread(); printf("\n\n"); udf_dump_discinfo(disc); /* now do the real thing */ newfs_udf(disc, dscr_ver, volset_name, privol_name, logvol_name, vds_num, max_vol_seq, lb_mult, DISC_TYPE_NORMAL); printf("Closing disc\n"); udf_dismount_disc(disc); return 0; } UDFclient.0.8.8/Makefile.in010066400001470000000000000034601307041407400147350ustar reinoudwheel# # UDFclient toolkit # # Copyright 2003,2004,2005 Reinoud P.Zandijk # # # File $Id: Makefile.in,v 1.24 2017/01/10 09:52:30 reinoud Exp $ $Name: $ # srcdir= @srcdir@ prefix= @prefix@ exec_prefix= @exec_prefix@ sbindir= @sbindir@ mandir= @mandir@ bindir= @bindir@ datarootdir= @datarootdir@ CC= @CC@ LD= $(CC) CPPFLAGS= @CPPFLAGS@ @DEFS@ -I$(srcdir) CFLAGS= @CFLAGS@ LDFLAGS= @LDFLAGS@ INSTALL= @INSTALL@ # NetBSD #CFLAGS+= -Wall \ # -Wuninitialized \ # -fno-strict-aliasing \ # -Wextra -Werror # -Werror ${COPTS} \ # -DNDEBUG # Anonymising this client (for comformity) #CFLAGS+= -D__ANONYMOUSUDF__ #CFLAGS+= -fPIC -DPIC POSTOBJ+= @SCSI_LIB@ @THREADLIB@ @TIMELIB@ # For use with the cpuflags package #CPROCFLAGS != cpuflags CFLAGS+= ${CPROCFLAGS} # Main programs APPS= udfdump udfclient newfs_udf cd_sessions SCSI_APPS= cd_disect mmc_format LIB= osta.o udf.o udf_bmap.o udf_allocentries.o udf_discop.o uio.o LIB+= udf_verbose.o udf_readwrite.o udf_unix.o vfs_dirhash.o USCSILIB= uscsi_sense.o uscsi_subr.o CFLAGS+= -DNEEDS_ISPRINT $(CPPFLAGS) all: @BUILD_APPS@ install: @BUILD_APPS@ $(INSTALL) -d $(DESTDIR)/$(bindir) for app in @BUILD_APPS@; do \ echo "$(INSTALL) $$app $(DESTDIR)/$(bindir)/$$app"; \ $(INSTALL) $$app $(DESTDIR)/$(bindir)/$$app; \ done depend: mkdep $(CFLAGS) *.c clean: rm -f *.o *.a *.core core.* core .depend *~ *.bak $(APPS) $(SCSI_APPS) rm -fr autom*.cache config.log config.status configure.lineno cleandir: clean rm -f Makefile libuscsi.a: $(USCSILIB) ar -rsc libuscsi.a $(USCSILIB) libudf.a: $(LIB) ar -rsc libudf.a $(LIB) $(SCSI_APPS): $(.TARGET).o libuscsi.a $(LD) -o $(.TARGET) $(LDFLAGS) $(.TARGET).o libuscsi.a $(POSTOBJ) $(APPS): $(.TARGET).o libuscsi.a libudf.a $(LD) -o $(.TARGET) $(LDFLAGS) $(.TARGET).o libudf.a libuscsi.a $(POSTOBJ) # DO NOT DELETE UDFclient.0.8.8/uscsilib.h010064400001470000000000000076471307041400500146610ustar reinoudwheel/* $NetBSD: extern.h,v 1.4 2002/06/26 16:04:11 mjacob Exp $ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Small changes made by Reinoud Zandijk * */ #ifndef _SCSILIB_H_ #define _SCSILIB_H_ #define SCSI_CMD_LEN 12 typedef unsigned char scsicmd[SCSI_CMD_LEN]; #include "defs.h" #include "uscsilib_machdep.h" extern int uscsilib_verbose; /* * Unified structure copied and modified from NetBSD's for ease */ struct uscsi_addr { int type; /* bus type */ #define USCSI_TYPE_SCSI 0 #define USCSI_TYPE_ATAPI 1 #define USCSI_TYPE_UNKNOWN 2 union { struct { int scbus; /* -1 if wildcard */ int target; /* -1 if wildcard */ int lun; /* -1 if wildcard */ } scsi; struct { int atbus; /* -1 if wildcard */ int drive; /* -1 if wildcard */ } atapi; } addr; }; struct uscsi_sense { int asc; /* Additional sense code */ int ascq; /* Additional sense code quality */ int skey_valid; /* sense key valid */ int sense_key; /* sense key; interpret on (asc, ascq) pair */ }; struct uscsi_dev { char *dev_name; int fhandle; void *devhandle; /* for if a fhandle is not enough */ }; /* uscsi_sense.c */ extern char *uscsi_decode_sense(void *sinfo, int flag); extern void uscsi_print_sense(const char *name, u_char *req_cmd, int req_cmdlen, u_char *req_sense, int req_senselen_used, int verbosity); /* scsi_subr.c */ extern int uscsi_open(struct uscsi_dev *); extern int uscsi_close(struct uscsi_dev *); extern int uscsi_command(int flags, struct uscsi_dev *disc, void *cmd, size_t cmdlen, void *data, size_t datalen, uint32_t timeout, struct uscsi_sense *uscsi_sense); extern int uscsi_check_for_scsi(struct uscsi_dev *); extern int uscsi_identify(struct uscsi_dev *, struct uscsi_addr *saddr); extern int uscsi_mode_sense(struct uscsi_dev *, u_int8_t, u_int8_t, void *, size_t); extern int uscsi_mode_select(struct uscsi_dev *, u_int8_t, void *, size_t); extern int uscsi_request_sense(struct uscsi_dev *, void *, size_t); #endif /* _SCSILIB_H_ */ UDFclient.0.8.8/ecma167-udf.h010064400001470000000000000536601307041400500147570ustar reinoudwheel/* $NetBSD: ecma167-udf.h,v 1.5 2006/10/22 00:06:48 reinoud Exp $ */ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2011 * Reinoud Zandijk * Copyright (c) 2001, 2002 Scott Long * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Extended and adapted for UDFv2.50+ bij Reinoud Zandijk based on the * origional by Scott Long. * * 20030508 Made some small typo and explainatory comments * 20030510 Added UDF 2.01 structures * 20030519 Added/correct comments on multi-partitioned logical volume space * 20050616 Added pseudo overwrite * 20050624 Added the missing extended attribute types and `magic values'. * 20051106 Reworked some implementation use parts * */ #ifndef _FS_UDF_ECMA167_UDF_H_ #define _FS_UDF_ECMA167_UDF_H_ /* * in case of an older gcc versions, define the __packed as explicit * attribute */ /* * You may specify the `aligned' and `transparent_union' attributes either in * a `typedef' declaration or just past the closing curly brace of a complete * enum, struct or union type _definition_ and the `packed' attribute only * past the closing brace of a definition. You may also specify attributes * between the enum, struct or union tag and the name of the type rather than * after the closing brace. */ #if 1 #ifndef __packed #define __packed __attribute__((packed)) #endif #endif /* ecma167-udf.h */ /* Volume recognition sequence ECMA 167 rev. 3 16.1 */ struct vrs_desc { uint8_t struct_type; uint8_t identifier[5]; uint8_t version; uint8_t data[2041]; } __packed; #define VRS_NSR02 "NSR02" #define VRS_NSR03 "NSR03" #define VRS_BEA01 "BEA01" #define VRS_TEA01 "TEA01" #define VRS_CD001 "CD001" #define VRS_CDW02 "CDW02" /* Structure/definitions/constants a la ECMA 167 rev. 3 */ #define MAX_TAGID_VOLUMES 9 /* Tag identifiers */ enum { TAGID_SPARING_TABLE = 0, TAGID_PRI_VOL = 1, TAGID_ANCHOR = 2, TAGID_VOL = 3, TAGID_IMP_VOL = 4, TAGID_PARTITION = 5, TAGID_LOGVOL = 6, TAGID_UNALLOC_SPACE = 7, TAGID_TERM = 8, TAGID_LOGVOL_INTEGRITY= 9, TAGID_FSD = 256, TAGID_FID = 257, TAGID_ALLOCEXTENT = 258, TAGID_INDIRECT_ENTRY = 259, TAGID_ICB_TERM = 260, TAGID_FENTRY = 261, TAGID_EXTATTR_HDR = 262, TAGID_UNALL_SP_ENTRY = 263, TAGID_SPACE_BITMAP = 264, TAGID_PART_INTEGRETY = 265, TAGID_EXTFENTRY = 266, TAGID_MAX = 266 }; enum { UDF_DOMAIN_FLAG_HARD_WRITE_PROTECT = 1, UDF_DOMAIN_FLAG_SOFT_WRITE_PROTECT = 2 }; enum { UDF_ACCESSTYPE_NOT_SPECIFIED = 0, /* unknown */ UDF_ACCESSTYPE_PSEUDO_OVERWITE = 0, /* Pseudo overwritable, f.e. BD-R's LOW */ UDF_ACCESSTYPE_READ_ONLY = 1, /* really only readable */ UDF_ACCESSTYPE_WRITE_ONCE = 2, /* write once and you're done */ UDF_ACCESSTYPE_REWRITEABLE = 3, /* may need extra work to rewrite */ UDF_ACCESSTYPE_OVERWRITABLE = 4 /* no limits on rewriting; harddisc f.e.*/ }; /* Descriptor tag [3/7.2] */ struct desc_tag { uint16_t id; uint16_t descriptor_ver; uint8_t cksum; uint8_t reserved; uint16_t serial_num; uint16_t desc_crc; uint16_t desc_crc_len; uint32_t tag_loc; } __packed; #define UDF_DESC_TAG_LENGTH 16 /* Recorded Address [4/7.1] */ struct lb_addr { /* within partition space */ uint32_t lb_num; uint16_t part_num; } __packed; /* Extent Descriptor [3/7.1] */ struct extent_ad { uint32_t len; uint32_t loc; } __packed; /* Short Allocation Descriptor [4/14.14.1] */ struct short_ad { uint32_t len; uint32_t lb_num; } __packed; /* Long Allocation Descriptor [4/14.14.2] */ struct UDF_ADImp_use { uint16_t flags; uint32_t unique_id; } __packed; #define UDF_ADIMP_FLAGS_EXTENT_ERASED 1 struct long_ad { uint32_t len; struct lb_addr loc; /* within a logical volume mapped partition space !! */ union { uint8_t bytes[6]; struct UDF_ADImp_use im_used; } impl; } __packed; #define longad_uniqueid impl.im_used.unique_id /* Extended Allocation Descriptor [4/14.14.3] ; identifies an extent of allocation descriptors ; also in UDF ? */ struct ext_ad { uint32_t ex_len; uint32_t rec_len; uint32_t inf_len; struct lb_addr ex_loc; uint8_t reserved[2]; } __packed; /* ICB : Information Control Block; positioning */ union icb { struct short_ad s_ad; struct long_ad l_ad; struct ext_ad e_ad; }; /* short/long/ext extent have flags encoded in length */ #define UDF_EXT_ALLOCATED (0<<30) #define UDF_EXT_FREED (1<<30) #define UDF_EXT_ALLOCATED_BUT_NOT_USED (1<<30) #define UDF_EXT_FREE (2<<30) #define UDF_EXT_REDIRECT (3<<30) #define UDF_EXT_FLAGS(len) ((len) & (3<<30)) #define UDF_EXT_LEN(len) ((len) & ((1<<30)-1)) /* Character set spec [1/7.2.1] */ struct charspec { uint8_t type; uint8_t inf[63]; } __packed; struct pathcomp { uint8_t type; uint8_t l_ci; uint16_t comp_filever; uint8_t ident[256]; } __packed; #define UDF_PATH_COMP_SIZE 4 #define UDF_PATH_COMP_RESERVED 0 #define UDF_PATH_COMP_ROOT 1 #define UDF_PATH_COMP_MOUNTROOT 2 #define UDF_PATH_COMP_PARENTDIR 3 #define UDF_PATH_COMP_CURDIR 4 #define UDF_PATH_COMP_NAME 5 /* Timestamp [1/7.3] */ struct timestamp { uint16_t type_tz; uint16_t year; uint8_t month; uint8_t day; uint8_t hour; uint8_t minute; uint8_t second; uint8_t centisec; uint8_t hund_usec; uint8_t usec; } __packed; #define UDF_TIMESTAMP_SIZE 12 /* Entity Identifier [1/7.4] */ #define UDF_REGID_ID_SIZE 23 struct regid { uint8_t flags; uint8_t id[UDF_REGID_ID_SIZE]; uint8_t id_suffix[8]; } __packed; /* ICB Tag [4/14.6] */ struct icb_tag { uint32_t prev_num_dirs; uint16_t strat_type; union { uint8_t strat_param[2]; uint16_t strat_param16; } __packed; uint16_t max_num_entries; uint8_t reserved; uint8_t file_type; struct lb_addr parent_icb; uint16_t flags; } __packed; #define UDF_ICB_TAG_FLAGS_ALLOC_MASK 0x03 #define UDF_ICB_SHORT_ALLOC 0x00 #define UDF_ICB_LONG_ALLOC 0x01 #define UDF_ICB_EXT_ALLOC 0x02 #define UDF_ICB_INTERN_ALLOC 0x03 #define UDF_ICB_TAG_FLAGS_DIRORDERED (1<< 3) #define UDF_ICB_TAG_FLAGS_NONRELOC (1<< 4) #define UDF_ICB_TAG_FLAGS_CONTIGUES (1<< 9) #define UDF_ICB_TAG_FLAGS_MULTIPLEVERS (1<<12) #define UDF_ICB_TAG_FLAGS_SETUID (1<< 6) #define UDF_ICB_TAG_FLAGS_SETGID (1<< 7) #define UDF_ICB_TAG_FLAGS_STICKY (1<< 8) #define UDF_ICB_FILETYPE_UNKNOWN 0 #define UDF_ICB_FILETYPE_UNALLOCSPACE 1 #define UDF_ICB_FILETYPE_PARTINTEGRITY 2 #define UDF_ICB_FILETYPE_INDIRECTENTRY 3 #define UDF_ICB_FILETYPE_DIRECTORY 4 #define UDF_ICB_FILETYPE_RANDOMACCESS 5 #define UDF_ICB_FILETYPE_BLOCKDEVICE 6 #define UDF_ICB_FILETYPE_CHARDEVICE 7 #define UDF_ICB_FILETYPE_EXTATTRREC 8 #define UDF_ICB_FILETYPE_FIFO 9 #define UDF_ICB_FILETYPE_SOCKET 10 #define UDF_ICB_FILETYPE_TERM 11 #define UDF_ICB_FILETYPE_SYMLINK 12 #define UDF_ICB_FILETYPE_STREAMDIR 13 #define UDF_ICB_FILETYPE_VAT 248 #define UDF_ICB_FILETYPE_REALTIME 249 #define UDF_ICB_FILETYPE_META_MAIN 250 #define UDF_ICB_FILETYPE_META_MIRROR 251 #define UDF_ICB_FILETYPE_META_BITMAP 252 /* Anchor Volume Descriptor Pointer [3/10.2] */ struct anchor_vdp { struct desc_tag tag; struct extent_ad main_vds_ex; /* to main volume descriptor set ; 16 sectors min */ struct extent_ad reserve_vds_ex; /* copy of main volume descriptor set ; 16 sectors min */ } __packed; /* Volume Descriptor Pointer [3/10.3] */ struct vol_desc_ptr { struct desc_tag tag; /* use for extending the volume descriptor space */ uint32_t vds_number; struct extent_ad next_vds_ex; /* points to the next block for volume descriptor space */ } __packed; /* Primary Volume Descriptor [3/10.1] */ struct pri_vol_desc { struct desc_tag tag; uint32_t seq_num; /* MAX prevail */ uint32_t pvd_num; /* assigned by author; 0 is special as in it may only occure once */ char vol_id[32]; /* KEY ; main identifier of this disc */ uint16_t vds_num; /* volume descriptor number; i.e. what volume number is it */ uint16_t max_vol_seq; /* maximum volume descriptor number known */ uint16_t ichg_lvl; uint16_t max_ichg_lvl; uint32_t charset_list; uint32_t max_charset_list; char volset_id[128]; /* KEY ; if part of a multi-disc set or a band of volumes */ struct charspec desc_charset; /* KEY according to ECMA 167 */ struct charspec explanatory_charset; struct extent_ad vol_abstract; struct extent_ad vol_copyright; struct regid app_id; struct timestamp time; struct regid imp_id; uint8_t imp_use[64]; uint32_t prev_vds_loc; /* location of predecessor _lov ? */ uint16_t flags; /* bit 0 : if set indicates volume set name is meaningfull */ uint8_t reserved[22]; } __packed; /* UDF specific implementation use part of the implementation use volume descriptor */ struct udf_lv_info { struct charspec lvi_charset; char logvol_id[128]; char lvinfo1[36]; char lvinfo2[36]; char lvinfo3[36]; struct regid impl_id; uint8_t impl_use[128]; } __packed; /* Implementation use Volume Descriptor */ struct impvol_desc { struct desc_tag tag; uint32_t seq_num; struct regid impl_id; union { struct udf_lv_info lv_info; char impl_use[460]; }_impl_use; } __packed; /* Logical Volume Descriptor [3/10.6] */ struct logvol_desc { struct desc_tag tag; uint32_t seq_num; /* MAX prevail */ struct charspec desc_charset; /* KEY */ char logvol_id[128]; /* KEY */ uint32_t lb_size; struct regid domain_id; union { struct long_ad fsd_loc; /* to fileset descriptor SEQUENCE */ uint8_t logvol_content_use[16]; } _lvd_use; uint32_t mt_l; /* Partition map length */ uint32_t n_pm; /* Number of partition maps */ struct regid imp_id; uint8_t imp_use[128]; struct extent_ad integrity_seq_loc; uint8_t maps[1]; } __packed; #define lv_fsd_loc _lvd_use.fsd_loc #define UDF_INTEGRITY_OPEN 0 #define UDF_INTEGRITY_CLOSED 1 #define UDF_PMAP_SIZE 64 /* Type 1 Partition Map [3/10.7.2] */ struct part_map_1 { uint8_t type; uint8_t len; uint16_t vol_seq_num; uint16_t part_num; } __packed; /* Type 2 Partition Map [3/10.7.3] */ struct part_map_2 { uint8_t type; uint8_t len; uint8_t reserved[2]; struct regid part_id; uint16_t vol_seq_num; uint16_t part_num; uint8_t reserved2[24]; } __packed; /* Virtual Partition Map [UDF 2.01/2.2.8] */ struct part_map_virt { uint8_t type; uint8_t len; uint8_t reserved[2]; struct regid id; uint16_t vol_seq_num; uint16_t part_num; uint8_t reserved1[24]; } __packed; /* Sparable Partition Map [UDF 2.01/2.2.9] */ struct part_map_spare { uint8_t type; uint8_t len; uint8_t reserved[2]; struct regid id; uint16_t vol_seq_num; uint16_t part_num; uint16_t packet_len; uint8_t n_st; /* Number of redundant sparing tables range 1-4 */ uint8_t reserved1; uint32_t st_size; /* size of EACH sparing table */ uint32_t st_loc[1]; /* locations of sparing tables */ } __packed; /* Metadata Partition Map [UDF 2.50/2.2.10] */ struct part_map_meta { uint8_t type; uint8_t len; uint8_t reserved[2]; struct regid id; uint16_t vol_seq_num; uint16_t part_num; uint32_t meta_file_lbn; /* logical block number for file entry within part_num */ uint32_t meta_mirror_file_lbn; uint32_t meta_bitmap_file_lbn; uint32_t alloc_unit_size; /* allocation unit size in blocks */ uint16_t alignment_unit_size; /* alignment nessisary in blocks */ uint8_t flags; uint8_t reserved1[5]; } __packed; #define METADATA_DUPLICATED 1 union udf_pmap { uint8_t data[UDF_PMAP_SIZE]; struct part_map_1 pm1; struct part_map_2 pm2; struct part_map_virt pmv; struct part_map_spare pms; struct part_map_meta pmm; }; /* Sparing Map Entry [UDF 2.01/2.2.11] */ struct spare_map_entry { uint32_t org; /* partion relative address */ uint32_t map; /* absolute disc address (!) can be in partion, but doesn't have to be */ } __packed; /* Sparing Table [UDF 2.01/2.2.11] */ struct udf_sparing_table { struct desc_tag tag; struct regid id; uint16_t rt_l; /* Relocation Table len */ uint8_t reserved[2]; uint32_t seq_num; struct spare_map_entry entries[1]; } __packed; #define UDF_NO_PREV_VAT 0xffffffff /* UDF 1.50 VAT suffix [UDF 2.2.10 (UDF 1.50 spec)] */ struct udf_oldvat_tail { struct regid id; /* "*UDF Virtual Alloc Tbl" */ uint32_t prev_vat; } __packed; /* VAT table [UDF 2.0.1/2.2.10] */ struct udf_vat { uint16_t header_len; uint16_t impl_use_len; char logvol_id[128]; /* newer version of the LVD one */ uint32_t prev_vat; uint32_t num_files; uint32_t num_directories; uint16_t min_udf_readver; uint16_t min_udf_writever; uint16_t max_udf_writever; uint16_t reserved; uint8_t data[1]; /* impl.use followed by VAT entries (uint32_t) */ } __packed; /* Space bitmap descriptor as found in the partition header descriptor */ struct space_bitmap_desc { struct desc_tag tag; /* TagId 264 */ uint32_t num_bits; /* number of bits */ uint32_t num_bytes; /* bytes that contain it */ uint8_t data[1]; } __packed; /* Unalloc space entry as found in the partition header descriptor */ struct space_entry_desc { struct desc_tag tag; /* TagId 263 */ struct icb_tag icbtag; /* type 1 */ uint32_t l_ad; /* in bytes */ uint8_t entry[1]; } __packed; /* Partition header descriptor; in the contents_use of part_desc */ struct part_hdr_desc { struct short_ad unalloc_space_table; struct short_ad unalloc_space_bitmap; struct short_ad part_integrity_table; /* has to be ZERO for UDF */ struct short_ad freed_space_table; struct short_ad freed_space_bitmap; uint8_t reserved[88]; } __packed; /* Partition Descriptor [3/10.5] */ struct part_desc { struct desc_tag tag; uint32_t seq_num; /* MAX prevailing */ uint16_t flags; /* bit 0 : if set the space is allocated */ uint16_t part_num; /* KEY */ struct regid contents; union { struct part_hdr_desc part_hdr; uint8_t contents_use[128]; } _impl_use; uint32_t access_type; /* R/W, WORM etc. */ uint32_t start_loc; /* start of partion with given length */ uint32_t part_len; struct regid imp_id; uint8_t imp_use[128]; uint8_t reserved[156]; } __packed; #define pd_part_hdr _impl_use.part_hdr #define UDF_PART_FLAG_ALLOCATED 1 /* Unallocated Space Descriptor (UDF 2.01/2.2.5) */ struct unalloc_sp_desc { struct desc_tag tag; uint32_t seq_num; /* MAX prevailing */ uint32_t alloc_desc_num; struct extent_ad alloc_desc[1]; } __packed; /* Logical Volume Integrity Descriptor [3/30.10] */ struct logvolhdr { uint64_t next_unique_id; /* rest reserved */ } __packed; struct udf_logvol_info { struct regid impl_id; uint32_t num_files; uint32_t num_directories; uint16_t min_udf_readver; uint16_t min_udf_writever; uint16_t max_udf_writever; } __packed; struct logvol_int_desc { struct desc_tag tag; struct timestamp time; uint32_t integrity_type; struct extent_ad next_extent; union { struct logvolhdr logvolhdr; int8_t reserved[32]; } _impl_use; uint32_t num_part; uint32_t l_iu; uint32_t tables[1]; /* Freespace table, Sizetable, Implementation use */ } __packed; #define lvint_next_unique_id _impl_use.logvolhdr.next_unique_id /* File Set Descriptor [4/14.1] */ struct fileset_desc { struct desc_tag tag; struct timestamp time; uint16_t ichg_lvl; uint16_t max_ichg_lvl; uint32_t charset_list; uint32_t max_charset_list; uint32_t fileset_num; /* key! */ uint32_t fileset_desc_num; struct charspec logvol_id_charset; char logvol_id[128]; /* for recovery */ struct charspec fileset_charset; char fileset_id[32]; /* Mountpoint !! */ char copyright_file_id[32]; char abstract_file_id[32]; struct long_ad rootdir_icb; /* to rootdir; icb->virtual ? */ struct regid domain_id; struct long_ad next_ex; /* to the next fileset_desc extent */ struct long_ad streamdir_icb; /* streamdir; needed? */ uint8_t reserved[32]; } __packed; /* File Identifier Descriptor [4/14.4] */ struct fileid_desc { struct desc_tag tag; uint16_t file_version_num; uint8_t file_char; uint8_t l_fi; /* Length of file identifier area */ struct long_ad icb; uint16_t l_iu; /* Length of implementation use area */ uint8_t data[0]; } __packed; #define UDF_FID_SIZE 38 #define UDF_FILE_CHAR_VIS (1 << 0) /* Invisible */ #define UDF_FILE_CHAR_DIR (1 << 1) /* Directory */ #define UDF_FILE_CHAR_DEL (1 << 2) /* Deleted */ #define UDF_FILE_CHAR_PAR (1 << 3) /* Parent Directory */ #define UDF_FILE_CHAR_META (1 << 4) /* Stream metadata */ /* Extended attributes [4/14.10.1] */ struct extattrhdr_desc { struct desc_tag tag; uint32_t impl_attr_loc; /* offsets within this descriptor */ uint32_t appl_attr_loc; /* ditto */ } __packed; #define UDF_IMPL_ATTR_LOC_NOT_PRESENT 0xffffffff #define UDF_APPL_ATTR_LOC_NOT_PRESENT 0xffffffff /* Extended attribute entry [4/48.10.2] */ struct extattr_entry { uint32_t type; uint8_t subtype; uint8_t reserved[3]; uint32_t a_l; } __packed; /* Extended attribute entry; type 2048 [4/48.10.8] */ struct impl_extattr_entry { struct extattr_entry hdr; uint32_t iu_l; struct regid imp_id; union { uint8_t data[1]; uint16_t data16; } __packed; } __packed; /* Extended attribute entry; type 65 536 [4/48.10.9] */ struct appl_extattr_entry { struct extattr_entry hdr; uint32_t au_l; struct regid appl_id; uint8_t data[1]; } __packed; /* File Times attribute entry; type 5 or type 6 [4/48.10.5], [4/48.10.6] */ struct filetimes_extattr_entry { struct extattr_entry hdr; uint32_t d_l; /* length of times[] data following */ uint32_t existence; /* bitmask */ struct timestamp times[1]; /* in order of assending bits */ } __packed; #define UDF_FILETIMES_ATTR_NO 5 #define UDF_FILETIMES_FILE_CREATION 1 #define UDF_FILETIMES_FILE_DELETION 4 #define UDF_FILETIMES_FILE_EFFECTIVE 8 #define UDF_FILETIMES_FILE_BACKUPED 16 #define UDF_FILETIMES_ATTR_SIZE(no) (20 + (no)*sizeof(struct timestamp)) /* Device Specification Extended Attribute [4/4.10.7] */ struct device_extattr_entry { struct extattr_entry hdr; uint32_t iu_l; /* length of implementation use */ uint32_t major; uint32_t minor; uint8_t data[1]; /* UDF: if nonzero length, contain developer ID regid */ } __packed; #define UDF_DEVICESPEC_ATTR_NO 12 /* VAT LV extension Extended Attribute [UDF 3.3.4.5.1.3] 1.50 errata */ struct vatlvext_extattr_entry { uint64_t unique_id_chk; /* needs to be copy of ICB's */ uint32_t num_files; uint32_t num_directories; char logvol_id[128]; /* replaces logvol name */ } __packed; /* File Entry [4/14.9] */ struct file_entry { struct desc_tag tag; struct icb_tag icbtag; uint32_t uid; uint32_t gid; uint32_t perm; uint16_t link_cnt; uint8_t rec_format; uint8_t rec_disp_attr; uint32_t rec_len; uint64_t inf_len; uint64_t logblks_rec; struct timestamp atime; struct timestamp mtime; struct timestamp attrtime; uint32_t ckpoint; struct long_ad ex_attr_icb; struct regid imp_id; uint64_t unique_id; uint32_t l_ea; /* Length of extended attribute area */ uint32_t l_ad; /* Length of allocation descriptors */ uint8_t data[1]; } __packed; #define UDF_FENTRY_SIZE 176 #define UDF_FENTRY_PERM_USER_MASK 0x07 #define UDF_FENTRY_PERM_GRP_MASK 0xE0 #define UDF_FENTRY_PERM_OWNER_MASK 0x1C00 /* Extended File Entry [4/48.17] */ struct extfile_entry { struct desc_tag tag; struct icb_tag icbtag; uint32_t uid; uint32_t gid; uint32_t perm; uint16_t link_cnt; uint8_t rec_format; uint8_t rec_disp_attr; uint32_t rec_len; uint64_t inf_len; uint64_t obj_size; uint64_t logblks_rec; struct timestamp atime; struct timestamp mtime; struct timestamp ctime; struct timestamp attrtime; uint32_t ckpoint; uint32_t reserved1; struct long_ad ex_attr_icb; struct long_ad streamdir_icb; struct regid imp_id; uint64_t unique_id; uint32_t l_ea; /* Length of extended attribute area */ uint32_t l_ad; /* Length of allocation descriptors */ uint8_t data[1]; } __packed; #define UDF_EXTFENTRY_SIZE 216 /* Indirect entry [ecma 48.7] */ struct indirect_entry { struct desc_tag tag; struct icb_tag icbtag; struct long_ad indirect_icb; } __packed; /* Allocation extent descriptor [ecma 48.5] */ struct alloc_ext_entry { struct desc_tag tag; uint32_t prev_entry; uint32_t l_ad; uint8_t data[1]; } __packed; union dscrptr { struct desc_tag tag; struct anchor_vdp avdp; struct vol_desc_ptr vdp; struct pri_vol_desc pvd; struct logvol_desc lvd; struct unalloc_sp_desc usd; struct logvol_int_desc lvid; struct impvol_desc ivd; struct part_desc pd; struct fileset_desc fsd; struct fileid_desc fid; struct file_entry fe; struct extfile_entry efe; struct extattrhdr_desc eahd; struct indirect_entry inde; struct alloc_ext_entry aee; struct udf_sparing_table spt; struct space_bitmap_desc sbd; struct space_entry_desc sed; }; /* Useful defines */ #define GETICB(ad_type, fentry, offset) \ (struct ad_type *)&fentry->data[offset] #define GETICBLEN(ad_type, icb) ((struct ad_type *)(icb))->len #endif /* !_FS_UDF_ECMA167_UDF_H_ */ UDFclient.0.8.8/Session.vim010064400001470000000000000160061307041400500150200ustar reinoudwheellet SessionLoad = 1 if &cp | set nocp | endif let s:cpo_save=&cpo set cpo&vim imap imap map  :bn map  :bp map Q gq nmap gx NetrwBrowseX nnoremap NetrwBrowseX :call netrw#NetrwBrowseX(expand(""),0) imap  gq{gq} imap  c \cite{p} let &cpo=s:cpo_save unlet s:cpo_save set autoindent set background=dark set backspace=2 set backup set cindent set comments=sr:/*,mb:*,el:*/,:// set formatoptions=croql set guifont=Monospace\ 8 set hidden set highlight=8:SpecialKey,@:NonText,d:Directory,e:ErrorMsg,i:IncSearch,l:IncSearch,m:MoreMsg,M:ModeMsg,n:LineNr,r:Question,s:StatusLine,S:StatusLineNC,t:Title,v:Visual,w:WarningMsg set hlsearch set mouse=a set ruler set termencoding=utf-8 set textwidth=78 set visualbell set window=79 let s:so_save = &so | let s:siso_save = &siso | set so=0 siso=0 let v:this_session=expand(":p") silent only cd ~/UDF/src if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == '' let s:wipebuf = bufnr('%') endif set shortmess=aoO badd +41 cd_disect.c badd +1 cd_sessions.c badd +1 config.h badd +1 defs.h badd +1 dirhash.h badd +136 ecma167-udf.h badd +1 mmc_format.c badd +31 newfs_udf.c badd +1 osta.c badd +1 osta.h badd +1 queue.h badd +5182 udf.c badd +527 udf.h badd +1 udf_allocentries.c badd +1 udf_bmap.c badd +1 udf_bswap.h badd +1 udf_discop.c badd +1 udf_discop.h badd +1 udf_readwrite.c badd +1 udf_unix.c badd +1 udf_unix.h badd +1370 udf_verbose.c badd +714 udfclient.c badd +206 udfdump.c badd +1 uio.c badd +1 uio.h badd +1 uscsi_sense.c badd +1 uscsi_subr.c badd +1 uscsilib.h badd +1 uscsilib_machdep.h badd +423 vfs_dirhash.c badd +554 /usr/src/sys/fs/udf/udf_vnops.c badd +4684 /usr/src/sys/fs/udf/udf_subr.c args cd_disect.c cd_sessions.c config.h defs.h dirhash.h ecma167-udf.h mmc_format.c newfs_udf.c osta.c osta.h queue.h udf.c udf.h udf_allocentries.c udf_bmap.c udf_bswap.h udf_discop.c udf_discop.h udf_readwrite.c udf_unix.c udf_unix.h udf_verbose.c udfclient.c udfdump.c uio.c uio.h uscsi_sense.c uscsi_subr.c uscsilib.h uscsilib_machdep.h vfs_dirhash.c edit vfs_dirhash.c set splitbelow splitright wincmd _ | wincmd | split 1wincmd k wincmd w set nosplitbelow set nosplitright wincmd t set winheight=1 winwidth=1 exe '1resize ' . ((&lines * 26 + 40) / 80) exe '2resize ' . ((&lines * 51 + 40) / 80) argglobal edit vfs_dirhash.c setlocal autoindent setlocal balloonexpr= setlocal nobinary setlocal bufhidden= setlocal buflisted setlocal buftype= setlocal cindent setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e setlocal cinoptions= setlocal cinwords=if,else,while,do,for,switch setlocal comments=sr:/*,mb:*,el:*/,:// setlocal commentstring=/*%s*/ setlocal complete=.,w,b,u,t,i setlocal completefunc= setlocal nocopyindent setlocal nocursorcolumn setlocal nocursorline setlocal define= setlocal dictionary= setlocal nodiff setlocal equalprg= setlocal errorformat= setlocal noexpandtab if &filetype != 'c' setlocal filetype=c endif setlocal foldcolumn=0 setlocal foldenable setlocal foldexpr=0 setlocal foldignore=# setlocal foldlevel=0 setlocal foldmarker={{{,}}} setlocal foldmethod=manual setlocal foldminlines=1 setlocal foldnestmax=20 setlocal foldtext=foldtext() setlocal formatexpr= setlocal formatoptions=croql setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* setlocal grepprg= setlocal iminsert=0 setlocal imsearch=0 setlocal include= setlocal includeexpr= setlocal indentexpr= setlocal indentkeys=0{,0},:,0#,!^F,o,O,e setlocal noinfercase setlocal iskeyword=@,48-57,_,192-255 setlocal keywordprg= setlocal nolinebreak setlocal nolisp setlocal nolist setlocal makeprg= setlocal matchpairs=(:),{:},[:] setlocal modeline setlocal modifiable setlocal nrformats=octal,hex setlocal nonumber setlocal numberwidth=4 setlocal omnifunc= setlocal path= setlocal nopreserveindent setlocal nopreviewwindow setlocal quoteescape=\\ setlocal noreadonly setlocal noscrollbind setlocal shiftwidth=8 setlocal noshortname setlocal nosmartindent setlocal softtabstop=0 setlocal nospell setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+ setlocal spellfile= setlocal spelllang=en setlocal statusline= setlocal suffixesadd= setlocal swapfile setlocal synmaxcol=3000 if &syntax != 'c' setlocal syntax=c endif setlocal tabstop=8 setlocal tags= setlocal textwidth=78 setlocal thesaurus= setlocal nowinfixheight setlocal nowinfixwidth setlocal wrap setlocal wrapmargin=0 silent! normal! zE let s:l = 341 - ((19 * winheight(0) + 13) / 26) if s:l < 1 | let s:l = 1 | endif exe s:l normal! zt 341 normal! 0 wincmd w argglobal edit udf.c setlocal autoindent setlocal balloonexpr= setlocal nobinary setlocal bufhidden= setlocal buflisted setlocal buftype= setlocal cindent setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e setlocal cinoptions= setlocal cinwords=if,else,while,do,for,switch setlocal comments=sr:/*,mb:*,el:*/,:// setlocal commentstring=/*%s*/ setlocal complete=.,w,b,u,t,i setlocal completefunc= setlocal nocopyindent setlocal nocursorcolumn setlocal nocursorline setlocal define= setlocal dictionary= setlocal nodiff setlocal equalprg= setlocal errorformat= setlocal noexpandtab if &filetype != 'c' setlocal filetype=c endif setlocal foldcolumn=0 setlocal foldenable setlocal foldexpr=0 setlocal foldignore=# setlocal foldlevel=0 setlocal foldmarker={{{,}}} setlocal foldmethod=manual setlocal foldminlines=1 setlocal foldnestmax=20 setlocal foldtext=foldtext() setlocal formatexpr= setlocal formatoptions=croql setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* setlocal grepprg= setlocal iminsert=0 setlocal imsearch=0 setlocal include= setlocal includeexpr= setlocal indentexpr= setlocal indentkeys=0{,0},:,0#,!^F,o,O,e setlocal noinfercase setlocal iskeyword=@,48-57,_,192-255 setlocal keywordprg= setlocal nolinebreak setlocal nolisp setlocal nolist setlocal makeprg= setlocal matchpairs=(:),{:},[:] setlocal modeline setlocal modifiable setlocal nrformats=octal,hex setlocal nonumber setlocal numberwidth=4 setlocal omnifunc= setlocal path= setlocal nopreserveindent setlocal nopreviewwindow setlocal quoteescape=\\ setlocal noreadonly setlocal noscrollbind setlocal shiftwidth=8 setlocal noshortname setlocal nosmartindent setlocal softtabstop=0 setlocal nospell setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+ setlocal spellfile= setlocal spelllang=en setlocal statusline= setlocal suffixesadd= setlocal swapfile setlocal synmaxcol=3000 if &syntax != 'c' setlocal syntax=c endif setlocal tabstop=8 setlocal tags= setlocal textwidth=78 setlocal thesaurus= setlocal nowinfixheight setlocal nowinfixwidth setlocal wrap setlocal wrapmargin=0 silent! normal! zE let s:l = 5895 - ((22 * winheight(0) + 25) / 51) if s:l < 1 | let s:l = 1 | endif exe s:l normal! zt 5895 normal! 0 wincmd w 2wincmd w exe '1resize ' . ((&lines * 26 + 40) / 80) exe '2resize ' . ((&lines * 51 + 40) / 80) tabnext 1 if exists('s:wipebuf') silent exe 'bwipe ' . s:wipebuf endif unlet! s:wipebuf set winheight=1 winwidth=20 shortmess=filnxtToO let s:sx = expand(":p:r")."x.vim" if file_readable(s:sx) exe "source " . s:sx endif let &so = s:so_save | let &siso = s:siso_save doautoall SessionLoadPost unlet SessionLoad " vim: set ft=vim : UDFclient.0.8.8/udf.c010066400001470000000000006353021307044072700136240ustar reinoudwheel/* $NetBSD$ */ /* * File "udf.c" is part of the UDFclient toolkit. * File $Id: udf.c,v 1.302 2017/04/03 12:36:21 reinoud Exp $ $Name: $ * * Copyright (c) 2003, 2004, 2005, 2006, 2011 * Reinoud Zandijk * All rights reserved. * * The UDFclient toolkit is distributed under the Clarified Artistic Licence. * A copy of the licence is included in the distribution as * `LICENCE.clearified.artistic' and a copy of the licence can also be * requested at the GNU foundantion's website. * * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "uscsilib.h" /* for locals */ #include "udf.h" #include "udf_bswap.h" #include "udf_discop.h" #include "udf_unix.h" #include "uio.h" #include "dirhash.h" #include /* for scsilib */ const char *dvname="UDF device"; #ifndef MAX # define MAX(a,b) ((a)>(b)?(a):(b)) # define MIN(a,b) ((a)<(b)?(a):(b)) #endif /* #define DEBUG(a) { a; } */ #define DEBUG(a) if (0) { a; } #if 1 extern void udf_dump_descriptor(union dscrptr *dscrpt); extern void udf_dump_file_entry(struct file_entry *fe); extern void udf_dump_extfile_entry(struct extfile_entry *efe); extern void udf_dump_alloc_extent(struct alloc_ext_entry *ext, int addr_type); extern void udf_dump_vat_table(struct udf_part_mapping *udf_part_mapping); extern void udf_dump_disc_anchors(struct udf_discinfo *disc); extern void udf_dump_alive_sets(void); extern void udf_dump_root_dir(struct udf_mountpoint *mountpoint); extern void udf_dump_timestamp(char *dscr, struct timestamp *t); #else void udf_dump_descriptor(union dscrptr *dscrpt) {}; extern void udf_dump_file_entry(struct file_entry *fe) {}; extern void udf_dump_extfile_entry(struct extfile_entry *efe) {}; extern void udf_dump_alloc_extent(struct alloc_ext_entry *ext, int addr_type) {}; void udf_dump_vat_table(struct udf_part_mapping *udf_part_mapping) {}; void udf_dump_disc_anchors(struct udf_discinfo *disc) {}; void udf_dump_alive_sets(void) {}; void udf_dump_root_dir(struct udf_mountpoint *mountpoint) {}; void udf_dump_timestamp(char *dscr, struct timestamp *t) {}; #endif /* global settings outside udf.h */ int udf_verbose = UDF_VERBLEV_ACTIONS; #define UDF_INODE_NUM_GUESS 2048 /* predefines */ int udf_validate_tag_and_crc_sums(union dscrptr *dscr); void udf_node_mark_dirty(struct udf_node *udf_node); static void udf_set_imp_id(struct regid *regid); static void udf_set_app_id(struct regid *regid); static void udf_node_unmark_dirty(struct udf_node *udf_node); static void udf_init_desc_tag(struct desc_tag *tag, uint16_t id, uint16_t dscr_ver, uint16_t serial_num); static int udf_translate_icb_filetype_to_dirent_filetype(int udf_filetype); static int udf_remove_directory_prim(struct udf_node *dir_node, struct udf_node *udf_node, char *componentname); static int udf_remove_directory_entry(struct udf_node *dir_node, struct udf_node *udf_node, char *componentname); /****************************************************************************************** * * Filename space conversion * ******************************************************************************************/ void udf_to_unix_name(char *result, char *id, int len, struct charspec *chsp) { uint16_t raw_name[1024], unix_name[1024]; uint16_t *inchp, ch; uint8_t *outchp; int ucode_chars, nice_uchars; assert(sizeof(char) == sizeof(uint8_t)); outchp = (uint8_t *) result; if ((chsp->type == 0) && (strcmp((char*) chsp->inf, "OSTA Compressed Unicode") == 0)) { *raw_name = *unix_name = 0; ucode_chars = udf_UncompressUnicode(len, (uint8_t *) id, raw_name); ucode_chars = MIN(ucode_chars, UnicodeLength((unicode_t *) raw_name)); nice_uchars = UDFTransName(unix_name, raw_name, ucode_chars); for (inchp = unix_name; nice_uchars>0; inchp++, nice_uchars--) { ch = *inchp; /* sloppy unicode -> latin */ *outchp++ = ch & 255; if (!ch) break; } *outchp++ = 0; } else { /* assume 8bit char length byte latin-1 */ assert(*id == 8); strncpy((char *) result, (char *) (id+1), strlen((char *) (id+1))); } } void unix_to_udf_name(char *result, char *name, uint8_t *result_len, struct charspec *chsp) { uint16_t raw_name[1024]; int udf_chars, name_len; char *inchp; uint16_t *outchp; /* convert latin-1 or whatever to unicode-16 */ *raw_name = 0; name_len = 0; inchp = name; outchp = raw_name; while (*inchp) { *outchp++ = (uint16_t) (*inchp++); name_len++; } if ((chsp->type == 0) && (strcmp((char *) chsp->inf, "OSTA Compressed Unicode") == 0)) { udf_chars = udf_CompressUnicode(name_len, 8, (unicode_t *) raw_name, (byte *) result); } else { /* assume 8bit char length byte latin-1 */ *result++ = 8; udf_chars = 1; strncpy(result, name + 1, strlen(name+1)); udf_chars += strlen(name); } *result_len = udf_chars; } static char *udf_get_compound_name(struct udf_mountpoint *mountpoint) { static char compound[128+128+32+32+1]; struct charspec *charspec; struct udf_log_vol *udf_log_vol; struct udf_pri_vol *udf_pri_vol; char *unix_name; udf_log_vol = mountpoint->udf_log_vol; udf_pri_vol = udf_log_vol->primary; charspec = &udf_pri_vol->pri_vol->desc_charset; assert(charspec->type == 0); assert(strcmp((const char *) charspec->inf, "OSTA Compressed Unicode")==0); unix_name = compound; udf_to_unix_name(unix_name, udf_pri_vol->pri_vol->volset_id, 128, charspec); strcat(unix_name, ":"); unix_name += strlen(unix_name); udf_to_unix_name(unix_name, udf_pri_vol->pri_vol->vol_id, 32, charspec); strcat(unix_name, ":"); unix_name += strlen(unix_name); udf_to_unix_name(unix_name, udf_log_vol->log_vol->logvol_id, 128, charspec); strcat(unix_name, ":"); unix_name += strlen(unix_name); udf_to_unix_name(unix_name, mountpoint->fileset_desc->fileset_id, 32, charspec); return compound; } /****************************************************************************************** * * Dump helpers for printing out information during parse * ******************************************************************************************/ void udf_dump_long_ad(char *prefix, struct long_ad *adr) { printf("%s at sector %d within partion space %d for %d bytes\n", prefix, udf_rw32(adr->loc.lb_num), udf_rw16(adr->loc.part_num), udf_rw32(adr->len) ); } void udf_dump_id(char *prefix, int len, char *id, struct charspec *chsp) { uint16_t raw_name[1024]; uint16_t *pos, ch; int ucode_chars; if (prefix) printf("%s ", prefix); if ((chsp->type == 0) && (strcmp((char *) chsp->inf, "OSTA Compressed Unicode") == 0)) { /* print the identifier using the OSTA compressed unicode */ printf("`"); ucode_chars = udf_UncompressUnicode(len, (uint8_t *) id, raw_name); for (pos = raw_name; ucode_chars > 0; pos++, ucode_chars--) { ch = *pos; /* OSTA code decompresses to machine endian */ if (!ch) break; if ((ch < 32) || (ch > 255)) { printf("[%d]", ch); } else { printf("%c", ch & 255); } } printf("`"); } else { printf("(roughly) `%s`", id+1); } if (prefix) printf("\n"); } void udf_dump_volume_name(char *prefix, struct udf_log_vol *udf_log_vol) { if (prefix) printf("%s%s", prefix, udf_log_vol->primary->udf_session->session_offset?" (local) ":" "); udf_dump_id(NULL, 128, udf_log_vol->primary->pri_vol->volset_id, &udf_log_vol->primary->pri_vol->desc_charset); printf(":"); udf_dump_id(NULL, 32, udf_log_vol->primary->pri_vol->vol_id, &udf_log_vol->primary->pri_vol->desc_charset); printf(":"); udf_dump_id(NULL, 128, udf_log_vol->log_vol->logvol_id, &udf_log_vol->log_vol->desc_charset); if (prefix) printf("\n"); } /****************************************************************************************** * * UDF tag checkers and size calculator * ******************************************************************************************/ /* not used extensively enough yet */ int udf_check_tag(union dscrptr *dscr) { struct desc_tag *tag = &dscr->tag; uint8_t *pos, sum, cnt; /* check TAG header checksum */ pos = (uint8_t *) tag; sum = 0; for(cnt = 0; cnt < 16; cnt++) { if (cnt != 4) sum += *pos; pos++; } if (sum != tag->cksum) { /* bad tag header checksum; this is not a valid tag */ DEBUG(printf("Bad checksum\n")); return EINVAL; } return 0; } int udf_check_tag_payload(union dscrptr *dscr) { struct desc_tag *tag = &dscr->tag; uint16_t crc; /* check payload CRC if applicable */ if (udf_rw16(tag->desc_crc_len) == 0) return 0; crc = udf_cksum(((uint8_t *) tag) + UDF_DESC_TAG_LENGTH, udf_rw16(tag->desc_crc_len)); if (crc != udf_rw16(tag->desc_crc)) { DEBUG(printf("ERROR: CRC bad read 0x%0x calc 0x%0x\n", udf_rw16(tag->desc_crc), crc)); /* bad payload CRC; this is a broken tag */ return EINVAL; } return 0; } int udf_validate_tag_sum(union dscrptr *dscr) { struct desc_tag *tag = &dscr->tag; uint8_t *pos, sum, cnt; /* calculate TAG header checksum */ pos = (uint8_t *) tag; sum = 0; for(cnt = 0; cnt < 16; cnt++) { if (cnt != 4) sum += *pos; pos++; } tag->cksum = sum; /* 8 bit */ return 0; } /* assumes sector number of descriptor to be allready present */ int udf_validate_tag_and_crc_sums(union dscrptr *dscr) { struct desc_tag *tag = &dscr->tag; uint16_t crc; /* check payload CRC if applicable */ if (udf_rw16(tag->desc_crc_len) > 0) { crc = udf_cksum(((uint8_t *) tag) + UDF_DESC_TAG_LENGTH, udf_rw16(tag->desc_crc_len)); tag->desc_crc = udf_rw16(crc); } /* calculate TAG header checksum */ return udf_validate_tag_sum(dscr); } int udf_check_tag_presence(union dscrptr *dscr, int TAG) { struct desc_tag *tag = &dscr->tag; int error; error = udf_check_tag(dscr); if (error) return error; if (udf_rw16(tag->id) != TAG) { DEBUG(fprintf(stderr, "looking for tag %d but found %d\n", TAG, udf_rw16(tag->id))); return ENOENT; } return 0; } /* * for malloc() purposes ... rather have an upperlimit than an exact size */ uint64_t udf_calc_tag_malloc_size(union dscrptr *dscr, uint32_t udf_sector_size) { uint32_t size, tag_id; tag_id = udf_rw16(dscr->tag.id); switch (tag_id) { case TAGID_LOGVOL : size = sizeof(struct logvol_desc) - 1; /* maps[1] */ size += udf_rw32(dscr->lvd.mt_l); break; case TAGID_UNALLOC_SPACE : size = sizeof(struct unalloc_sp_desc) - sizeof(struct extent_ad); /* alloc_desc[1] */ size += udf_rw32(dscr->usd.alloc_desc_num) * sizeof(struct extent_ad); break; case TAGID_FID : size = UDF_FID_SIZE + dscr->fid.l_fi + udf_rw16(dscr->fid.l_iu); size = (size + 3) & ~3; return size; /* RETURN !! */ case TAGID_LOGVOL_INTEGRITY : size = sizeof(struct logvol_int_desc) - sizeof(uint32_t); /* tables[1] */ size += udf_rw32(dscr->lvid.l_iu); size += (2 * udf_rw32(dscr->lvid.num_part) * sizeof(uint32_t)); break; case TAGID_SPACE_BITMAP : size = sizeof(struct space_bitmap_desc) - 1; /* data[1] */ size += udf_rw32(dscr->sbd.num_bytes); break; case TAGID_SPARING_TABLE : size = sizeof(struct udf_sparing_table) - sizeof(struct spare_map_entry); /* entries[1] */ size += udf_rw16(dscr->spt.rt_l) * sizeof(struct spare_map_entry); break; case TAGID_FENTRY : size = sizeof(struct file_entry); size += udf_rw32(dscr->fe.l_ea) + udf_rw32(dscr->fe.l_ad)-1; /* data[0] */ break; case TAGID_EXTFENTRY : size = sizeof(struct extfile_entry); size += udf_rw32(dscr->efe.l_ea) + udf_rw32(dscr->efe.l_ad)-1; /* data[0] */ break; case TAGID_FSD : size = sizeof(struct fileset_desc); break; default : size = sizeof(union dscrptr); break; } if ((size == 0) || (udf_sector_size == 0)) return 0; return ((size + udf_sector_size -1) / udf_sector_size) * udf_sector_size; } /* explicit only for FID's */ static int udf_fidsize(struct fileid_desc *fid) { int size; size = UDF_FID_SIZE + fid->l_fi + udf_rw16(fid->l_iu); size = (size + 3) & ~3; return size; } /****************************************************************************************** * * Logical to physical adres transformation * ******************************************************************************************/ /* convert (udf_log_vol, vpart_num) to a udf_partion structure */ int udf_logvol_vpart_to_partition(struct udf_log_vol *udf_log_vol, uint32_t vpart_num, struct udf_part_mapping **udf_part_mapping_ptr, struct udf_partition **udf_partition_ptr) { struct udf_volumeset *udf_volumeset; struct udf_partition *udf_partition; struct udf_part_mapping *udf_part_mapping; uint32_t part_num; int found; assert(udf_log_vol); assert(!SLIST_EMPTY(&udf_log_vol->part_mappings)); /* clear result */ if (udf_part_mapping_ptr) *udf_part_mapping_ptr = NULL; if (udf_partition_ptr) *udf_partition_ptr = NULL; /* map the requested partition map to the physical udf partition */ found = 0; SLIST_FOREACH(udf_part_mapping, &udf_log_vol->part_mappings, next_mapping) { if (udf_part_mapping->udf_virt_part_num == vpart_num) { found = 1; break; } } if (!found) { printf("\t\t\tVirtual partition number %d not found!\n", vpart_num); return EINVAL; } assert(udf_part_mapping); /* call me paranoid */ part_num = udf_part_mapping->udf_phys_part_num; /* search for the physical partition information */ udf_volumeset = udf_log_vol->primary->volumeset; SLIST_FOREACH(udf_partition, &udf_volumeset->parts, next_partition) { if (udf_rw16(udf_partition->partition->part_num) == part_num) break; } if (!udf_partition) { printf("\t\t\tNo information known about partition %d yet!\n", part_num); printf("\t\t\t\tPlease insert volume %d of this volumeset and try again\n", udf_part_mapping->vol_seq_num); return ENOENT; } if (udf_part_mapping_ptr) *udf_part_mapping_ptr = udf_part_mapping; if (udf_partition_ptr) *udf_partition_ptr = udf_partition; return 0; } /* no recursive translations yet (UDF OK) */ /* All translation is done in 64 bits to prevent bitrot and returns the PARTITION relative address */ int udf_vpartoff_to_sessionoff(struct udf_log_vol *udf_log_vol, struct udf_part_mapping *udf_part_mapping, struct udf_partition *udf_partition, uint64_t offset, uint64_t *ses_off, uint64_t *trans_valid_len) { struct spare_map_entry *sp_entry; struct udf_node *udf_node; struct udf_allocentry *alloc_entry; uint64_t part_start, part_length; uint64_t eff_sector, eff_offset; uint64_t trans_sector; uint64_t cur_offset; uint32_t len, lb_num, block_offset; uint32_t entry, entries; uint32_t sector_size, lb_size; uint64_t packet_num, packet_rlb; uint64_t packet_len; uint32_t vat_entries, *vat_pos; int flags; assert(udf_part_mapping); assert(udf_partition); assert(ses_off); assert(trans_valid_len); /* not ok, but rather this than a dangling random value */ *ses_off = UINT_MAX; *trans_valid_len = 0; lb_size = udf_log_vol->lb_size; sector_size = udf_log_vol->sector_size; part_start = (uint64_t) udf_rw32(udf_partition->partition->start_loc) * sector_size; part_length = (uint64_t) udf_rw32(udf_partition->partition->part_len) * sector_size; /* get the offset (in bytes) in the partition and check its validity */ if (offset >= part_length) { printf("\t\toffset %"PRIu64" is outside partition %d!\n", offset, udf_rw16(udf_partition->partition->part_num)); return EFAULT; } /* do the address translations based on the partition mapping type */ /* translation of virt/sparable etc. is assumed to be done in logical block sizes */ switch (udf_part_mapping->udf_part_mapping_type) { case UDF_PART_MAPPING_PHYSICAL : /* nothing to be done; physical is logical */ *ses_off = part_start + offset; /* 1:1 */ *trans_valid_len = part_length - offset; /* rest of partition */ return 0; case UDF_PART_MAPPING_VIRTUAL : vat_entries = udf_part_mapping->vat_entries; vat_pos = (uint32_t *) udf_part_mapping->vat_translation; /* this translation is dependent on logical sector numbers */ eff_sector = offset / lb_size; eff_offset = offset % lb_size; /* TODO check range for logical sector against VAT length */ assert(eff_sector < vat_entries); trans_sector = vat_pos[eff_sector]; *ses_off = part_start + (trans_sector * lb_size) + eff_offset; /* trans sectors are in lb->lb ? */ *trans_valid_len = lb_size - eff_offset; /* maximum one logical sector */ return 0; case UDF_PART_MAPPING_SPARABLE : /* this translation is dependent on logical sector numbers */ *ses_off = part_start + offset; /* 1:1 */ eff_sector = offset / lb_size; eff_offset = offset % lb_size; /* transform on packet-length base */ packet_len = udf_rw16(udf_part_mapping->udf_pmap->pms.packet_len); /* in lb */ entries = udf_rw16(udf_part_mapping->sparing_table->rt_l); packet_num = (eff_sector / packet_len) * packet_len; packet_rlb = eff_sector % packet_len; /* within packet */ /* translate this packet; source is in partition, destination is absolute disc address */ sp_entry = &udf_part_mapping->sparing_table->entries[0]; for (entry = 0; entry < entries; entry++) { if (udf_rw32(sp_entry->org) - packet_num == 0) { /* mappings contain absolute disc addresses, so no partition offsets please */ *ses_off = (uint64_t) (udf_rw32(sp_entry->map) + packet_rlb) * lb_size + eff_offset; break; } sp_entry++; } *trans_valid_len = (packet_len - packet_rlb) * lb_size; /* maximum one packet */ return 0; case UDF_PART_MAPPING_META : /* We follow the allocation entries to calculate our offset */ udf_node = udf_part_mapping->meta_file; assert(udf_node->addr_type != UDF_ICB_INTERN_ALLOC); /* find sector in the allocation space */ UDF_MUTEX_LOCK(&udf_node->alloc_mutex); cur_offset = 0; TAILQ_FOREACH(alloc_entry, &udf_node->alloc_entries, next_alloc) { len = alloc_entry->len; lb_num = alloc_entry->lb_num; /* vpart_num = alloc_entry->vpart_num; */ flags = alloc_entry->flags; /* check overlap with this alloc entry */ if (cur_offset + len > offset) { assert(((offset - cur_offset) % lb_size) == 0); /* ought to be on sector boundary */ if (flags != UDF_EXT_ALLOCATED) break; block_offset = offset - cur_offset; *ses_off = part_start + lb_num * lb_size + block_offset; /* 1:1 within the block */ *trans_valid_len = len - block_offset; /* rest of this chunk */ UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex); return 0; } cur_offset += len; } /* FOREACH */ UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex); printf("\t\toffset %"PRIu64" is not translated within current metadata partition %d file descriptor!\n", offset, udf_rw16(udf_partition->partition->part_num)); return EFAULT; case UDF_PART_MAPPING_ERROR : default : break; } printf("Unsupported or bad mapping %d; can't translate\n", udf_part_mapping->udf_part_mapping_type); return EFAULT; } /****************************************************************************************** * * udf_node creator, destructor and syncer * ******************************************************************************************/ static mode_t udf_perm_to_unix_mode(uint32_t perm) { mode_t mode; mode = ((perm & UDF_FENTRY_PERM_USER_MASK) ); mode |= ((perm & UDF_FENTRY_PERM_GRP_MASK ) >> 2); mode |= ((perm & UDF_FENTRY_PERM_OWNER_MASK) >> 4); return mode; } static uint32_t unix_mode_to_udf_perm(mode_t mode) { uint32_t perm; perm = ((mode & S_IRWXO) ); perm |= ((mode & S_IRWXG) << 2); perm |= ((mode & S_IRWXU) << 4); perm |= ((mode & S_IWOTH) << 3); perm |= ((mode & S_IWGRP) << 5); perm |= ((mode & S_IWUSR) << 7); return perm; } /* * Fill in timestamp structure based on clock_gettime(). Time is reported back as a time_t * accompanied with a nano second field. * * The husec, usec and csec could be relaxed in type. */ static void udf_timespec_to_timestamp(struct timespec *timespec, struct timestamp *timestamp) { struct tm tm; uint64_t husec, usec, csec; bzero(timestamp, sizeof(struct timestamp)); gmtime_r(×pec->tv_sec, &tm); /* * Time type and time zone : see ECMA 1/7.3, UDF 2., 2.1.4.1, 3.1.1. * * Lower 12 bits are two complement signed timezone offset if bit 12 * (method 1) is clear. Otherwise if bit 12 is set, specify timezone * offset to -2047 i.e. unsigned `zero' */ timestamp->type_tz = udf_rw16((1<<12) + 0); /* has to be method 1 for CUT/GMT */ timestamp->year = udf_rw16(tm.tm_year + 1900); timestamp->month = tm.tm_mon + 1; /* `tm' structure uses 0..11 for months */ timestamp->day = tm.tm_mday; timestamp->hour = tm.tm_hour; timestamp->minute = tm.tm_min; timestamp->second = tm.tm_sec; usec = (timespec->tv_nsec + 500) / 1000; /* round (if possible) */ husec = usec / 100; usec -= husec * 100; /* we only want 0-99 in usec */ csec = husec / 100; /* we get 0-99 in csec */ husec -= csec * 100; /* we only want 0-99 in husec */ timestamp->centisec = csec; timestamp->hund_usec = husec; timestamp->usec = usec; } void udf_set_timestamp_now(struct timestamp *timestamp) { struct timespec now; clock_gettime(CLOCK_REALTIME, &now); udf_timespec_to_timestamp(&now, timestamp); } /* implemented as a seperate function to allow tuning */ void udf_set_timespec_now(struct timespec *timespec) { clock_gettime(CLOCK_REALTIME, timespec); } int udf_insanetimespec(struct timespec *check) { struct timespec now; struct tm tm; gmtime_r(&check->tv_sec, &tm); /* since our converters can only deal with timestamps after 1970 we * reject earlier */ if (tm.tm_year < 1970) return 1; /* don't accept values from the future; FFS or NFS might not mind, but * UDF does! */ clock_gettime(CLOCK_REALTIME, &now); if (now.tv_sec < check->tv_sec) return 1; if ((now.tv_sec == check->tv_sec) && (now.tv_nsec < check->tv_nsec)) return 1; return 0; } /* * Timestamp to timespec conversion code is taken with small modifications * from FreeBSD /sys/fs/udf by Scott Long */ static int mon_lens[2][12] = { {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} }; static int udf_isaleapyear(int year) { int i; i = (year % 4) ? 0 : 1; i &= (year % 100) ? 1 : 0; i |= (year % 400) ? 0 : 1; return i; } static void udf_timestamp_to_timespec(struct timestamp *timestamp, struct timespec *timespec) { uint32_t usecs, secs, nsecs; uint16_t tz; int i, lpyear, daysinyear, year; timespec->tv_sec = secs = 0; timespec->tv_nsec = nsecs = 0; /* * DirectCD seems to like using bogus year values. * Distrust time->month especially, since it will be used for an array * index. */ year = udf_rw16(timestamp->year); if ((year < 1970) || (timestamp->month > 12)) { return; } /* Calculate the time and day */ usecs = timestamp->usec + 100*timestamp->hund_usec + 10000*timestamp->centisec; nsecs = usecs * 1000; secs = timestamp->second; secs += timestamp->minute * 60; secs += timestamp->hour * 3600; secs += (timestamp->day-1) * 3600 * 24; /* day : 1-31 */ /* Calclulate the month */ lpyear = udf_isaleapyear(year); for (i = 1; i < timestamp->month; i++) secs += mon_lens[lpyear][i-1] * 3600 * 24; /* month: 1-12 */ for (i = 1970; i < year; i++) { daysinyear = udf_isaleapyear(i) + 365 ; secs += daysinyear * 3600 * 24; } /* * Calculate the time zone. The timezone is 12 bit signed 2's * compliment, so we gotta do some extra magic to handle it right. */ tz = udf_rw16(timestamp->type_tz); tz &= 0x0fff; /* only lower 12 bits are significant */ if (tz & 0x0800) /* sign extention */ tz |= 0xf000; /* TODO check timezone conversion */ #if 1 /* check if we are specified a timezone to convert */ if (udf_rw16(timestamp->type_tz) & 0x1000) if ((int16_t) tz != -2047) secs -= (int16_t) tz * 60; #endif timespec->tv_sec = secs; timespec->tv_nsec = nsecs; } static void udf_node_get_fileinfo(struct udf_node *udf_node, union dscrptr *dscrptr) { struct stat *stat; struct file_entry *file_entry; struct extfile_entry *extfile_entry; struct timestamp *atime, *mtime, *ctime, *attrtime; uint64_t inf_len, unique_id; uint32_t uid, gid, udf_perm; uint16_t fe_tag; uint16_t udf_icbtag_flags, serial_num, link_cnt; uint8_t filetype; assert(udf_node); assert(dscrptr); stat = &udf_node->stat; /* check if its an normal file entry or a extended file entry ICB */ fe_tag = udf_rw16(dscrptr->tag.id); if (fe_tag == TAGID_FENTRY) { file_entry = &dscrptr->fe; #if 0 prev_direct_entries = udf_rw32(file_entry->icbtag.prev_num_dirs); strat_param16 = udf_rw16(* (uint16_t *) (file_entry->icbtag.strat_param)); entries = udf_rw16(file_entry->icbtag.max_num_entries); strategy = udf_rw16(file_entry->icbtag.strat_type); data_length = udf_rw32(file_entry->l_ad); addr_type = udf_rw16(file_entry->icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK; pos = &file_entry->data[0] + udf_rw32(file_entry->l_ea); #endif filetype = file_entry->icbtag.file_type; inf_len = udf_rw64(file_entry->inf_len); uid = udf_rw32(file_entry->uid); gid = udf_rw32(file_entry->gid); udf_perm = udf_rw32(file_entry->perm); serial_num = udf_rw16(file_entry->tag.serial_num); udf_icbtag_flags = udf_rw16(file_entry->icbtag.flags); link_cnt = udf_rw16(file_entry->link_cnt); unique_id = udf_rw64(file_entry->unique_id); atime = &file_entry->atime; mtime = &file_entry->mtime; ctime = &file_entry->mtime; /* XXX assumption */ attrtime = &file_entry->attrtime; } else if (fe_tag == TAGID_EXTFENTRY) { extfile_entry = &dscrptr->efe; #if 0 prev_direct_entries = udf_rw32(extfile_entry->icbtag.prev_num_dirs); strat_param16 = udf_rw16(* (uint16_t *) (extfile_entry->icbtag.strat_param)); entries = udf_rw16(extfile_entry->icbtag.max_num_entries); strategy = udf_rw16(extfile_entry->icbtag.strat_type); data_length = udf_rw32(extfile_entry->l_ad); addr_type = udf_rw16(extfile_entry->icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK; pos = &extfile_entry->data[0] + udf_rw32(extfile_entry->l_ea); #endif filetype = extfile_entry->icbtag.file_type; inf_len = udf_rw64(extfile_entry->inf_len); uid = udf_rw32(extfile_entry->uid); gid = udf_rw32(extfile_entry->gid); udf_perm = udf_rw32(extfile_entry->perm); serial_num = udf_rw16(extfile_entry->tag.serial_num); udf_icbtag_flags = udf_rw16(extfile_entry->icbtag.flags); link_cnt = udf_rw16(extfile_entry->link_cnt); /* how many FID's are linked to this (ext)fentry */ unique_id = udf_rw64(extfile_entry->unique_id); /* unique file ID */ atime = &extfile_entry->atime; mtime = &extfile_entry->mtime; ctime = &extfile_entry->ctime; attrtime = &extfile_entry->attrtime; } else { printf("udf_node_set_file_info : help! i can't be here!!! i got a %d tag\n", fe_tag); udf_dump_descriptor(dscrptr); return; } /* fill in (parts of) the stat structure */ /* XXX important info missing still like access mode, times etc. XXX */ udf_node->udf_filetype = filetype; udf_node->serial_num = serial_num; udf_node->udf_icbtag_flags = udf_icbtag_flags; udf_node->link_cnt = link_cnt; /* how many FID's are linked to this (ext)fentry */ udf_node->unique_id = unique_id; /* unique file ID */ /* fill in stat basics */ bzero(stat, sizeof(struct stat)); stat->st_ino = unique_id; /* lowest 32 bit(!) only */ stat->st_mode = udf_perm_to_unix_mode(udf_perm); /* CONVERT from udf_perm */ stat->st_mode |= (udf_translate_icb_filetype_to_dirent_filetype(filetype) & DT_DIR) ? S_IFDIR : S_IFREG; stat->st_uid = uid; stat->st_gid = gid; /* ... times */ udf_timestamp_to_timespec(atime, &stat->st_atimespec); udf_timestamp_to_timespec(mtime, &stat->st_mtimespec); udf_timestamp_to_timespec(attrtime, &stat->st_ctimespec); #ifndef NO_STAT_BIRTHTIME udf_timestamp_to_timespec(ctime, &stat->st_birthtimespec); #endif /* ... sizes */ stat->st_size = inf_len; stat->st_blksize = udf_node->udf_log_vol->lb_size; /* special: updatables */ stat->st_nlink = link_cnt; stat->st_blocks = (stat->st_size + 512 -1)/512; /* blocks are hardcoded 512 bytes/sector in stat :-/ */ return; } static void udf_node_set_fileinfo(struct udf_node *udf_node, union dscrptr *dscrptr) { struct stat *stat; struct file_entry *file_entry; struct extfile_entry *extfile_entry; struct timestamp *atime, *mtime, *ctime, *attrtime; uint64_t inf_len, unique_id; uint32_t uid, gid, udf_perm; uint16_t fe_tag, serial_num, link_cnt; uint8_t filetype; assert(udf_node); assert(dscrptr); stat = &udf_node->stat; /* set (parts of) the stat structure */ /* XXX important info missing still like times etc. XXX */ uid = stat->st_uid; gid = stat->st_gid; inf_len = stat->st_size; udf_perm = unix_mode_to_udf_perm(stat->st_mode); /* conversion to UDF perm. */ filetype = udf_node->udf_filetype; unique_id = udf_node->unique_id; serial_num = udf_node->serial_num; link_cnt = udf_node->link_cnt; /* check if its to be written in an normal file entry or a extended file entry ICB */ fe_tag = udf_rw16(dscrptr->tag.id); if (fe_tag == TAGID_FENTRY) { file_entry = &dscrptr->fe; #if 0 prev_direct_entries = udf_rw32(file_entry->icbtag.prev_num_dirs); strat_param16 = udf_rw16(* (uint16_t *) (file_entry->icbtag.strat_param)); entries = udf_rw16(file_entry->icbtag.max_num_entries); strategy = udf_rw16(file_entry->icbtag.strat_type); data_length = udf_rw32(file_entry->l_ad); addr_type = udf_rw16(file_entry->icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK; pos = &file_entry->data[0] + udf_rw32(file_entry->l_ea); #endif file_entry->icbtag.file_type = filetype; file_entry->inf_len = udf_rw64(inf_len); file_entry->uid = udf_rw32(uid); file_entry->gid = udf_rw32(gid); file_entry->perm = udf_rw32(udf_perm); file_entry->tag.serial_num = udf_rw16(serial_num); file_entry->link_cnt = udf_rw16(link_cnt); file_entry->unique_id = udf_rw64(unique_id); atime = &file_entry->atime; mtime = &file_entry->mtime; ctime = mtime; /* XXX assumption */ attrtime = &file_entry->attrtime; } else if (fe_tag == TAGID_EXTFENTRY) { extfile_entry = &dscrptr->efe; #if 0 prev_direct_entries = udf_rw32(extfile_entry->icbtag.prev_num_dirs); strat_param16 = udf_rw16(* (uint16_t *) (extfile_entry->icbtag.strat_param)); entries = udf_rw16(extfile_entry->icbtag.max_num_entries); strategy = udf_rw16(extfile_entry->icbtag.strat_type); data_length = udf_rw32(extfile_entry->l_ad); addr_type = udf_rw16(extfile_entry->icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK; pos = &extfile_entry->data[0] + udf_rw32(extfile_entry->l_ea); #endif extfile_entry->icbtag.file_type = filetype; extfile_entry->inf_len = udf_rw64(inf_len); extfile_entry->uid = udf_rw32(uid); extfile_entry->gid = udf_rw32(gid); extfile_entry->perm = udf_rw32(udf_perm); extfile_entry->tag.serial_num = udf_rw16(serial_num); extfile_entry->link_cnt = udf_rw16(link_cnt); /* how many FID's are linked to this (ext)fentry */ extfile_entry->unique_id = udf_rw64(unique_id); /* unique file ID */ atime = &extfile_entry->atime; mtime = &extfile_entry->mtime; ctime = &extfile_entry->ctime; attrtime = &extfile_entry->attrtime; } else { printf("udf_node_set_file_info : help! i can't be here!!! i got a %d tag\n", fe_tag); udf_dump_descriptor(dscrptr); return; } /* FILL in {atime, mtime, attrtime} TIMES! */ udf_timespec_to_timestamp(&stat->st_atimespec, atime); udf_timespec_to_timestamp(&stat->st_mtimespec, mtime); udf_timespec_to_timestamp(&stat->st_ctimespec, attrtime); #ifndef NO_STAT_BIRTHTIME udf_timespec_to_timestamp(&stat->st_birthtimespec, ctime); #else memcpy(ctime, mtime, sizeof(*ctime)); #endif return; } /* with 32 bits ino_t, a maximum of about 8 TB discs are supported (1<<32) * 2KB*/ ino_t udf_calc_hash(struct long_ad *icbptr) { /* TODO unique file-id would be better */ return (ino_t) udf_rw32(icbptr->loc.lb_num); } void udf_insert_node_in_hash(struct udf_node *udf_node) { struct udf_log_vol *log_vol; uint32_t bucket; ino_t hashkey; struct long_ad icb; icb.loc.lb_num = udf_rw32(TAILQ_FIRST(&udf_node->dscr_allocs)->lb_num); log_vol = udf_node->udf_log_vol; hashkey = udf_calc_hash(&icb); udf_node->hashkey = hashkey; bucket = hashkey & UDF_INODE_HASHMASK; LIST_INSERT_HEAD(&log_vol->udf_nodes[bucket], udf_node, next_node); } /* dispose udf_node's administration */ void udf_dispose_udf_node(struct udf_node *udf_node) { struct udf_allocentry *alloc_entry; struct udf_buf *buf_entry; struct udf_node *lookup; uint32_t bucket; ino_t hashkey; if (!udf_node) return; /* XXX locks? XXX */ UDF_MUTEX_LOCK(&udf_node->alloc_mutex); if (udf_node->dirty) { DEBUG(printf("Warning: disposing dirty node\n")); udf_node_unmark_dirty(udf_node); } /* free all associated buffers */ UDF_MUTEX_LOCK(&udf_bufcache->bufcache_lock); UDF_MUTEX_LOCK(&udf_node->buf_mutex); /* due to this `trick' we don't need to use a marker */ while ((buf_entry = TAILQ_FIRST(&udf_node->vn_bufs))) { udf_mark_buf_clean(udf_node, buf_entry); /* its destroyed so not dirty */ udf_mark_buf_allocated(udf_node, buf_entry); /* i.e. taken care of */ udf_detach_buf_from_node(udf_node, buf_entry); udf_free_buf_entry(buf_entry); } /* free in-node filedata blob if present */ if (udf_node->intern_data) free(udf_node->intern_data); UDF_MUTEX_UNLOCK(&udf_node->buf_mutex); UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock); /* free our extended attribute administration if present */ if (udf_node->extattrfile_icb) free(udf_node->extattrfile_icb); if (udf_node->streamdir_icb) free(udf_node->streamdir_icb); if (udf_node->extended_attr) free(udf_node->extended_attr); /* free dscr_allocs queue */ while ((alloc_entry = TAILQ_FIRST(&udf_node->dscr_allocs))) { TAILQ_REMOVE(&udf_node->dscr_allocs, alloc_entry, next_alloc); free(alloc_entry); } /* free allocation queue */ while ((alloc_entry = TAILQ_FIRST(&udf_node->alloc_entries))) { TAILQ_REMOVE(&udf_node->alloc_entries, alloc_entry, next_alloc); free(alloc_entry); } /* if its part of a logical volume, delete it in its hash table */ if (udf_node->udf_log_vol) { hashkey = udf_node->hashkey; bucket = hashkey & UDF_INODE_HASHMASK; LIST_FOREACH(lookup, &udf_node->udf_log_vol->udf_nodes[bucket], next_node) { /* hashkey doesn't matter; just remove same udf_node pointer */ if (lookup == udf_node) { assert(lookup->hashkey == hashkey); DEBUG(printf("removal of udf_node from the hash table\n")); LIST_REMOVE(lookup, next_node); break; } } } UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex); /* free the node */ free(udf_node); } uint64_t udf_increment_unique_id(struct udf_log_vol *udf_log_vol) { uint64_t unique_id, next_unique_id; /* lock? */ unique_id = udf_log_vol->next_unique_id; /* increment according to UDF 3/3.2.1.1 */ next_unique_id = unique_id + 1; if (((next_unique_id << 32) >> 32) < 16) next_unique_id |= 16; udf_log_vol->next_unique_id = next_unique_id; DEBUG(printf("next unique_id <-- %"PRIu64"\n", udf_log_vol->next_unique_id)); return unique_id; } int udf_init_udf_node(struct udf_mountpoint *mountpoint, struct udf_log_vol *udf_log_vol, char *what, struct udf_node **udf_nodeptr) { struct udf_node *udf_node; uint32_t lb_size, data_space_avail; int descr_ver; what = what; /* not used yet */ assert(udf_log_vol); lb_size = udf_log_vol->lb_size; /* get ourselves some space */ udf_node = calloc(1, sizeof(struct udf_node)); if (!udf_node) return ENOMEM; /* setup basic udf_node */ udf_node->addr_type = UDF_ICB_LONG_ALLOC; udf_node->icb_len = sizeof(struct long_ad); udf_node->serial_num = 1; udf_node->udf_icbtag_flags = UDF_ICB_INTERN_ALLOC; udf_node->link_cnt = 1; /* how many FID's are linked to this node */ udf_node->unique_id = 0; /* unique file ID unknown */ /* get internal space available for internal nodes */ /* TODO keep in mind the extended attributes! XXX */ descr_ver = udf_rw16(udf_log_vol->log_vol->tag.descriptor_ver); if (descr_ver == 2) { /* TODO reserve some space for the icb creation time */ data_space_avail = lb_size - sizeof(struct file_entry) - 0; /* udf_rw32(file_entry->l_ea) */ } else { data_space_avail = lb_size - sizeof(struct extfile_entry) - 0; /* udf_rw32(extfile_entry->l_ea) */ } udf_node->intern_free = data_space_avail; udf_node->intern_data = NULL; udf_node->intern_len = 0; /* finalise udf_node */ udf_node->mountpoint = mountpoint; udf_node->udf_log_vol = udf_log_vol; TAILQ_INIT(&udf_node->dscr_allocs); TAILQ_INIT(&udf_node->alloc_entries); TAILQ_INIT(&udf_node->vn_bufs); UDF_MUTEX_INIT(&udf_node->alloc_mutex); UDF_MUTEX_INIT(&udf_node->buf_mutex); /* XXX udf_node_lock NOT USED XXX */ /* pthread_rwlock_init(&udf_node->udf_node_lock, NULL); */ *udf_nodeptr = udf_node; return 0; } int udf_allocate_udf_node_on_disc(struct udf_node *udf_node) { struct udf_allocentry *alloc_entry; uint32_t lb_num, lb_size; uint16_t vpart_num; int error; assert(udf_node); assert(udf_node->udf_log_vol); assert(udf_node->udf_log_vol->log_vol); lb_size = udf_node->udf_log_vol->lb_size; assert(lb_size); /* pre-allocate node; its needed in directory linkage for now */ error = udf_allocate_lbs(udf_node->udf_log_vol, UDF_C_NODE, /*num lb */ 1, "New FID", &vpart_num, &lb_num, NULL); if (error) return error; alloc_entry = calloc(1, sizeof(struct udf_allocentry)); if (!alloc_entry) { return ENOMEM; } alloc_entry->len = lb_size; alloc_entry->vpart_num = vpart_num; alloc_entry->lb_num = lb_num; alloc_entry->flags = 0; TAILQ_INSERT_TAIL(&udf_node->dscr_allocs, alloc_entry, next_alloc); assert(error == 0); return error; } /* note: the udf_node (inode) is not stored in a hashtable! hash value is still invalid */ /* TODO remember our extended attributes and remember our streamdir long_ad */ int udf_readin_anon_udf_node(struct udf_log_vol *udf_log_vol, union dscrptr *given_dscrptr, struct long_ad *udf_icbptr, char *what, struct udf_node **udf_nodeptr) { union dscrptr *dscrptr; struct udf_node *udf_node; struct udf_allocentry *alloc_entry; struct udf_allocentry *cur_alloc, *next_alloc; struct file_entry *file_entry; struct extfile_entry *extfile_entry; struct alloc_ext_entry *alloc_ext_entry; struct long_ad *l_ad; struct short_ad *s_ad; uint64_t inf_len, calculated_len; uint32_t lb_size, entries; uint64_t data_length; uint32_t data_space_avail; uint32_t fe_tag; uint64_t len; uint32_t lb_num, vpart_num; uint32_t icb_len; int16_t addr_type; uint8_t *pos; uint8_t flags; int error, advance_sector; if ((udf_icbptr->loc.lb_num == 0) && (udf_icbptr->loc.part_num == 0) && (udf_icbptr->len == 0)) return ENOENT; DEBUG(printf("udf_readin_anon_udf_node for %s\n", what)); error = udf_init_udf_node(/*mountpoint*/ NULL, udf_log_vol, what, &udf_node); DEBUG( if (error) printf("While reading in `anononymous' udf_node : got error %s\n", strerror(error)); ); if (error) return error; *udf_nodeptr = udf_node; assert(udf_log_vol); lb_size = udf_log_vol->lb_size; /* read in descriptor if not provided to us */ dscrptr = NULL; len = lb_size; /* nodes are defined in lb_size only (?) */ lb_num = udf_rw32(udf_icbptr->loc.lb_num); vpart_num = udf_rw16(udf_icbptr->loc.part_num); if (!given_dscrptr) { error = udf_read_logvol_descriptor(udf_log_vol, vpart_num, lb_num, what, &dscrptr, NULL); if (error) { *udf_nodeptr = NULL; return error; } } else { dscrptr = given_dscrptr; } fe_tag = udf_rw16(dscrptr->tag.id); if (fe_tag != TAGID_FENTRY && fe_tag != TAGID_EXTFENTRY) { /* something wrong with this address; it doesn't start with a file entry */ printf("UDF: bad udf_node for %s; got a %d tag\n", what, fe_tag); if (dscrptr != given_dscrptr) free(dscrptr); udf_dispose_udf_node(udf_node); *udf_nodeptr = NULL; return EFAULT; } /* get as much info as possible */ udf_node_get_fileinfo(udf_node, dscrptr); /* reset pending write count */ udf_node->v_numoutput = 0; /* initialise various variables for extracting allocation information */ inf_len = 0; data_length = 0; lb_num = 0; len = 0; vpart_num = 0; pos = NULL; data_space_avail = 0; next_alloc = calloc(1, sizeof(struct udf_allocentry)); if (!next_alloc) { if (dscrptr != given_dscrptr) free(dscrptr); udf_dispose_udf_node(udf_node); *udf_nodeptr = NULL; return ENOMEM; } next_alloc->len = lb_size; next_alloc->lb_num = udf_rw32(udf_icbptr->loc.lb_num); next_alloc->vpart_num = udf_rw16(udf_icbptr->loc.part_num); entries = 1; calculated_len = 0; error = 0; addr_type = -1; do { cur_alloc = next_alloc; next_alloc = calloc(1, sizeof(struct udf_allocentry)); if (!next_alloc) { if (dscrptr != given_dscrptr) free(dscrptr); udf_dispose_udf_node(udf_node); *udf_nodeptr = NULL; return ENOMEM; } memcpy(next_alloc, cur_alloc, sizeof(struct udf_allocentry)); TAILQ_INSERT_TAIL(&udf_node->dscr_allocs, cur_alloc, next_alloc); /* process this allocation descriptor */ /* note that we don't store the file descriptors -> XXX impl. use stuff gets lost here */ fe_tag = udf_rw16(dscrptr->tag.id); switch (fe_tag) { case TAGID_FENTRY : /* allocation descriptors follow this tag */ file_entry = &dscrptr->fe; entries = udf_rw16(file_entry->icbtag.max_num_entries); data_length = udf_rw32(file_entry->l_ad); pos = &file_entry->data[0] + udf_rw32(file_entry->l_ea); inf_len = udf_rw64(file_entry->inf_len); addr_type = udf_rw16(file_entry->icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK; data_space_avail = lb_size - sizeof(struct file_entry) - udf_rw32(file_entry->l_ea); /* process extended attributes */ /* keep a trace of the descriptors in this udf_node */ UDF_VERBOSE_MAX(udf_dump_file_entry(file_entry)); break; case TAGID_EXTFENTRY : /* allocation descriptors follow this tag */ extfile_entry = &dscrptr->efe; entries = udf_rw16(extfile_entry->icbtag.max_num_entries); data_length = udf_rw32(extfile_entry->l_ad); pos = &extfile_entry->data[0] + udf_rw32(extfile_entry->l_ea); inf_len = udf_rw64(extfile_entry->inf_len); addr_type = udf_rw16(extfile_entry->icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK; data_space_avail = lb_size - sizeof(struct extfile_entry) - udf_rw32(extfile_entry->l_ea); /* process extended attributes */ /* keep a trace of the descriptors in this udf_node */ UDF_VERBOSE_MAX(udf_dump_extfile_entry(extfile_entry)); break; case TAGID_ALLOCEXTENT : /* allocation descriptors follow this tag; treat as if continuation of a (ext)file entry*/ alloc_ext_entry = &dscrptr->aee; data_length = udf_rw32(alloc_ext_entry->l_ad); pos = &alloc_ext_entry->data[0]; assert(addr_type >= 0); /* keep a trace of the descriptors in this udf_node */ UDF_VERBOSE_MAX(udf_dump_alloc_extent(alloc_ext_entry, addr_type)); break; case TAGID_INDIRECT_ENTRY : printf("create_anon_udf_node called with indirect entry; following chain\n"); l_ad = &dscrptr->inde.indirect_icb; next_alloc->len = udf_rw32(l_ad->len); next_alloc->lb_num = udf_rw32(l_ad->loc.lb_num); next_alloc->vpart_num = udf_rw16(l_ad->loc.part_num); entries = 1; /* at least one more entry */ advance_sector = 0; /* don't advance to next sector */ UDF_VERBOSE_MAX(udf_dump_descriptor(dscrptr)); break; default: printf("read_file_part_extents: i can't be here! (tag = %d) in ICB hiargy of %s\n", fe_tag, what); udf_dump_descriptor(dscrptr); return EFAULT; } if (fe_tag != TAGID_INDIRECT_ENTRY) { udf_node->addr_type = addr_type; if (addr_type == UDF_ICB_INTERN_ALLOC) { udf_node->intern_len = inf_len; udf_node->intern_free = data_space_avail; udf_node->intern_data = calloc(1, udf_node->intern_free); if (udf_node->intern_data) { memcpy(udf_node->intern_data, pos, inf_len); } else { error = ENOMEM; } if (dscrptr != given_dscrptr) free(dscrptr); return error; } icb_len = 0; switch (udf_node->addr_type) { case UDF_ICB_SHORT_ALLOC : icb_len = sizeof(struct short_ad); break; case UDF_ICB_LONG_ALLOC : icb_len = sizeof(struct long_ad); break; default : printf("UDF encountered an unknown allocation type %d\n", udf_node->addr_type); break; } udf_node->icb_len = icb_len; advance_sector = 1; while (icb_len && data_length) { switch (udf_node->addr_type) { case UDF_ICB_SHORT_ALLOC : s_ad = (struct short_ad *) pos; len = udf_rw32(s_ad->len); lb_num = udf_rw32(s_ad->lb_num); vpart_num = cur_alloc->vpart_num; break; case UDF_ICB_LONG_ALLOC : l_ad = (struct long_ad *) pos; len = udf_rw32(l_ad->len); lb_num = udf_rw32(l_ad->loc.lb_num); vpart_num = udf_rw16(l_ad->loc.part_num); if (l_ad->impl.im_used.flags & UDF_ADIMP_FLAGS_EXTENT_ERASED) { printf("UDF: got a `extent erased' flag in a file's long_ad; ignoring\n"); } break; default : printf("UDF encountered an unknown allocation type %d\n", udf_node->addr_type); break; } /* ecma-167 48.14.1.1 */ flags = (uint8_t) ((uint32_t) (len >> 30) & 3); len = len & ((1<<30)-1); if (flags == UDF_SPACE_REDIRECT) { /* fill in next extent */ next_alloc->len = len; next_alloc->lb_num = lb_num; next_alloc->vpart_num = vpart_num; advance_sector = 0; /* don't advance to next sector */ icb_len = data_length; /* must be last */ printf("Continuing extent flagged at vpart = %d, lb_num = %d, len = %d\n", (int) vpart_num, (int) lb_num, (int) len); } else { if (len) { alloc_entry = calloc(1, sizeof(struct udf_allocentry)); if (!alloc_entry) { if (dscrptr != given_dscrptr) free(dscrptr); return ENOMEM; } alloc_entry->len = len; alloc_entry->lb_num = lb_num; alloc_entry->vpart_num = vpart_num; alloc_entry->flags = flags; TAILQ_INSERT_TAIL(&udf_node->alloc_entries, alloc_entry, next_alloc); } calculated_len += len; } data_length -= icb_len; pos += icb_len; } /* while */ if (advance_sector) { /* Note: UDF descriptor length is maximised to one sector */ next_alloc->lb_num++; /* advance one sector */ entries--; } } /* indirect ICB check */ if (entries) { /* load in new dscrptr */ if (dscrptr != given_dscrptr) free(dscrptr); error = udf_read_logvol_descriptor(udf_log_vol, next_alloc->vpart_num, next_alloc->lb_num, what, &dscrptr, NULL); } } while (entries && !error); /* error from reading next sector in extent is not considered an error */ if (dscrptr != given_dscrptr && dscrptr) free(dscrptr); if (calculated_len != (uint64_t) udf_node->stat.st_size) { printf("UDF: create node length mismatch; stated as %g but calculated as %g bytes. fixing\n", (double) udf_node->stat.st_size, (double) calculated_len); udf_node->stat.st_size = calculated_len; } return 0; } int udf_readin_udf_node(struct udf_node *dir_node, struct long_ad *udf_icbptr, struct fileid_desc *fid, struct udf_node **res_sub_node) { struct udf_node *sub_node; char *fid_name; char entry_name[NAME_MAX]; uint32_t bucket; ino_t hashkey; int error; assert(dir_node); assert(udf_icbptr); assert(fid); assert(res_sub_node); /* check if its allready in the logical volume's udf_node cache (inodes) */ hashkey = udf_calc_hash(udf_icbptr); bucket = hashkey & UDF_INODE_HASHMASK; LIST_FOREACH(sub_node, &dir_node->udf_log_vol->udf_nodes[bucket], next_node) { if (sub_node->hashkey == hashkey) { *res_sub_node = sub_node; DEBUG(printf("found node in hashlist\n")); return 0; } } /* dump the FID we are trying to read in */ UDF_VERBOSE_MAX(udf_dump_descriptor((union dscrptr *) fid)); fid_name = (char *) fid->data + udf_rw16(fid->l_iu); udf_to_unix_name(entry_name, fid_name, fid->l_fi, &dir_node->udf_log_vol->log_vol->desc_charset); /* build missing vnode */ error = udf_readin_anon_udf_node(dir_node->udf_log_vol, NULL, udf_icbptr, entry_name, &sub_node); if (error) return error; if (!sub_node) { printf("sub_node = NULL? and no error? \n"); } assert(sub_node); /* link this UDF node to the mountpoint and remember its hash-key */ sub_node->mountpoint = dir_node->mountpoint; sub_node->hashkey = hashkey; /* XXX use file version number and filechar from fid ? */ sub_node->file_version_num = udf_rw16(fid->file_version_num); /* user set */ sub_node->udf_filechar = fid->file_char; /* insert/replace in mountpoint's udfnode hashtable with optional check for doubles */ if (0) { struct udf_node *lookup; LIST_FOREACH(lookup, &dir_node->udf_log_vol->udf_nodes[bucket], next_node) { if (lookup->hashkey == sub_node->hashkey) printf("DOUBLE hashnode?\n"); } } LIST_INSERT_HEAD(&dir_node->udf_log_vol->udf_nodes[bucket], sub_node, next_node); DEBUG(printf("inserting hash node for hash = %d\n", (int) hashkey)); *res_sub_node = sub_node; return 0; } void udf_syncnode_callback(int reason, struct udf_wrcallback *wrcallback, int error, uint8_t *sectordata) { /* struct udf_node *udf_node = (struct udf_node *) wrcallback->structure; */ wrcallback = wrcallback; /* unused for now */ sectordata = sectordata; if (reason == UDF_WRCALLBACK_REASON_PENDING) { /* what to do? */ return; } if (reason == UDF_WRCALLBACK_REASON_ANULATE) { /* what to do? */ return; } assert(reason == UDF_WRCALLBACK_REASON_WRITTEN); if (error) { printf("UDF error: syncnode writing failed, not fixing yet!\n"); return; } } /* XXX This mark node dirty code will simplify if we store nodes in buffers? XXX */ void udf_node_mark_dirty(struct udf_node *udf_node) { struct udf_allocentry *alloc_entry, *my_entry, *tail_entry; struct udf_node *search_node, *tail_node; if (udf_node->dirty) return; my_entry = TAILQ_FIRST(&udf_node->dscr_allocs); assert(my_entry); /* dscr locks ? */ UDF_MUTEX_LOCK(&udf_node->udf_log_vol->dirty_nodes_mutex); if (1) { /* insertion sort :-S */ tail_node = TAILQ_LAST(&udf_node->udf_log_vol->dirty_nodes, udf_node_list); if (!tail_node) { TAILQ_INSERT_TAIL(&udf_node->udf_log_vol->dirty_nodes, udf_node, next_dirty); } else { tail_entry = TAILQ_FIRST(&tail_node->dscr_allocs); if (tail_entry->lb_num < my_entry->lb_num) { TAILQ_INSERT_TAIL(&udf_node->udf_log_vol->dirty_nodes, udf_node, next_dirty); } else { /* find my place; could be done smarter */ TAILQ_FOREACH(search_node, &udf_node->udf_log_vol->dirty_nodes, next_dirty) { alloc_entry = TAILQ_FIRST(&tail_node->dscr_allocs); if (alloc_entry->lb_num > my_entry->lb_num) { TAILQ_INSERT_BEFORE(search_node, udf_node, next_dirty); break; /* foreach */ } } } } } else { /* dumb */ TAILQ_INSERT_TAIL(&udf_node->udf_log_vol->dirty_nodes, udf_node, next_dirty); } UDF_MUTEX_UNLOCK(&udf_node->udf_log_vol->dirty_nodes_mutex); udf_node->dirty = 1; } static void udf_node_unmark_dirty(struct udf_node *udf_node) { if (!udf_node->dirty) return; /* remove me just in case; why were we called otherwise? */ UDF_MUTEX_LOCK(&udf_node->udf_log_vol->dirty_nodes_mutex); TAILQ_REMOVE(&udf_node->udf_log_vol->dirty_nodes, udf_node, next_dirty); UDF_MUTEX_UNLOCK(&udf_node->udf_log_vol->dirty_nodes_mutex); udf_node->dirty = 0; } /* VOP_FSYNC : data FDATASYNC */ int udf_sync_udf_node(struct udf_node *udf_node, char *why) { DEBUG(printf("Syncing udf_node `%"PRIu64"` because of %s\n", udf_node->unique_id, why)); DEBUG(printf("sync udf node: dirty = %d, v_numoutput = %d\n", udf_node->dirty, udf_node->v_numoutput)); if (!udf_node->dirty) { /* Not dirty??!!! */ udf_node_unmark_dirty(udf_node); return 0; } if (!udf_node->udf_log_vol->writable) { fprintf(stderr, "encountered a dirty node on a read-only filingsystem!\n"); exit(1); } /* * We are really syncing disc but we are only continueing when the * node itself is clean... not breaking the semantics. */ /* XXX flushall flag magic XXX */ udf_bufcache->flushall = 1; udf_purgethread_kick("Sync node"); fflush(stdout); /* wait until all dirty bufs associated with this node are processed */ if (!udf_node->dirty) return 0; if (udf_node->v_numoutput) { usleep(100); } if (!udf_node->v_numoutput) return 0; UDF_VERBOSE(printf("(wait on node)")); while (udf_node->v_numoutput) { usleep(100); } return 0; } extern void udf_merge_allocentry_queue(struct udf_alloc_entries *queue, uint32_t lb_size); /* VOP_FSYNC : metadata FFILESYNC */ /* writeout the udf_node back to disc */ /* TODO don't forget to writeout our extended attributes and write out the link to the associated streamdir as well */ int udf_writeout_udf_node(struct udf_node *udf_node, char *why) { struct udf_wrcallback wr_callback; struct udf_allocentry *dscr_entry, *next_dscr_entry, *alloc_entry; union dscrptr *dscrptr; struct file_entry *fe; struct extfile_entry *efe; struct alloc_ext_entry *aee; struct lb_addr parent_icb; struct icb_tag *icbtag; struct long_ad *l_ad; struct short_ad *s_ad; uint32_t *l_adptr; /* points to length of alloc. descr. */ uint8_t *pos; char *what; uint32_t alloc_entries; uint64_t rest; /* in bytes */ uint64_t len; uint64_t logblks_rec; uint32_t lb_size, descr_ver; if (!udf_node->udf_log_vol->writable) { fprintf(stderr, "encountered a dirty node on a read-only filingsystem!\n"); exit(1); } lb_size = udf_node->udf_log_vol->lb_size; /* assure all file data is written out! and clean up */ udf_sync_udf_node(udf_node, why); /* XXX node lock? XXX */ UDF_MUTEX_LOCK(&udf_node->alloc_mutex); /* clean up allocentry queue so we get a nice clean layout */ udf_merge_allocentry_queue(&udf_node->alloc_entries, lb_size); UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex); /* allocate for descriptor */ dscrptr = calloc(1, lb_size); /* not a bit biggish? */ if (!dscrptr) return ENOMEM; /* calculate logical blocks recorded; zero for interns [UDF 2.3.6.5, ECMA 4/14.9.11, 4/14.6.8] */ logblks_rec = 0; if (udf_node->addr_type != UDF_ICB_INTERN_ALLOC) { UDF_MUTEX_LOCK(&udf_node->alloc_mutex); TAILQ_FOREACH(alloc_entry, &udf_node->alloc_entries, next_alloc) { if (alloc_entry->flags == UDF_SPACE_ALLOCATED) { logblks_rec += (alloc_entry->len + lb_size-1) / lb_size; } } UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex); } /* fill in (ext)fentry descriptor */ /* copy descriptor version from the logvol's */ bzero(&parent_icb, sizeof(struct lb_addr)); descr_ver = udf_rw16(udf_node->udf_log_vol->log_vol->tag.descriptor_ver); if (descr_ver == 3) { efe = &dscrptr->efe; efe->tag.id = udf_rw16(TAGID_EXTFENTRY); efe->tag.descriptor_ver = udf_rw16(descr_ver); efe->ckpoint = udf_rw32(1); /* [ECMA 4/14.17.17] */ udf_set_imp_id(&efe->imp_id); efe->logblks_rec = udf_rw64(logblks_rec); /* set additional fileinfo (access, uid/gid) etc. */ udf_node_set_fileinfo(udf_node, dscrptr); efe->obj_size = efe->inf_len; /* not true if there are streams [ECMA 4/48.17.11] */ icbtag = &efe->icbtag; } else if (descr_ver == 2) { fe = &dscrptr->fe; fe->tag.id = udf_rw16(TAGID_FENTRY); fe->tag.descriptor_ver = udf_rw16(descr_ver); fe->ckpoint = udf_rw32(1); /* [ECMA 4/14.17.17] */ udf_set_imp_id(&fe->imp_id); fe->logblks_rec = udf_rw64(logblks_rec); /* set additional fileinfo (access, uid/gid) etc. */ udf_node_set_fileinfo(udf_node, dscrptr); /* fe->obj_size doesn't exist */ icbtag = &fe->icbtag; } else { printf("UDF: i don't know this descriptor version %d\n", descr_ver); return EBADF; } /* update derived info */ udf_node->udf_icbtag_flags = (udf_node->udf_icbtag_flags & ~UDF_ICB_TAG_FLAGS_ALLOC_MASK) | udf_node->addr_type; /* strategy 4 has no parent nodes */ /* XXX NO extended attributes recorded YET (!!) XXX (like device nodes !!! ) */ dscr_entry = TAILQ_FIRST(&udf_node->dscr_allocs); /* ensure allocation of (ext) file descriptor */ if (!dscr_entry) { /* have to allocate one and add to queue ! */ printf("UDF: XXX no allocation of file descriptor entry yet in sync_udf_node\n"); return ENOENT; } /* XXX implement alloc entry walker? XXX */ UDF_MUTEX_LOCK(&udf_node->alloc_mutex); what = "UDF sync: File descriptor"; alloc_entry = TAILQ_FIRST(&udf_node->alloc_entries); do { assert(dscr_entry->len <= lb_size); if (icbtag) { /* fill in ICB fields */ /* XXX we're only writing out strategy type 4 !!! XXX */ icbtag->prev_num_dirs = udf_rw32(0); /* prev_alloc_entries = 0 due to strategy type 4 XXX */ icbtag->strat_type = udf_rw16(4); /* default UDF strategy type 4 XXX what about 4096? */ icbtag->parent_icb = parent_icb; icbtag->file_type = udf_node->udf_filetype; icbtag->flags = udf_rw16(udf_node->udf_icbtag_flags); icbtag->max_num_entries = udf_rw16(1); /* due to strategy type 4 ! XXX */ } pos = 0; rest = 0; l_adptr = NULL; /* invalid */ switch (udf_rw16(dscrptr->tag.id)) { case TAGID_FENTRY : /* not used now */ fe = &dscrptr->fe; pos = &fe->data[0] + udf_rw32(fe->l_ea); rest = dscr_entry->len - sizeof(struct file_entry) - udf_rw32(fe->l_ea); l_adptr = &fe->l_ad; break; case TAGID_EXTFENTRY : efe = &dscrptr->efe; pos = &efe->data[0] + udf_rw32(efe->l_ea); rest = dscr_entry->len - sizeof(struct extfile_entry) - udf_rw32(efe->l_ea); l_adptr = &efe->l_ad; break; case TAGID_ALLOCEXTENT : aee = &dscrptr->aee; pos = &aee->data[0]; rest = dscr_entry->len - sizeof(struct alloc_ext_entry); l_adptr = &aee->l_ad; break; case TAGID_INDIRECT_ENTRY : /* do we even do these in strat 4 ? */ printf("UDF: sanity check; request for writeout of indirect entry\n"); free(dscrptr); UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex); return ENOENT; /* panic really */ } assert(l_adptr); /* fill in remaining allocation entries */ /* remember to keep one SPARE for extending */ alloc_entries = 0; DEBUG(printf("Allocated at ")); if (udf_node->addr_type == UDF_ICB_INTERN_ALLOC) { /* internal allocation -> copy in data */ assert(udf_node->intern_len <= rest); bzero(pos, rest); memcpy(pos, udf_node->intern_data, udf_node->intern_len); /* make sure the length for allocation entries is the same as the data it contains (4/8.8.2, 4/14.6.8) */ *l_adptr = udf_rw32(udf_node->intern_len); /* alloc_entry is zero, so it'll fall trough */ pos += udf_node->intern_len; /* advance pos for length calculation */ alloc_entry = NULL; /* not applicable */ } while ((rest > 2*udf_node->icb_len) && alloc_entry) { assert(udf_node->icb_len); DEBUG(printf("[%p, lb_num = %d, len = %d] ", alloc_entry, (uint32_t) alloc_entry->lb_num, (uint32_t) alloc_entry->len)); /* XXX assumption: UDF_SPACE_* is equal to UDF flags XXX */ len = alloc_entry->len | (((uint32_t) alloc_entry->flags) << 30); switch (udf_node->addr_type) { case UDF_ICB_SHORT_ALLOC : s_ad = (struct short_ad *) pos; s_ad->len = udf_rw32(len); s_ad->lb_num = udf_rw32(alloc_entry->lb_num); assert(alloc_entry->vpart_num == 0); if (alloc_entry->len == 0) s_ad->lb_num = udf_rw32(0); if (alloc_entry->flags == UDF_SPACE_FREE) s_ad->lb_num = udf_rw32(0); break; case UDF_ICB_LONG_ALLOC : l_ad = (struct long_ad *) pos; l_ad->len = udf_rw32(len); l_ad->loc.lb_num = udf_rw32(alloc_entry->lb_num); l_ad->loc.part_num = udf_rw16(alloc_entry->vpart_num); l_ad->impl.im_used.unique_id = udf_rw64(udf_node->unique_id); if (alloc_entry->len == 0) l_ad->loc.lb_num = udf_rw32(0); if (alloc_entry->flags == UDF_SPACE_FREE) l_ad->loc.lb_num = udf_rw32(0); break; } alloc_entries++; *l_adptr = udf_rw32(alloc_entries * udf_node->icb_len); alloc_entry = TAILQ_NEXT(alloc_entry, next_alloc); pos += udf_node->icb_len; rest -= udf_node->icb_len; } DEBUG(printf("\nend alloc\n\n")); next_dscr_entry = TAILQ_NEXT(dscr_entry, next_alloc); if (alloc_entry) { /* overflow */ /* ensure allocation of (ext) file descriptor */ if (!next_dscr_entry) { /* have to allocate one and add to queue ! */ printf("UDF: XXX no allocation of allocation extent descriptor yet in sync_udf_node\n"); UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex); return ENOENT; } /* flag next extent being specified */ len = next_dscr_entry->len | ((uint32_t) UDF_SPACE_REDIRECT << 30); switch (udf_node->addr_type) { case UDF_ICB_SHORT_ALLOC : s_ad = (struct short_ad *) pos; s_ad->len = udf_rw32(len); s_ad->lb_num = udf_rw32(next_dscr_entry->lb_num); assert(next_dscr_entry->vpart_num == 0); break; case UDF_ICB_LONG_ALLOC : l_ad = (struct long_ad *) pos; l_ad->len = udf_rw32(len); l_ad->loc.lb_num = udf_rw32(next_dscr_entry->lb_num); l_ad->loc.part_num = udf_rw16(next_dscr_entry->vpart_num); l_ad->impl.im_used.unique_id = udf_rw64(udf_node->unique_id); break; } alloc_entries++; pos += udf_node->icb_len; rest -= udf_node->icb_len; } /* manage lengths */ dscrptr->tag.desc_crc_len = udf_rw16((pos - (uint8_t *) dscrptr) - UDF_DESC_TAG_LENGTH); /* writeout */ wr_callback.function = udf_syncnode_callback; #if 0 wr_callback.structure = (void *) udf_node; wr_callback.vpart_num = dscr_entry->vpart_num; wr_callback.lb_num = dscr_entry->lb_num; wr_callback.offset = 0; /* ? */ wr_callback.length = dscr_entry->len; #endif UDF_VERBOSE_MAX( udf_validate_tag_and_crc_sums(dscrptr); /* for dumping */ udf_dump_descriptor(dscrptr); ); errno = udf_write_logvol_descriptor(udf_node->udf_log_vol, dscr_entry->vpart_num, dscr_entry->lb_num, what, dscrptr, &wr_callback); /* advance */ if (alloc_entry) { dscr_entry = next_dscr_entry; assert(dscr_entry); /* allocate and initialise new allocation extent descriptor */ /* also flag no icbtag follows */ bzero(dscrptr, lb_size); aee = &dscrptr->aee; aee->tag.id = udf_rw16(TAGID_ALLOCEXTENT); aee->tag.descriptor_ver = udf_node->udf_log_vol->log_vol->tag.descriptor_ver; icbtag = NULL; what = "UDF sync: allocation extent"; } } while (alloc_entry); UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex); /* XXX Free extra non used allocation extent descriptors XXX */ /* Mark me clean */ if (udf_node->mountpoint) { /* remove me just in case; why were we called otherwise? */ udf_node_unmark_dirty(udf_node); } return 0; } /****************************************************************************************** * * Space bitmap reader and writer * ******************************************************************************************/ /* tested OK */ int udf_read_in_space_bitmap(struct udf_alloc_entries *queue, struct space_bitmap_desc *sbd, uint32_t lb_size, uint64_t *freespace) { struct udf_allocentry *alloc_entry; uint64_t bits, from, now, start, end; uint8_t byte, bit, bitpos, state, *pos; int cnt; assert(udf_rw16(sbd->tag.id) == TAGID_SPACE_BITMAP); DEBUG(printf("processing space bitmap : \n");); bits = udf_rw32(sbd->num_bits); /* * Mark the disc as completely full; * Bugallert: use `udf_mark_allocentry_queue()' for the extent might * not fit in just one alloc entry for bigger discs */ assert(TAILQ_EMPTY(queue)); udf_mark_allocentry_queue(queue, lb_size, 0, bits * lb_size, UDF_SPACE_ALLOCATED, NULL, NULL); pos = sbd->data; from = 0; now = 0; bitpos = 0; byte = *pos; state = byte & 1; *freespace = 0; while (now < bits) { if (bitpos == 0) { byte = *pos++; } bit = byte & 1; if (bit != state) { if (state) { start = from; end = now-1; /* printf("[%08d - %08d]", start, end); */ udf_mark_allocentry_queue(queue, lb_size, start*lb_size, (end-start+1)*lb_size, UDF_SPACE_FREE, NULL, NULL); *freespace += (end-start+1)*lb_size; } from = now; state = bit; } byte >>= 1; bitpos = (bitpos+1) & 7; now++; } if (state) { start = from; end = now; /* printf("[%08d - %08d]", start, end); */ udf_mark_allocentry_queue(queue, lb_size, start*lb_size, (end-start)*lb_size, UDF_SPACE_FREE, NULL, NULL); *freespace += (end-start)*lb_size; } UDF_VERBOSE_TABLES( printf("\t\tFree space found on this partition"); cnt = 0; start = 0; TAILQ_FOREACH(alloc_entry, queue, next_alloc) { if (alloc_entry->flags == UDF_SPACE_ALLOCATED) { /* printf("... "); */ } else { if (cnt == 0) printf("\n\t\t\t"); printf("[%08"PRIu64" - %08"PRIu64"] ", start / lb_size, ((start + alloc_entry->len) / lb_size)-1); cnt++; if (cnt > 4) cnt = 0; } start += alloc_entry->len; } printf("\n"); ); /* merge is not nessisary */ return 0; } /* inverse of readin space bitmap; it synchronises the bitmap with the queue */ /* tested OK */ int udf_sync_space_bitmap(struct udf_alloc_entries *queue, struct space_bitmap_desc *sbd, uint32_t lb_size) { struct udf_allocentry *alloc_entry; uint32_t start, bits, total_bits; uint32_t cnt, byte; uint8_t bit, bitmask, setting; uint8_t *pos; /* merge it just in case */ udf_merge_allocentry_queue(queue, lb_size); total_bits = udf_rw32(sbd->num_bits); DEBUG(printf("SYNC SPACE BITMAP DEBUG: total bits = %d\n", total_bits)); alloc_entry = TAILQ_FIRST(queue); start = alloc_entry->lb_num; assert(start == 0); TAILQ_FOREACH(alloc_entry, queue, next_alloc) { DEBUG(printf(" [%d : %d + %d]", alloc_entry->flags, alloc_entry->lb_num, alloc_entry->len)); bits = alloc_entry->len / lb_size; assert(bits*lb_size == alloc_entry->len); byte = start / 8; bit = start - byte*8; pos = sbd->data + byte; if (byte*8 + bit + bits > total_bits) { /* XXX > or >= ? */ /* this should NEVER happen */ printf("UDF: not enough space writing back space bitmap! HELP!\n"); return EBADF; } cnt = 0; setting = (alloc_entry->flags != UDF_SPACE_FREE) ? 0 : 255; while (cnt < bits) { bitmask = (1 << bit); /* simple sanity check */ if (byte*8 + bit >= total_bits) { printf("IEEEE!!!! too big; %d instead of %d\n", (byte*8 + bit), total_bits); } *pos = (*pos & (~bitmask)) | (setting ? bitmask: 0); cnt++; bit++; if (bit == 8) { /* byte transition */ byte++; bit = 0; pos++; #if 0 /* speedup by doing bytes at a time */ while (bits-cnt > 8) { *pos = setting; cnt += 8; pos++; byte++; } #endif } } start += bits; } DEBUG(printf("\n\n")); return 0; } /****************************************************************************************** * * Filepart readers and writers * ******************************************************************************************/ /* part of VOP_STRATEGY */ /* internal function; reads in a new buffer */ /* !!! bufcache lock ought to be held on entry !!! */ int udf_readin_file_buffer(struct udf_node *udf_node, char *what, uint32_t sector, int cache_flags, struct udf_buf **buf_entry_p) { struct udf_allocentry *alloc_entry; struct udf_buf *buf_entry; uint64_t cur_offset; uint64_t overlap_length, overlap_sectors, transfer_length; uint32_t lb_size; uint32_t len, lb_num, vpart_num; int32_t error; uint8_t flags; assert(udf_node); assert(buf_entry_p); assert(udf_bufcache->bufcache_lock.locked); error = udf_get_buf_entry(udf_node, buf_entry_p); if (error) return error; buf_entry = *buf_entry_p; lb_size = udf_node->udf_log_vol->lb_size; /* internal node? */ if (udf_node->addr_type == UDF_ICB_INTERN_ALLOC) { buf_entry->b_lblk = 0; buf_entry->b_flags = 0; /* not dirty, not needing alloc */ buf_entry->b_bcount = udf_node->intern_len; buf_entry->b_resid = lb_size - udf_node->intern_len; memcpy(buf_entry->b_data, udf_node->intern_data, udf_node->intern_len); UDF_MUTEX_LOCK(&udf_node->buf_mutex); udf_attach_buf_to_node(udf_node, buf_entry); UDF_MUTEX_UNLOCK(&udf_node->buf_mutex); return error; } /* `normal' node */ /* find sector in the allocation space */ UDF_MUTEX_LOCK(&udf_node->alloc_mutex); cur_offset = 0; error = EIO; /* until proven readable */ TAILQ_FOREACH(alloc_entry, &udf_node->alloc_entries, next_alloc) { len = alloc_entry->len; lb_num = alloc_entry->lb_num; vpart_num = alloc_entry->vpart_num; flags = alloc_entry->flags; /* check overlap with this alloc entry */ if (cur_offset + len > sector * lb_size) { /* found an extent that fits */ assert(((sector * lb_size - cur_offset) % lb_size) == 0); /* ought to be on sector boundary */ lb_num += sector - (cur_offset / lb_size); overlap_length = cur_offset + len - sector * lb_size; overlap_sectors = (overlap_length + lb_size -1) / lb_size; transfer_length = MIN(lb_size, overlap_length); /* max one logical sector */ /* fill in new buf info */ buf_entry->b_lblk = sector; buf_entry->b_bcount = transfer_length; buf_entry->b_resid = lb_size - transfer_length; /* sector transfered; mark valid */ buf_entry->b_flags = 0; /* not dirty and valid */ switch (flags) { case UDF_SPACE_ALLOCATED : /* on disc or in the write queue/cache to be written out; read one block at a time */ error = udf_read_logvol_sector(udf_node->udf_log_vol, vpart_num, lb_num, what, buf_entry->b_data, overlap_sectors, cache_flags); break; case UDF_SPACE_FREE : /* fall trough */ case UDF_SPACE_ALLOCATED_BUT_NOT_USED : error = 0; bzero(buf_entry->b_data, lb_size); break; default : fprintf(stderr, "Got an redirect flag, can't happen\n"); break; } if (error) { fprintf(stderr, "\tgot error from read_logvol_sector : %s\n", strerror(error)); break; /* FOREACH */ } UDF_MUTEX_LOCK(&udf_node->buf_mutex); udf_attach_buf_to_node(udf_node, buf_entry); UDF_MUTEX_UNLOCK(&udf_node->buf_mutex); UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex); return 0; } /* looking for overlap */ cur_offset += len; } /* FOREACH */ UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex); *buf_entry_p = NULL; udf_mark_buf_clean(udf_node, buf_entry); /* its destroyed so not dirty */ udf_mark_buf_allocated(udf_node, buf_entry); /* i.e. taken care of */ udf_free_buf_entry(buf_entry); return error; } /* internal function; shedule writing out of a buffer */ /* part of VOP_STRATEGY */ int udf_writeout_file_buffer(struct udf_node *udf_node, char *what, int cache_flags, struct udf_buf *buf_entry) { struct udf_allocentry *from_alloc, *to_alloc, *alloc_entry; uint32_t lb_num, lb_size, lblk; uint16_t vpart_num; int error; what = what; /* not used now */ if (!udf_node->udf_log_vol->writable) { /* ieek */ fprintf(stderr, "write request from non writable file buffer?\n"); } /* first get logical block offset and block size */ lblk = buf_entry->b_lblk; lb_size = udf_node->udf_log_vol->lb_size; error = 0; UDF_MUTEX_LOCK(&udf_bufcache->bufcache_lock); UDF_MUTEX_LOCK(&udf_node->alloc_mutex); UDF_MUTEX_LOCK(&udf_node->buf_mutex); /* maybe a bit too strict locking; code is not winning the beauty contest */ /* check if we can convert/save disc space */ if (udf_node->stat.st_size <= udf_node->intern_free) { /* convert to internal alloc with backup storage (writing there) */ if (udf_node->addr_type != UDF_ICB_INTERN_ALLOC) { DEBUG(printf("CONVERTING to intern alloc\n")); /* first free all previously allocated sectors (if any) */ error = udf_node_release_extent(udf_node, 0, udf_node->stat.st_size); } assert(!error); if (!udf_node->intern_data) { udf_node->intern_data = calloc(1, udf_node->intern_free); } if (udf_node->intern_data) { assert(buf_entry->b_bcount <= udf_node->intern_free); memcpy(udf_node->intern_data, buf_entry->b_data, buf_entry->b_bcount); udf_node->intern_len = buf_entry->b_bcount; udf_node->addr_type = UDF_ICB_INTERN_ALLOC; /* we don't write here: mark buffer clean */ udf_mark_buf_clean(udf_node, buf_entry); udf_mark_buf_allocated(udf_node, buf_entry); /* signal its allocated */ buf_entry->b_flags &= ~(B_ERROR); /* check if all buffers are gone now and mark node for writeout to indicate state change */ assert(udf_node->v_numoutput == 0); udf_node_mark_dirty(udf_node); UDF_MUTEX_UNLOCK(&udf_node->buf_mutex); UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex); UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock); return 0; } /* fall trough ... for some reason it isn't converted */ } else { if (udf_node->addr_type == UDF_ICB_INTERN_ALLOC) { DEBUG(printf("CONVERTING to normal alloc\n")); /* won't fit anymore, have to turn it into a `normal' alloced */ udf_node->intern_len = 0; if (udf_node->intern_data) free(udf_node->intern_data); udf_node->intern_data = NULL; udf_node->icb_len = sizeof(struct long_ad); udf_node->addr_type = UDF_ICB_LONG_ALLOC; udf_node_mark_dirty(udf_node); /* mark needalloc to make sure it gets an address */ udf_mark_buf_needing_allocate(udf_node, buf_entry); /* signal it needs allocation */ } } /* merge queue first to get better performance */ udf_merge_allocentry_queue(&udf_node->alloc_entries, lb_size); /* get extent that it represents */ udf_mark_allocentry_queue(&udf_node->alloc_entries, lb_size, (uint64_t) lblk*lb_size, buf_entry->b_bcount, UDF_SPACE_ALLOCATED, &from_alloc, &to_alloc); alloc_entry = from_alloc; if (buf_entry->b_flags & B_NEEDALLOC) { /* need allocation */ error = udf_node_allocate_lbs(udf_node, /* num lb */ 1, &vpart_num, &lb_num, NULL); assert(!error); udf_mark_buf_allocated(udf_node, buf_entry); alloc_entry->lb_num = lb_num; alloc_entry->vpart_num = vpart_num; } assert(TAILQ_NEXT(alloc_entry, next_alloc) == to_alloc || (alloc_entry == to_alloc)); lb_num = alloc_entry->lb_num; vpart_num = alloc_entry->vpart_num; UDF_MUTEX_UNLOCK(&udf_node->buf_mutex); UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex); UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock); /* printf("writing out filebuffer vpart %d, lb_num %d for %s\n", vpart_num, lb_num, what); */ error = udf_write_logvol_sector(udf_node->udf_log_vol, vpart_num, lb_num, "File contents", buf_entry->b_data, cache_flags, NULL); UDF_MUTEX_LOCK(&udf_bufcache->bufcache_lock); UDF_MUTEX_LOCK(&udf_node->buf_mutex); if (error) { printf("YIKES error during writing of logvol_sector\n"); udf_mark_buf_needing_allocate(udf_node, buf_entry); buf_entry->b_flags |= B_ERROR; /* buf_entry->b_errno = error; */ } else { udf_mark_buf_clean(udf_node, buf_entry); buf_entry->b_flags &= ~(B_ERROR); } UDF_MUTEX_UNLOCK(&udf_node->buf_mutex); UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock); return error; } /* VOP_READ */ int udf_read_file_part_uio(struct udf_node *udf_node, char *what, int content, struct uio *data_uio) { struct udf_buf *buf_entry; off_t offset; uint64_t sector, lb_size, data_length; uint8_t *base; int error, short_buf; if (!udf_node) return EINVAL; /* NOTE: we are NOT marking the node dirty only by reading it */ udf_set_timespec_now(&udf_node->stat.st_atimespec); if (udf_node->stat.st_size == 0) { if (data_uio->uio_resid) return EIO; /* reading past end by default */ return 0; } lb_size = udf_node->udf_log_vol->lb_size; error = 0; while (data_uio->uio_resid) { error = 0; short_buf = 0; sector = data_uio->uio_offset / lb_size; /* lookup sector in buffer set */ UDF_MUTEX_LOCK(&udf_bufcache->bufcache_lock); udf_lookup_node_buf(udf_node, sector, &buf_entry); if (!buf_entry || (buf_entry && (buf_entry->b_lblk != sector))) { /* `page in' sector from file */ error = udf_readin_file_buffer(udf_node, what, sector, content, &buf_entry); } if (!error && buf_entry) { offset = data_uio->uio_offset - (off_t) sector*lb_size; base = buf_entry->b_data; if (offset >= 0) { data_length = buf_entry->b_bcount - offset; data_length = MIN(data_length, data_uio->uio_resid); uiomove(base + offset, data_length, data_uio); } short_buf = (buf_entry->b_bcount < lb_size); /* short buf -> none will follow */ } assert(!error || (error && !buf_entry)); UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock); if (error) break; /* while */ if (data_uio->uio_resid == 0) return 0; /* finished? */ if (short_buf) break; /* while */ } /* while */ if (data_uio->uio_resid) { printf("UDF: WARNING file is truncated; missing %d bytes while reading %s\n", (int) data_uio->uio_resid, what); return EIO; } return error; } /* XXX meaning is to be changed; kept for reference still XXX */ void udf_filepart_write_callback(int reason, struct udf_wrcallback *wrcallback, int error, uint8_t *sectordata) { /* struct udf_node *udf_node = (struct udf_node *) wrcallback->structure; */ wrcallback = wrcallback; /* unused for now */ sectordata = sectordata; if (reason == UDF_WRCALLBACK_REASON_PENDING) { /* what to do? */ return; } if (reason == UDF_WRCALLBACK_REASON_ANULATE) { /* what to do? */ return; } assert(reason == UDF_WRCALLBACK_REASON_WRITTEN); if (error) { printf("UDF error: file part write failed, not fixing yet!\n"); return; } } /* VOP_TRUNCATE */ /* doesn't lock udf_node */ int udf_truncate_node(struct udf_node *udf_node, uint64_t length /* ,ioflags */) { struct udf_log_vol *udf_log_vol; struct udf_allocentry *alloc_entry, *cut_point; struct udf_buf *buf_entry, *marker; uint32_t lb_size; uint64_t cur_extent, block_extent, new_extent, too_much; uint32_t last_sector; int32_t error; if (!udf_node) return EINVAL; if (udf_open_logvol(udf_node->udf_log_vol)) return EROFS; udf_log_vol = udf_node->udf_log_vol; lb_size = udf_log_vol->lb_size; /* we might change this node AND access times ... */ if (!udf_node->dirty) { /* mark node as dirty */ udf_node_mark_dirty(udf_node); } /* XXX lock node !!! XXX */ /* merge known allocation entry queue */ new_extent = length; block_extent = (uint64_t) lb_size * ((new_extent + lb_size-1) / lb_size); /* inclusive */ too_much = block_extent - new_extent; assert(block_extent >= new_extent); UDF_MUTEX_LOCK(&udf_bufcache->bufcache_lock); UDF_MUTEX_LOCK(&udf_node->alloc_mutex); udf_merge_allocentry_queue(&udf_node->alloc_entries, lb_size); /* extend the file when nessisary */ if (new_extent > (uint64_t) udf_node->stat.st_size) { if (udf_node->addr_type == UDF_ICB_INTERN_ALLOC) { /* XXX to seperate function XXX */ /* grow intern node by converting it to a normal buffer first */ /* First lookup if the node already had a buffer associated */ udf_lookup_node_buf(udf_node, 0, &buf_entry); if (!buf_entry) { error = udf_get_buf_entry(udf_node, &buf_entry); if (error) { UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex); UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock); return error; } buf_entry->b_lblk = 0; buf_entry->b_flags = 0; UDF_MUTEX_LOCK(&udf_node->buf_mutex); udf_attach_buf_to_node(udf_node, buf_entry); UDF_MUTEX_UNLOCK(&udf_node->buf_mutex); } else { DEBUG(printf("found buffer associated with intern node!\n")); } buf_entry->b_bcount = MIN(lb_size, new_extent); buf_entry->b_resid = lb_size - buf_entry->b_bcount; memcpy(buf_entry->b_data, udf_node->intern_data, udf_node->intern_len); memset(buf_entry->b_data + udf_node->intern_len, 0, lb_size - udf_node->intern_len); UDF_MUTEX_LOCK(&udf_node->buf_mutex); udf_mark_buf_dirty(udf_node, buf_entry); UDF_MUTEX_UNLOCK(&udf_node->buf_mutex); udf_node->intern_len = 0; if (udf_node->intern_data) free(udf_node->intern_data); udf_node->intern_data = NULL; udf_node->icb_len = sizeof(struct long_ad); udf_node->addr_type = UDF_ICB_LONG_ALLOC; } udf_cut_allocentry_queue(&udf_node->alloc_entries, lb_size, block_extent); if (new_extent < block_extent) { alloc_entry = TAILQ_LAST(&udf_node->alloc_entries, udf_alloc_entries); assert(alloc_entry->len > too_much); alloc_entry->len -= too_much; } /* XXX Andrey suggested buffer extension? XXX */ udf_node->stat.st_size = new_extent; } UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex); UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock); /* `free' the extent when shrinking the extent */ if (new_extent < (uint64_t) udf_node->stat.st_size) { DEBUG(printf("TRIMMING file %"PRIu64" from %d to %d\n", udf_node->unique_id, (int32_t) udf_node->stat.st_size, (uint32_t) length)); /* free file buffers that are not needed anymore */ /* XXX NetBSD kernel : uvm_vnp_setsize() XXX */ marker = calloc(1, sizeof(struct udf_buf)); if (!marker) return ENOMEM; UDF_MUTEX_LOCK(&udf_bufcache->bufcache_lock); UDF_MUTEX_LOCK(&udf_node->buf_mutex); /* use marker as we are going to delete items in the list we are traversing */ last_sector = new_extent / lb_size; TAILQ_INSERT_HEAD(&udf_node->vn_bufs, marker, b_vnbufs); while ((buf_entry = TAILQ_NEXT(marker, b_vnbufs))) { /* advance marker */ TAILQ_REMOVE(&udf_node->vn_bufs, marker, b_vnbufs); TAILQ_INSERT_AFTER(&udf_node->vn_bufs, buf_entry, marker, b_vnbufs); /* process buf_entry */ if (buf_entry->b_lblk > last_sector) { udf_mark_buf_clean(udf_node, buf_entry); /* its destroyed so not dirty */ udf_mark_buf_allocated(udf_node, buf_entry); /* i.e. taken care of */ udf_detach_buf_from_node(udf_node, buf_entry); udf_free_buf_entry(buf_entry); } /* trim last buffer entry */ /* XXX NetBSD kernel : uvm_vnp_zerorange(), vtruncbuf() XXX */ if (buf_entry->b_lblk == last_sector) { buf_entry->b_bcount = udf_node->stat.st_size % lb_size; buf_entry->b_resid = buf_entry->b_bufsize - buf_entry->b_bcount; /* still data to record? */ if (buf_entry->b_bcount == 0) { /* marker not an issue here */ udf_mark_buf_clean(udf_node, buf_entry); /* its destroyed so not dirty */ udf_mark_buf_allocated(udf_node, buf_entry); /* i.e. taken care of */ udf_detach_buf_from_node(udf_node, buf_entry); udf_free_buf_entry(buf_entry); } } } TAILQ_REMOVE(&udf_node->vn_bufs, marker, b_vnbufs); free(marker); UDF_MUTEX_UNLOCK(&udf_node->buf_mutex); UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock); UDF_MUTEX_LOCK(&udf_node->alloc_mutex); if (udf_node->addr_type == UDF_ICB_INTERN_ALLOC) { /* shrink intern node */ too_much = udf_node->stat.st_size - new_extent; udf_node->intern_len -= too_much; udf_node->intern_free += too_much; memset(udf_node->intern_data + new_extent, 0, too_much); } else { /* shrink alloc entries _after_ deleting bufs to make sure we are not crossed */ error = udf_node_release_extent(udf_node, block_extent, udf_node->stat.st_size); /* after `cleanup', trim now unused entries */ udf_merge_allocentry_queue(&udf_node->alloc_entries, lb_size); if (new_extent == 0) { /* remove all; most common case too */ while ((alloc_entry = TAILQ_FIRST(&udf_node->alloc_entries))) { TAILQ_REMOVE(&udf_node->alloc_entries, alloc_entry, next_alloc); free(alloc_entry); } cur_extent = 0; } else { /* move code to udf_allocentries.c ? */ udf_cut_allocentry_queue(&udf_node->alloc_entries, lb_size, block_extent); /* find cut-point */ cur_extent = 0; TAILQ_FOREACH(alloc_entry, &udf_node->alloc_entries, next_alloc) { cur_extent += alloc_entry->len; if (cur_extent == block_extent) break; } cut_point = alloc_entry; /* all after this point need to be deleted */ assert(cut_point); while ((alloc_entry = TAILQ_NEXT(cut_point, next_alloc))) { TAILQ_REMOVE(&udf_node->alloc_entries, alloc_entry, next_alloc); free(alloc_entry); } /* clip last entry to the correct size */ if (new_extent < block_extent) { assert(too_much == block_extent - new_extent); alloc_entry = TAILQ_LAST(&udf_node->alloc_entries, udf_alloc_entries); assert(alloc_entry->len > too_much); alloc_entry->len -= too_much; cur_extent -= too_much; } } assert(cur_extent == new_extent); } udf_node->stat.st_size = new_extent; UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex); } return 0; } /* VOP_WRITE */ int udf_write_file_part_uio(struct udf_node *udf_node, char *what, int content, struct uio *data_uio) { struct udf_buf *buf_entry; off_t offset; uint64_t new_possible_extent; uint64_t start_extent, end_extent; uint64_t lb_size, sector, data_length; uint8_t *base; int error, appending, allocated; if (!udf_node) return EINVAL; if (udf_open_logvol(udf_node->udf_log_vol)) return EROFS; /* write chanches both modification and file status times */ udf_set_timespec_now(&udf_node->stat.st_ctimespec); udf_set_timespec_now(&udf_node->stat.st_mtimespec); /* Zero length write -> finished */ if (data_uio->uio_resid == 0) return 0; /* TODO lock node directly to avoid multiple writers entering */ /* pthread_rwlock_wrlock(&udf_node->udf_node_lock); */ if (!udf_node->dirty) { udf_node_mark_dirty(udf_node); } /* auto-extent file */ appending = 0; allocated = 0; new_possible_extent = data_uio->uio_offset + data_uio->uio_resid; if (new_possible_extent >= (uint64_t) udf_node->stat.st_size) { /* BUGALERT: extra space can be pre-allocated AFTER file length */ error = udf_truncate_node(udf_node, new_possible_extent); appending = 1; } lb_size = udf_node->udf_log_vol->lb_size; while (data_uio->uio_resid) { error = 0; sector = data_uio->uio_offset / lb_size; /* lookup sector in buffer set */ UDF_MUTEX_LOCK(&udf_bufcache->bufcache_lock); udf_lookup_node_buf(udf_node, sector, &buf_entry); if (!buf_entry || (buf_entry && (buf_entry->b_lblk != sector))) { /* not found in cache; `page in' sector from file BUT ONLY if we don't completely overwrite it anyway */ if ((data_uio->uio_resid < lb_size) && (!appending)) { DEBUG(printf("Reading in file buffer for %s for %"PRIu64" bytes\n", what, (uint64_t) data_uio->uio_resid)); error = udf_readin_file_buffer(udf_node, what, sector, content, &buf_entry); } /* check if the extent is allocated; check assumption that the size of a buffer is a lb_size */ if (buf_entry) assert(buf_entry->b_bufsize == lb_size); UDF_MUTEX_LOCK(&udf_node->alloc_mutex); start_extent = (uint64_t) lb_size * sector; end_extent = MIN((uint64_t) udf_node->stat.st_size, start_extent + lb_size); error = udf_extent_properties(&udf_node->alloc_entries, lb_size, start_extent, end_extent, &allocated); UDF_MUTEX_UNLOCK(&udf_node->alloc_mutex); /* check free space if space is to allocated */ if (!buf_entry || !allocated) { /* be coulant on metadata here to avoid not to easy to solve resource problems */ if (content == UDF_C_USERDATA) { /* check for space no space anymore for userdata (bit on the safe side really) */ assert(udf_node->udf_log_vol); if (!udf_confirm_freespace(udf_node->udf_log_vol, content, lb_size)) { UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock); return ENOSPC; } } } DEBUG(if (allocated) printf("Writing pre-allocated buffer\n")); if (!buf_entry) { /* create new buffer */ error = udf_get_buf_entry(udf_node, &buf_entry); if (error) { UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock); return error; } /* don't forget to set the relative block number! */ buf_entry->b_lblk = sector; /* add it to the buffer list */ UDF_MUTEX_LOCK(&udf_node->buf_mutex); udf_attach_buf_to_node(udf_node, buf_entry); UDF_MUTEX_UNLOCK(&udf_node->buf_mutex); } assert(buf_entry); if (allocated) { /* * we could free the old allocated extent and mark it needing allocation * again */ } if (!allocated) { /* mark it needs to be allocated, locks are not very nice here */ UDF_MUTEX_LOCK(&udf_node->buf_mutex); udf_mark_buf_needing_allocate(udf_node, buf_entry); UDF_MUTEX_UNLOCK(&udf_node->buf_mutex); } } if (error) { UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock); break; /* while */ } assert(buf_entry); offset = data_uio->uio_offset - (off_t) sector*lb_size; base = buf_entry->b_data; assert(offset >= 0); if (offset >= 0) { UDF_MUTEX_LOCK(&udf_node->buf_mutex); udf_mark_buf_dirty(udf_node, buf_entry); data_length = buf_entry->b_bufsize - offset; data_length = MIN(data_length, data_uio->uio_resid); uiomove(base + offset, data_length, data_uio); buf_entry->b_bcount = MAX(buf_entry->b_bcount, offset + data_length); buf_entry->b_resid = buf_entry->b_bufsize - buf_entry->b_bcount; UDF_MUTEX_UNLOCK(&udf_node->buf_mutex); } UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock); if (data_uio->uio_resid == 0) return 0; /* finished? */ } /* while */ return 0; } /****************************************************************************************** * * UDF volume and descriptor logic * ******************************************************************************************/ struct udf_volumeset *udf_search_volumeset(char *volset_id) { struct udf_volumeset *volumeset; struct udf_pri_vol *primary; /* XXX this is a bit ugly XXX */ SLIST_FOREACH(volumeset, &udf_volumeset_list, next_volumeset) { primary = STAILQ_FIRST(&volumeset->primaries); assert(primary->pri_vol); if (memcmp(primary->pri_vol->volset_id, volset_id, 128) == 0) return volumeset; } return NULL; } struct udf_pri_vol *udf_search_primary(struct udf_volumeset *set, char *id) { struct udf_pri_vol *primary; STAILQ_FOREACH(primary, &set->primaries, next_primary) { assert(primary->pri_vol); if (memcmp(primary->pri_vol->vol_id, id, 32) == 0) return primary; } return NULL; } struct udf_log_vol *udf_search_logical_volume_in_primary(struct udf_pri_vol *primary, char *logvol_id) { struct udf_log_vol *here; SLIST_FOREACH(here, &primary->log_vols, next_logvol) { if (memcmp(here->log_vol->logvol_id, logvol_id, 128) == 0) return here; } return NULL; } /* called not very often ... ; free incomming when not needed */ int udf_proc_pri_vol(struct udf_session *udf_session, struct udf_pri_vol **current, struct pri_vol_desc *incomming) { struct udf_volumeset *volset; struct udf_pri_vol *primary; assert(current); volset = udf_search_volumeset(incomming->volset_id); if (!volset) { /* create a volume set */ volset = calloc(1, sizeof(struct udf_volumeset)); if (!volset) { free(incomming); return ENOMEM; } /* populate and link in */ volset->max_partnum = 0; STAILQ_INIT(&volset->primaries); SLIST_INSERT_HEAD(&udf_volumeset_list, volset, next_volumeset); } assert(volset); primary = udf_search_primary(volset, incomming->vol_id); *current = primary; if (!primary) { /* create a primary volume */ primary = calloc(1, sizeof(struct udf_pri_vol)); if (!primary) { free(incomming); return ENOMEM; } /* add to volset's primaries list */ STAILQ_INSERT_TAIL(&volset->primaries, primary, next_primary); *current = primary; } else { /* mark as current */ /* ok ... we now need to check if this new descriptor is a newer version */ if (udf_rw32(incomming->seq_num) <= udf_rw32(primary->pri_vol->seq_num)) { if (udf_session->session_num <= (*current)->udf_session->session_num) { DEBUG(printf("UDF: DISCARDING primary descriptor for its the same but higher session number\n")); /* its an older one; ignore */ free(incomming); return 0; } } DEBUG(printf("UPDATING primary descriptor for it has a higher session number\n")); } /* update the primary volume descriptor */ if (primary->pri_vol) free(primary->pri_vol); primary->volumeset = volset; primary->pri_vol = incomming; primary->udf_session = udf_session; return 0; } /* not called often ; free lvid when not used */ int udf_proc_logvol_integrity(struct udf_log_vol *udf_log_vol, struct logvol_int_desc *new_lvid) { struct udf_logvol_info *impl; uint64_t psize, pfree; uint32_t *free_space_pos, *size_pos; uint32_t lb_size, part_map; uint32_t integrity; int error, tagid; error = udf_check_tag((union dscrptr *) new_lvid); if (error) { return error; /* return error on faulty tag */ } tagid = udf_rw16(new_lvid->tag.id); /* getting a terminator tag or zero is an OK condition */ if ((tagid == TAGID_TERM) || (tagid == 0)) { return 0; } /* not getting an logical volume itegrity volume descriptor is an error now */ if (tagid != TAGID_LOGVOL_INTEGRITY) { printf("IEE! got a %d tag while searching for a logical volume integrity descriptor\n", tagid); return EINVAL; /* XXX error code? XXX */ } /* check CRC on the contents of the logvol integrity */ error = udf_check_tag_payload((union dscrptr *) new_lvid); if (error) { return error; } /* check logvol integrity validity */ integrity = udf_rw32(new_lvid->integrity_type); if ((integrity != UDF_INTEGRITY_OPEN) && (integrity != UDF_INTEGRITY_CLOSED)) return EINVAL; /* allways go for the next in line; silly but thats Ecma-167/UDF */ /* process information contained in logical volume integrity descriptor */ udf_log_vol->logvol_state = integrity; udf_log_vol->integrity_serial = udf_rw16(new_lvid->tag.serial_num); impl = (struct udf_logvol_info *) (new_lvid->tables + 2*udf_rw32(new_lvid->num_part)); udf_log_vol->min_udf_readver = udf_rw16(impl->min_udf_readver); udf_log_vol->min_udf_writever = udf_rw16(impl->min_udf_writever); udf_log_vol->max_udf_writever = udf_rw16(impl->max_udf_writever); udf_log_vol->num_files = udf_rw32(impl->num_files); udf_log_vol->num_directories = udf_rw32(impl->num_directories); udf_log_vol->next_unique_id = udf_rw64(new_lvid->lvint_next_unique_id); /* calculate free space from this integrity descritor */ lb_size = udf_log_vol->lb_size; /* init start positions */ free_space_pos = &new_lvid->tables[0]; size_pos = &new_lvid->tables[udf_log_vol->num_part_mappings]; /* init counters */ udf_log_vol->total_space = udf_log_vol->free_space = udf_log_vol->await_alloc_space = 0; for (part_map = 0; part_map < udf_log_vol->num_part_mappings; part_map++) { psize = udf_rw32(*size_pos); size_pos++; pfree = udf_rw32(*free_space_pos); free_space_pos++; if (pfree != UINT_MAX) { /* if UINT_MAX, its not applicable like virtual space partitions */ udf_log_vol->total_space += (uint64_t) psize * lb_size; udf_log_vol->free_space += (uint64_t) pfree * lb_size; } } UDF_VERBOSE( if (udf_log_vol->logvol_state == UDF_INTEGRITY_OPEN) { udf_dump_timestamp("\t\t\t\tmarked open at ", &new_lvid->time); } else { udf_dump_timestamp("\t\t\t\tmarked closed at ", &new_lvid->time); } ); return 0; } void udf_derive_new_logvol_integrity(struct udf_log_vol *udf_log_vol) { udf_log_vol->logvol_state = UDF_INTEGRITY_OPEN; udf_log_vol->integrity_serial = 1; /* analyse the log vol to check out minimum and maximum read/write versions */ if (udf_rw16(udf_log_vol->log_vol->tag.descriptor_ver) == 2) { udf_log_vol->min_udf_readver = 0x0102; udf_log_vol->min_udf_writever = 0x0150; udf_log_vol->max_udf_writever = 0x0150; } else { udf_log_vol->min_udf_readver = 0x0201; udf_log_vol->min_udf_writever = 0x0201; udf_log_vol->max_udf_writever = 0x0201; /* 2.50? */ } udf_log_vol->num_files = 0; udf_log_vol->num_directories = 0; udf_log_vol->next_unique_id = 16; /* zero first, rest 15/16+ minimum */ } int udf_proc_logvol_integrity_sequence(struct udf_log_vol *udf_log_vol) { union dscrptr *dscr; uint32_t sector, length, lvid_len, num_sectors; uint32_t lb_size; int error; sector = udf_rw32(udf_log_vol->log_vol->integrity_seq_loc.loc); length = udf_rw32(udf_log_vol->log_vol->integrity_seq_loc.len); lb_size = udf_log_vol->lb_size; /* go for the default `open' integrity first as initialisation */ udf_derive_new_logvol_integrity(udf_log_vol); if (!length) { fprintf(stderr, "UDF: no volume integrity descriptor sequence space defined... OK for Ecma-167, not for UDF; rejecting\n"); return EBADF; } error = 0; while (length) { error = udf_read_session_descriptor(udf_log_vol->primary->udf_session, sector, "Logical volume integrity descriptor (LVID)", &dscr, &lvid_len); if (error) { if (dscr) free(dscr); dscr = NULL; break; } UDF_VERBOSE_MAX(udf_dump_descriptor(dscr)); error = udf_proc_logvol_integrity(udf_log_vol, &dscr->lvid); if (error) break; if (udf_rw16(dscr->tag.id) == TAGID_TERM) break; num_sectors = (lvid_len + lb_size-1) / lb_size; length -= num_sectors * lb_size; sector += num_sectors; if (udf_rw32(dscr->lvid.next_extent.len)) { sector = udf_rw32(dscr->lvid.next_extent.loc); length = udf_rw32(dscr->lvid.next_extent.len); } /* free consumed descriptor */ free(dscr); dscr = NULL; } /* free dangling descriptor */ if (dscr) free(dscr); /* either an error has occured or we have processed all descriptors */ if (error) { fprintf(stderr, "WARNING: integrity sequence ended with a bad descriptor; creating new\n"); udf_derive_new_logvol_integrity(udf_log_vol); return ENOENT; } /* * If its marked closed we hope/assume all is fine otherwise it may be * marked closed later on when we are using a VAT and its found and * correct */ return 0; } /* Add partition mapping to specified logvol descriptor */ void udf_add_physical_to_logvol(struct logvol_desc *logvol, uint16_t vol_seq_num, uint16_t phys_part_num) { union udf_pmap *pmap; uint8_t *pmap_pos; pmap_pos = logvol->maps + udf_rw32(logvol->mt_l); pmap = (union udf_pmap *) pmap_pos; pmap->pm1.type = 1; pmap->pm1.len = sizeof(struct part_map_1); pmap->pm1.vol_seq_num = udf_rw16(vol_seq_num); pmap->pm1.part_num = udf_rw16(phys_part_num); /* increment partition mapping count */ logvol->n_pm = udf_rw32(udf_rw32(logvol->n_pm) + 1); logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + sizeof(struct part_map_1)); logvol->tag.desc_crc_len = udf_rw16(udf_rw16(logvol->tag.desc_crc_len) + sizeof(struct part_map_1)); } #if 0 /* not yet */ void udf_add_sparable_to_logvol(struct logvol_desc *logvol, uint16_t vol_seq_num, uint16_t phys_part_num, uint16_t packet_len, ) { union udf_pmap *pmap; uint8_t *pmap_pos; pmap_pos = logvol->maps + udf_rw32(logvol->mt_l); pmap = (union udf_pmap *) pmap_pos; pmap->pm1.type = 1; pmap->pm1.len = sizeof(struct part_map_1); pmap->pm1.vol_seq_num = vol_seq_num; pmap->pm1.part_num = phys_part_num; /* increment partition mapping count */ logvol->n_pm = udf_rw32(udf_rw32(logvol->n_pm) + 1); logvol->mt_l = udf_rw32(udf_rw32(logvol->mt_l) + sizeof(struct part_map_1)); logvol->tag.desc_crc_len = udf_rw16(udf_rw16(logvol->tag.desc_crc_len) + sizeof(struct part_map_1)); } #endif /* not called often; free incomming when not needed */ int udf_proc_log_vol(struct udf_pri_vol *primary, struct udf_log_vol **current, struct logvol_desc *incomming) { struct udf_log_vol *logical; struct udf_part_mapping *part_mapping, *data_part_mapping, *search_part_mapping; union udf_pmap *pmap; uint32_t part_cnt, pmap_type, pmap_size; uint32_t data_part_num; uint8_t *pmap_pos; logical = udf_search_logical_volume_in_primary(primary, incomming->logvol_id); if (!logical) { /* create a logical volume */ logical = calloc(1, sizeof(struct udf_log_vol)); if (!logical) { free(incomming); return ENOMEM; } /* link in */ SLIST_INSERT_HEAD(&primary->log_vols, logical, next_logvol); } else { /* ok ... we now need to check if this new descriptor is a newer version */ if (udf_rw32(incomming->seq_num) < udf_rw32(logical->log_vol->seq_num)) { /* its an older one; ignore */ free(incomming); return 0; } } /* update the logical volume descriptor and its mappings; first delete old partition mappings allocated before */ logical->primary = primary; if (current) *current = logical; part_mapping = SLIST_FIRST(&logical->part_mappings); while ((part_mapping = SLIST_FIRST(&logical->part_mappings))) { /* TODO cleanup old cruft ? (XXX while mounted? i don't think so!) */ /* free(part_mapping->sparing_table); free(part_mapping->vat_file_entry); free(part_mapping->vat); free(part_mapping->meta_file); free(part_mapping->meta_mirror_file); free(part_mapping->meta_bitmap_file); */ SLIST_REMOVE_HEAD(&logical->part_mappings, next_mapping); free(part_mapping); } SLIST_INIT(&logical->part_mappings); /* use the new logical volume and preprocess it */ if (logical->log_vol) free(logical->log_vol); logical->log_vol = incomming; logical->lb_size = udf_rw32(incomming->lb_size); logical->sector_size = primary->udf_session->disc->sector_size; /* build up the partion mappings */ logical->num_part_mappings = udf_rw32(incomming->n_pm); /* process partition mappings */ pmap_pos = &logical->log_vol->maps[0]; for (part_cnt = 0; part_cnt < logical->num_part_mappings; part_cnt++) { /* get a new part_mapping structure */ part_mapping = calloc(1, sizeof(struct udf_part_mapping)); assert(part_mapping); /* XXX check with partition mapping destructor etc XXX */ /* * BUG alert: add to *tail* of list for dependencies sake. * Since this is the only place that its needed, I decided * against changing the SLIST to a TAILQ. */ if (SLIST_EMPTY(&logical->part_mappings)) SLIST_INSERT_HEAD(&logical->part_mappings, part_mapping, next_mapping); else { search_part_mapping = SLIST_FIRST(&logical->part_mappings); while (SLIST_NEXT(search_part_mapping, next_mapping)) search_part_mapping = SLIST_NEXT(search_part_mapping, next_mapping); SLIST_INSERT_AFTER(search_part_mapping, part_mapping, next_mapping); } /* process */ pmap = (union udf_pmap *) pmap_pos; pmap_type = pmap->data[0]; pmap_size = pmap->data[1]; part_mapping->udf_virt_part_num = part_cnt; part_mapping->udf_pmap = pmap; switch (pmap_type) { case 1: part_mapping->udf_part_mapping_type = UDF_PART_MAPPING_PHYSICAL; part_mapping->vol_seq_num = udf_rw16(pmap->pm1.vol_seq_num); part_mapping->udf_phys_part_num = udf_rw16(pmap->pm1.part_num); break; case 2: part_mapping->vol_seq_num = udf_rw16(pmap->pm2.vol_seq_num); part_mapping->udf_phys_part_num = udf_rw16(pmap->pm2.part_num); if (strncmp((char *) pmap->pm2.part_id.id, "*UDF Virtual Partition", UDF_REGID_ID_SIZE) == 0) { part_mapping->udf_part_mapping_type = UDF_PART_MAPPING_VIRTUAL; break; } if (strncmp((char *) pmap->pm2.part_id.id, "*UDF Sparable Partition", UDF_REGID_ID_SIZE) == 0) { part_mapping->udf_part_mapping_type = UDF_PART_MAPPING_SPARABLE; break; } if (strncmp((char *) pmap->pm2.part_id.id, "*UDF Metadata Partition", UDF_REGID_ID_SIZE) == 0) { part_mapping->udf_part_mapping_type = UDF_PART_MAPPING_META; break; } printf("HELP ... found unsupported type 2 partition mapping id `%s`; marking broken\n", pmap->pm2.part_id.id); default: part_mapping->udf_part_mapping_type = UDF_PART_MAPPING_ERROR; } pmap_pos += pmap_size; /* variable length array :( */ } /* flag all partion mappings data and metadata writable */ SLIST_FOREACH(part_mapping, &logical->part_mappings, next_mapping) { part_mapping->data_writable = 1; part_mapping->metadata_writable = 1; } /* update writable flags depending on mapping type */ SLIST_FOREACH(part_mapping, &logical->part_mappings, next_mapping) { switch (part_mapping->udf_part_mapping_type) { case UDF_PART_MAPPING_ERROR : part_mapping->data_writable = 0; part_mapping->metadata_writable = 0; break; case UDF_PART_MAPPING_PHYSICAL : break; case UDF_PART_MAPPING_VIRTUAL : case UDF_PART_MAPPING_META : /* * These are special in that there is a special metadata partition where no data * is meant to be written on and vice versa */ /* find the associated data partition */ data_part_num = part_mapping->udf_phys_part_num; SLIST_FOREACH(data_part_mapping, &logical->part_mappings, next_mapping) { if (data_part_mapping->udf_phys_part_num == data_part_num) { if (data_part_mapping != part_mapping) { data_part_mapping->metadata_writable = 0; break; } } } part_mapping->data_writable = 0; break; case UDF_PART_MAPPING_SPARABLE : break; } } TAILQ_INIT(&logical->dirty_nodes); UDF_MUTEX_INIT(&logical->dirty_nodes_mutex); return 0; } /* not called often; free incomming when not needed */ int udf_proc_part(struct udf_pri_vol *primary, struct udf_partition **current, struct part_desc *incomming) { struct udf_partition *udf_partition; struct udf_volumeset *udf_volset; uint32_t new_part_num, sector_size; assert(primary); assert(primary->pri_vol); udf_volset = udf_search_volumeset(primary->pri_vol->volset_id); assert(udf_volset); new_part_num = udf_rw16(incomming->part_num); /* check if its a partition type we recognize */ if (strncmp((char *) incomming->contents.id, "+NSR0", 5) != 0) { fprintf(stderr, "Unrecognized partition content type %s encountered; ignoring\n", incomming->contents.id); free(incomming); return 0; } /* look if we allready got it */ SLIST_FOREACH(udf_partition, &udf_volset->parts, next_partition) { if (udf_rw16(udf_partition->partition->part_num) == new_part_num) break; } /* we have space... now check if this is a newer one than the one known */ if (udf_partition) { if (udf_rw32(incomming->seq_num) < udf_rw32(udf_partition->partition->seq_num)) { /* its an older version */ free(incomming); return 0; } } else { /* get us a new udf_partition */ udf_partition = calloc(1, sizeof(struct udf_partition)); if (!udf_partition) { free(incomming); return ENOMEM; } /* link it in */ SLIST_INSERT_HEAD(&udf_volset->parts, udf_partition, next_partition); } assert(udf_partition); /* copy this new partition descriptor in the list */ if (udf_partition->partition) free(udf_partition->partition); udf_partition->partition = incomming; udf_partition->udf_session = primary->udf_session; udf_volset->max_partnum = MAX(udf_volset->max_partnum, new_part_num+1); /* REVIEW why +1? */ /* initialise */ sector_size = primary->udf_session->disc->sector_size; UDF_MUTEX_INIT(&udf_partition->partition_space_mutex); TAILQ_INIT(&udf_partition->unalloc_space_queue); TAILQ_INIT(&udf_partition->freed_space_queue); udf_partition->part_offset = udf_rw32(incomming->start_loc) * sector_size; udf_partition->part_length = udf_rw32(incomming->part_len) * sector_size; /* udf_partition->access_type = udf_rw32(incomming->access_type); */ udf_partition->free_unalloc_space = udf_partition->free_freed_space = 0; if (current) *current = udf_partition; return 0; } /* not called often; free incomming when not needed */ int udf_proc_filesetdesc(struct udf_log_vol *udf_log_vol, struct fileset_desc *incomming) { struct udf_mountpoint *mp; if (udf_rw16(incomming->tag.id) != TAGID_FSD) { printf("IEEE! Encountered a non TAGID_FSD in this fileset descriptor sequence!!!\n"); free(incomming); return EFAULT; } /* lookup fileset descriptor in this logical volume; interestingly fileset_num is KEY! */ SLIST_FOREACH(mp, &udf_log_vol->mountpoints, logvol_next) { if (mp->fileset_desc->fileset_num == incomming->fileset_num) break; } if (!mp) { /* add a new mountpoint! */ mp = calloc(1, sizeof(struct udf_mountpoint)); if (!mp) { free(incomming); return ENOMEM; } mp->fileset_desc = incomming; /* insert into udf_log_vol and into mountables list */ SLIST_INSERT_HEAD(&udf_log_vol->mountpoints, mp, logvol_next); SLIST_INSERT_HEAD(&udf_mountables, mp, all_next); } else { /* should we update mountpoint? */ if (udf_rw32(incomming->fileset_desc_num) <= udf_rw32(mp->fileset_desc->fileset_desc_num)) { /* we allready got a newer one */ free(incomming); return 0; } fprintf(stderr, "UDF DEBUG: would be updating mountpoint... HELP!\n"); /* FIXME delete all inode hash entries */ /* XXX how to do that? inodes OK but associated vnodes? XXX */ #if 0 if (!SLIST_EMPTY(&mp->inodes)) { printf("UDF: asked to delete mountpoint with inodes in hashtable!\n"); printf("Can't cope with that... aborting\n"); exit(1); } #endif /* free old information (allready in lists though!) */ free(mp->fileset_desc); free(mp->mount_name); } mp->udf_log_vol = udf_log_vol; mp->fileset_desc = incomming; mp->mount_name = strdup(udf_get_compound_name(mp)); return 0; } int udf_retrieve_volume_space(struct udf_discinfo *disc, struct udf_session *udf_session, struct extent_ad *extent) { struct udf_pri_vol *udf_pri_vol; struct udf_log_vol *udf_log_vol; union dscrptr *dscr; uint32_t sector, length, dscr_len, num_sectors; uint32_t sector_size; int tag_id; int error; udf_pri_vol = NULL; sector = udf_rw32(extent->loc); length = udf_rw32(extent->len); sector_size = disc->sector_size; error = 0; /* XXX zero length area's possible? XXX */ while (length) { error = udf_read_session_descriptor(udf_session, sector, "volume descriptor", &dscr, &dscr_len); if (error) { if (dscr) free(dscr); break; } tag_id = udf_rw16(dscr->tag.id); num_sectors = (dscr_len + sector_size-1) / sector_size; /* proc volume descriptor starting at sector `volume_sector' */ UDF_VERBOSE_MAX(udf_dump_descriptor(dscr)); switch (tag_id) { case TAGID_PRI_VOL : error = udf_proc_pri_vol(udf_session, &udf_pri_vol, &dscr->pvd); break; case TAGID_PARTITION : error = udf_proc_part(udf_pri_vol, NULL, &dscr->pd); break; case TAGID_LOGVOL : error = udf_proc_log_vol(udf_pri_vol, &udf_log_vol, &dscr->lvd); if (!error) { /* first create empty integrity descriptor then modify it on input (for sanity) */ udf_derive_new_logvol_integrity(udf_log_vol); } break; case TAGID_TERM : free(dscr); return 0; /* terminator */ case TAGID_UNALLOC_SPACE : /* unallocated space descriptor */ /* Specifies space that is not claimed yet in partitions (!) */ UDF_VERBOSE(printf("\t\t`unallocated space descriptor' ignored\n")); break; case TAGID_IMP_VOL : /* implemenation use volume descriptor */ /* Specifies information relevant for the implementator */ UDF_VERBOSE_MAX(printf("\t\t`implementation use volume descriptor' ignored\n")); break; case TAGID_VOL : fprintf(stderr, "UDF : untested volume space extender encountered\n"); break; default : printf("XXX Unhandled volume sequence %d; freeing\n", tag_id); free(dscr); break; } length -= num_sectors * sector_size; sector += num_sectors; if (tag_id == TAGID_VOL) { sector = udf_rw32(dscr->vdp.next_vds_ex.loc); length = udf_rw32(dscr->vdp.next_vds_ex.len); free(dscr); } } return error; } int udf_get_filelength(union dscrptr *dscr, uint64_t *length) { int32_t fe_tag; fe_tag = udf_rw16(dscr->tag.id); if (fe_tag == TAGID_FENTRY) { *length = udf_rw64(dscr->fe.inf_len); return 0; } else if (fe_tag == TAGID_EXTFENTRY) { *length = udf_rw64(dscr->efe.inf_len); return 0; } return ENOENT; } /* can be passed either a file_entry or an extfil_entry trough fentry! */ int udf_check_for_vat(struct udf_log_vol *udf_log_vol, struct udf_part_mapping *part_mapping, uint32_t vat_lb, union dscrptr *dscr) { struct udf_part_mapping *s_part_mapping; struct udf_node *vat_udf_node; struct long_ad udf_icbptr; struct regid *regid; struct uio vat_uio; struct iovec vat_iovec; struct icb_tag *icbtag; struct timestamp *mtime; uint64_t vat_length, vat_entries; uint32_t *vat_pos, vpart_num; uint8_t *vat; int error, found; /* prepare a `uio' structure for reading in complete VAT file */ error = udf_get_filelength(dscr, &vat_length); if (error) return error; if (vat_length == 0) return EFAULT; vat = malloc(vat_length); if (!vat) return ENOMEM; /* move to uio_newuio(struct uio *uio) with fixed length uio_iovcnt? */ bzero(&vat_uio, sizeof(struct uio)); vat_uio.uio_rw = UIO_WRITE; /* WRITE into this space */ vat_uio.uio_iovcnt = 1; vat_uio.uio_iov = &vat_iovec; vat_uio.uio_offset = 0; /* begin at the start */ vat_uio.uio_resid = vat_length; /* fill in IO vector */ vat_uio.uio_iov->iov_base = vat; vat_uio.uio_iov->iov_len = vat_length; /* find our virtual partition number corresponding to our physical partition number; this sucks */ found = 0; vpart_num = 0; SLIST_FOREACH(s_part_mapping, &udf_log_vol->part_mappings, next_mapping) { if (s_part_mapping->udf_phys_part_num == part_mapping->udf_phys_part_num) { if (s_part_mapping->udf_part_mapping_type == UDF_PART_MAPPING_PHYSICAL) { /* found it ! */ found = 1; vpart_num = s_part_mapping->udf_virt_part_num; } } } if (!found) { printf("Can't find accompanied physical volume\n"); return ENOENT; } /* prepare udf_icbptr file node for easy file reading */ udf_icbptr.loc.part_num = vpart_num; udf_icbptr.loc.lb_num = udf_rw32(vat_lb); udf_icbptr.len = udf_log_vol->lb_size; /* not used, but may not be zero */ /* * this udf_node creation and disposing may look a bit inefficient but * its beneficiary for normal file access. its only used once for * reading in the VAT. */ /* create the udf_vat_node; anonymous since it can't be in a mountpoint */ error = udf_readin_anon_udf_node(udf_log_vol, dscr, &udf_icbptr, "VAT", &vat_udf_node); if (!error) { DEBUG(printf("READ FILE PART UIO for VAT\n")); error = udf_read_file_part_uio(vat_udf_node, "VAT contents", 0, &vat_uio); DEBUG(printf("vat_uio rest %d\n", (uint32_t) vat_uio.uio_resid)); } /* XXX allow for SHORT VAT's ? XXX */ if (!error) { if (vat_uio.uio_resid) { fprintf(stderr, "Warning: VAT file can't be read in completely\n"); } part_mapping->vat_udf_node = vat_udf_node; part_mapping->vat = (struct udf_vat *) vat; part_mapping->vat_length = vat_length; /* extract next unique file ID from the VAT file entry's unique ID incremented by one */ udf_log_vol->next_unique_id = vat_udf_node->unique_id; /* ok? */ udf_increment_unique_id(udf_log_vol); /* fentry is confirmed to be either an file_entry or an extfile_entry here */ if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) { icbtag = &dscr->fe.icbtag; mtime = &dscr->fe.mtime; } else { icbtag = &dscr->efe.icbtag; mtime = &dscr->efe.mtime; } if (icbtag->file_type == UDF_ICB_FILETYPE_VAT) { /* we are in UDF 2.00+ userland */ part_mapping->vat_translation = ((uint8_t *) part_mapping->vat) + udf_rw16(part_mapping->vat->header_len); part_mapping->vat_entries = (vat_length - udf_rw16(part_mapping->vat->header_len))/4; udf_log_vol->num_files = udf_rw32(part_mapping->vat->num_files); udf_log_vol->num_directories = udf_rw32(part_mapping->vat->num_directories); udf_log_vol->min_udf_readver = udf_rw16(part_mapping->vat->min_udf_readver); udf_log_vol->min_udf_writever = udf_rw16(part_mapping->vat->min_udf_writever); udf_log_vol->max_udf_writever = udf_rw16(part_mapping->vat->max_udf_writever); /* TODO update logvol name */ } else { /* still in the old UDF 1.50 userland; update? its notoriously broken */ /* check the old UDF 1.50 VAT */ DEBUG(printf("CHECK UDF 1.50 VAT\n")); vat_pos = (uint32_t *) vat; vat_entries = (vat_length-36)/4; /* definition */ regid = (struct regid *) (vat_pos + vat_entries); error = (strncmp((char *) regid->id, "*UDF Virtual Alloc Tbl", 22) == 0) ? 0 : ENOENT; if (!error) { part_mapping->vat_entries = vat_entries; part_mapping->vat_translation = vat; part_mapping->vat = NULL; /* num files/dirs? */ } } if (!error) { UDF_VERBOSE(udf_dump_timestamp("\t\t\t\tmarked closed at ", mtime)); } } /* clean up uio structure */ if (error) { if (vat) free(vat); if (vat_udf_node) udf_dispose_udf_node(vat_udf_node); part_mapping->vat_udf_node = NULL; } return error; } int udf_retrieve_supporting_tables(struct udf_log_vol *udf_log_vol) { struct udf_partition *udf_partition; struct udf_part_mapping *part_mapping, *s_part_mapping; struct udf_session *udf_session; struct long_ad udf_icbptr; union dscrptr *possible_vat_fe; union dscrptr *sparing_table_dscr; uint32_t spar_loc; uint64_t first_vat_loc, vat_loc, last_vat_loc; uint32_t sector_size, lb_size; uint32_t part_num, spar_num, data_part_num, vpart_num; int session_num; int error; /* * if there are any virtual or sparable partition in this logical * volume, try to find their supporting tables so we can find the rest */ lb_size = udf_log_vol->lb_size; sector_size = udf_log_vol->sector_size; SLIST_FOREACH(part_mapping, &udf_log_vol->part_mappings, next_mapping) { part_num = part_mapping->udf_virt_part_num; udf_logvol_vpart_to_partition(udf_log_vol, part_num, NULL, &udf_partition); UDF_VERBOSE_TABLES(printf("\tFor partition mapping %d->%d\n", part_num, part_mapping->udf_phys_part_num)); switch (part_mapping->udf_part_mapping_type) { case UDF_PART_MAPPING_ERROR : /* nothing to be done for these */ break; case UDF_PART_MAPPING_PHYSICAL : /* nothing to be done for these; no supporting tables */ break; case UDF_PART_MAPPING_VIRTUAL : /* * we have to find a good VAT at the END of the session. Since VAT's are * only to be used on WORM's and need to written as last, the strategy is * to go for the predicted end of this session and walk UP */ udf_session = udf_log_vol->primary->udf_session; session_num = udf_session->session_num; UDF_VERBOSE_TABLES(printf("\t\tSearching for the VAT :\n")); if (udf_session->session_length == 0) { UDF_VERBOSE( printf("\t\tThis virtual partition is inaccessible since its its size is not known;\n"); printf("\t\tTry to insert the disc in a CD or DVD recordable device to access it.\n"); ); part_mapping->udf_part_mapping_type = UDF_PART_MAPPING_ERROR; continue; } if (udf_session->disc->next_writable[session_num]) { last_vat_loc = udf_session->disc->next_writable[session_num]; } else { last_vat_loc = udf_session->disc->session_end[session_num]; } last_vat_loc += udf_session->disc->blockingnr; /* give some extra slack since sizes are not allways given up correctly */ first_vat_loc = last_vat_loc - 256; /* 8 blocks of 32 */ first_vat_loc = MAX(first_vat_loc, (uint64_t) udf_session->disc->session_start[session_num]); /* try to find the fileid for the VAT; NOTE that we are reading backwards :( */ vat_loc = last_vat_loc; do { DEBUG( printf("Trying VAT at sector %d in session\n", (int) vat_loc) ); error = udf_read_session_descriptor(udf_session, vat_loc, "VAT file entry", &possible_vat_fe, NULL); if (!error) { error = udf_check_tag_presence(possible_vat_fe, TAGID_FENTRY); if (error) error = udf_check_tag_presence(possible_vat_fe, TAGID_EXTFENTRY); } if (!error) error = udf_check_tag_payload( possible_vat_fe); if (!error) error = udf_check_for_vat(udf_log_vol, part_mapping, vat_loc, possible_vat_fe); if (!error) { break; } else { if (possible_vat_fe) free(possible_vat_fe); vat_loc--; if (vat_loc < first_vat_loc) error = EIO; } } while (error != EIO); if (error) { printf("WARNING: was looking for a VAT but didnt find it; marking logical volume broken\n"); part_mapping->udf_part_mapping_type = UDF_PART_MAPPING_ERROR; udf_log_vol->logvol_state = UDF_INTEGRITY_OPEN; udf_log_vol->broken = 1; continue; } UDF_VERBOSE_TABLES(printf("\t\t\tfound VAT file-entry at device logical sector %d\n", (uint32_t) vat_loc)); UDF_VERBOSE_TABLES(printf("\t\t\tFound %d byte VAT descriptor+table\n", (uint32_t) part_mapping->vat_length)); UDF_VERBOSE_TABLES(udf_dump_descriptor(possible_vat_fe)); UDF_VERBOSE_MAX(udf_dump_vat_table(part_mapping)); if (part_mapping->vat_translation) { /* the presence of a correct VAT means the logical volume is in a closed state */ udf_log_vol->logvol_state = UDF_INTEGRITY_CLOSED; UDF_VERBOSE(printf("\t\t\t\tmarked closed due to presence of VAT\n")); /* XXX update `free' space by requesting the device's free space? XXX */ udf_log_vol->free_space = udf_partition->part_offset + udf_partition->part_length - vat_loc*sector_size; } if (!udf_session->disc->sequential) { UDF_VERBOSE(printf("\t\t\t\tenabling sequential media emulation\n")); udf_session->disc->sequential = 1; } break; case UDF_PART_MAPPING_SPARABLE : /* we have to find a good sparing table; address are in device logical blocks */ udf_session = udf_log_vol->primary->udf_session; for(spar_num = 0; spar_num < part_mapping->udf_pmap->pms.n_st; spar_num++) { spar_loc = udf_rw32(part_mapping->udf_pmap->pms.st_loc[spar_num]); /* fetch spar_loc's table ; on THIS session. */ error = udf_read_session_descriptor(udf_session, spar_loc, "Sparing table", &sparing_table_dscr, NULL); if (!error) error = udf_check_tag_presence(sparing_table_dscr, TAGID_SPARING_TABLE); if (!error) { UDF_VERBOSE_TABLES(printf("\t\tFound the sparing table\n")); part_mapping->sparing_table = &sparing_table_dscr->spt; break; } else { if (sparing_table_dscr) free(sparing_table_dscr); } } if (!part_mapping->sparing_table) { part_mapping->udf_part_mapping_type = UDF_PART_MAPPING_ERROR; } UDF_VERBOSE_TABLES(udf_dump_descriptor((union dscrptr *) part_mapping->sparing_table)); break; case UDF_PART_MAPPING_META : /* * set up common locator parts; the files are located inside the `part_num' partion where * this partition is a added layer on. */ /* find the associated data partition */ data_part_num = udf_rw16(part_mapping->udf_pmap->pmm.part_num); /* find our virtual partition number corresponding to our physical partition number; this sucks */ vpart_num = data_part_num; SLIST_FOREACH(s_part_mapping, &udf_log_vol->part_mappings, next_mapping) { if (s_part_mapping->udf_phys_part_num == data_part_num) { if (s_part_mapping->udf_part_mapping_type != UDF_PART_MAPPING_META) { /* found it ! */ vpart_num = s_part_mapping->udf_virt_part_num; break; } } } udf_icbptr.loc.part_num = vpart_num; udf_icbptr.len = lb_size; /* defined as maximum size */ UDF_VERBOSE_TABLES(printf("Reading metadata partition filedescriptor\n")); udf_icbptr.loc.lb_num = udf_rw32(part_mapping->udf_pmap->pmm.meta_file_lbn); error = udf_readin_anon_udf_node(udf_log_vol, NULL, &udf_icbptr, "Metadata partition file descriptor", &part_mapping->meta_file); if (error == 0) UDF_VERBOSE_TABLES(udf_dump_descriptor((union dscrptr *) part_mapping->meta_file)); udf_icbptr.loc.lb_num = udf_rw32(part_mapping->udf_pmap->pmm.meta_mirror_file_lbn); if ((error == 0) && (udf_icbptr.loc.lb_num != (uint32_t) -1)) { UDF_VERBOSE_TABLES(printf("Reading metadata partition mirror filedescriptor\n")); error = udf_readin_anon_udf_node(udf_log_vol, NULL, &udf_icbptr, "Metadata partition mirror file descriptor", &part_mapping->meta_mirror_file); if (error == 0) UDF_VERBOSE_TABLES(udf_dump_descriptor((union dscrptr *) part_mapping->meta_mirror_file)); error = 0; /* XXX ignoring error code for now */ } udf_icbptr.loc.lb_num = udf_rw32(part_mapping->udf_pmap->pmm.meta_bitmap_file_lbn); if ((error == 0) && (udf_icbptr.loc.lb_num != (uint32_t) -1)) { UDF_VERBOSE_TABLES(printf("Reading metadata partition bitmap filedescriptor\n")); error = udf_readin_anon_udf_node(udf_log_vol, NULL, &udf_icbptr, "Metadata partition bitmap file descriptor", &part_mapping->meta_bitmap_file); if (error == 0) UDF_VERBOSE_TABLES(udf_dump_descriptor((union dscrptr *) part_mapping->meta_bitmap_file)); } /* if something is wrong, then mark it as a broken partition */ if (error) { /* TODO handle read-errors on the meta data and meta data mirror file descriptors. */ part_mapping->udf_part_mapping_type = UDF_PART_MAPPING_ERROR; } break; } } UDF_VERBOSE_TABLES(printf("\n")); if (udf_log_vol->broken) return EIO; return 0; } int udf_retrieve_space_tables(struct udf_log_vol *udf_log_vol) { struct udf_partition *udf_partition; struct udf_part_mapping *part_mapping; struct part_hdr_desc *part_hdr_desc; union dscrptr *dscrptr; uint32_t sector; uint32_t lb_size; uint64_t length; int vpart_num, ppart_num; int error; lb_size = udf_log_vol->lb_size; SLIST_FOREACH(part_mapping, &udf_log_vol->part_mappings, next_mapping) { vpart_num = part_mapping->udf_virt_part_num; ppart_num = part_mapping->udf_phys_part_num; UDF_VERBOSE_TABLES(printf("\tFor partition mapping %d->%d\n", vpart_num, ppart_num)); if ((part_mapping->udf_part_mapping_type != UDF_PART_MAPPING_PHYSICAL) && (part_mapping->udf_part_mapping_type != UDF_PART_MAPPING_SPARABLE)) { UDF_VERBOSE_TABLES(printf("\t\tDon't know how to load space tables for type %d\n", part_mapping->udf_part_mapping_type)); continue; } /* retrieve and process unallocated- and freed-space information for all used partitions of the logvol */ error = udf_logvol_vpart_to_partition(udf_log_vol, vpart_num, NULL, &udf_partition); assert(udf_partition); part_hdr_desc = &udf_partition->partition->pd_part_hdr; sector = udf_rw32(part_hdr_desc->unalloc_space_table.lb_num); length = udf_rw32(part_hdr_desc->unalloc_space_table.len); /* needed? */ if (length) { error = udf_read_logvol_descriptor(udf_log_vol, vpart_num, sector, "Unallocated space table", &dscrptr, NULL); UDF_VERBOSE_MAX(printf("\tUnalloced space table\n")); UDF_VERBOSE_MAX(udf_dump_descriptor(dscrptr)); /* udf_process_space_table(&udf_partition->unalloc_space, dscrptr); */ free(dscrptr); } sector = udf_rw32(part_hdr_desc->unalloc_space_bitmap.lb_num); length = udf_rw32(part_hdr_desc->unalloc_space_bitmap.len); if (length && (udf_partition->unalloc_space_bitmap == 0)) { error = udf_read_logvol_descriptor(udf_log_vol, vpart_num, sector, "Unallocated space bitmap", &dscrptr, NULL); if (!error) { UDF_VERBOSE_MAX(printf("\tUnalloced space bitmap\n")); UDF_VERBOSE_MAX(udf_dump_descriptor(dscrptr)); udf_read_in_space_bitmap(&udf_partition->unalloc_space_queue, &dscrptr->sbd, lb_size, &udf_partition->free_unalloc_space); UDF_VERBOSE_TABLES(printf("\t\tPhysical partition's unallocated space : %"PRIu64"\n", udf_partition->free_unalloc_space)); udf_partition->unalloc_space_bitmap = &dscrptr->sbd; } else { printf("While reading in unallocated space bitmap : %s\n", strerror(error)); udf_partition->unalloc_space_bitmap = NULL; /* TODO mark read-only logvol */ } } sector = udf_rw32(part_hdr_desc->freed_space_table.lb_num); length = udf_rw32(part_hdr_desc->freed_space_table.len); if (length) { error = udf_read_logvol_descriptor(udf_log_vol, vpart_num, sector, "Freed space table", &dscrptr, NULL); UDF_VERBOSE_MAX(printf("\tFreed space table\n")); UDF_VERBOSE_MAX(udf_dump_descriptor(dscrptr)); /* udf_process_space_table(&udf_partition->freed_space, dscrptr); */ free(dscrptr); } sector = udf_rw32(part_hdr_desc->freed_space_bitmap.lb_num); length = udf_rw32(part_hdr_desc->freed_space_bitmap.len); if (length && (udf_partition->freed_space_bitmap == NULL)) { error = udf_read_logvol_descriptor(udf_log_vol, vpart_num, sector, "Freed space bitmap", &dscrptr, NULL); if (!error) { UDF_VERBOSE_MAX(printf("\tFreed space bitmap\n")); UDF_VERBOSE_MAX(udf_dump_descriptor(dscrptr)); udf_read_in_space_bitmap(&udf_partition->freed_space_queue, &dscrptr->sbd, lb_size, &udf_partition->free_freed_space); UDF_VERBOSE_TABLES(printf("\t\tPhysical partition's freed space : %"PRIu64"\n", udf_partition->free_unalloc_space)); udf_partition->freed_space_bitmap = &dscrptr->sbd; } else { printf("While reading in freed space bitmap : %s\n", strerror(error)); udf_partition->freed_space_bitmap = NULL; /* TODO mark read-only logvol */ } } } UDF_VERBOSE_TABLES(printf("\n")); return 0; } /* * Fileset descriptors are on a logical volume's partitions; since virtual * partitions are then also possible its OK to use the VAT for redefining the * fileset descriptors. */ int udf_retrieve_fileset_descriptor(struct udf_log_vol *udf_log_vol) { struct udf_mountpoint *mountable; struct long_ad *fsd_loc; struct fileset_desc *new_fsd; struct udf_node *vnode; uint32_t part_num, lb_num, length; int32_t error; error = 0; /* flag OK */ fsd_loc = &udf_log_vol->log_vol->_lvd_use.fsd_loc; part_num = udf_rw16(fsd_loc->loc.part_num); lb_num = udf_rw32(fsd_loc->loc.lb_num); length = udf_rw32(fsd_loc->len); while (length && !error) { UDF_VERBOSE_TABLES( printf("\tFileset descriptor extent at sector %d within partion %d for %d bytes\n", lb_num, part_num, length) ); /* only go for ONE fsb at a time */ error = udf_read_logvol_descriptor(udf_log_vol, part_num, lb_num, "Fileset descriptor", (union dscrptr **) &new_fsd, NULL); if (!error) error = udf_check_tag((union dscrptr *) new_fsd); /* TODO need a clearer handling unrecorded blocks here */ if (error || (!new_fsd) || (new_fsd && (udf_rw16(new_fsd->tag.id) == TAGID_TERM))) { /* end of sequence */ UDF_VERBOSE_TABLES( printf("\t\t(Terminator) "); if (!new_fsd || error) printf("; unrecorded"); else printf("; explicit"); printf("\n"); ); /* clear error to indicate end of sequence and free possible read in descriptor */ error = 0; if (new_fsd) free(new_fsd); break; } UDF_VERBOSE_MAX(udf_dump_descriptor((union dscrptr *) new_fsd)); udf_proc_filesetdesc(udf_log_vol, new_fsd); if (udf_rw32(new_fsd->next_ex.len) == 0) { /* next entry */ lb_num += 1; length -= udf_log_vol->lb_size; } else { /* follow the next extent */ fsd_loc = &new_fsd->next_ex; part_num = udf_rw16(fsd_loc->loc.part_num); lb_num = udf_rw32(fsd_loc->loc.lb_num); length = udf_rw32(fsd_loc->len); } } UDF_VERBOSE_TABLES(printf("\n")); if (error) return error; /* if no error occured, create rootdir udf_nodes */ SLIST_FOREACH(mountable, &udf_log_vol->mountpoints, logvol_next) { /* errors are OK */ udf_readin_anon_udf_node(udf_log_vol, NULL, &mountable->fileset_desc->rootdir_icb, "Rootdir", &mountable->rootdir_node); udf_readin_anon_udf_node(udf_log_vol, NULL, &mountable->fileset_desc->streamdir_icb, "Streamdir", &mountable->streamdir_node); /* keep names the same ? (duplicate code ahead ... ) */ if (mountable->rootdir_node) { vnode = mountable->rootdir_node; vnode->mountpoint = mountable; vnode->stat.st_uid = vnode->stat.st_gid = UINT_MAX; vnode->stat.st_mode = 0777 | S_IFDIR; udf_insert_node_in_hash(vnode); } if (mountable->streamdir_node) { vnode = mountable->streamdir_node; vnode->mountpoint = mountable; vnode->stat.st_uid = vnode->stat.st_gid = UINT_MAX; vnode->stat.st_mode = 0777 | S_IFDIR; udf_insert_node_in_hash(vnode); } } return 0; } int udf_check_writable_filesets(struct udf_log_vol *udf_log_vol, int mnt_flags) { struct udf_mountpoint *mp; struct udf_part_mapping *udf_part_mapping; int writable; writable = 1; if (mnt_flags & UDF_MNT_RDONLY) writable = 0; if (mnt_flags & UDF_MNT_FORCE) writable = 1; if (udf_log_vol->logvol_state == UDF_INTEGRITY_OPEN) { if (!(mnt_flags & UDF_MNT_FORCE)) { /* we explicitly DISABLE writing */ /* XXX do we even reach here? XXX */ if (udf_verbose) { printf("\t\t\t\tmounting READ-ONLY due to open integrity\n"); } else { printf("WARNING: mounting logical volume READ-ONLY due to open integrity\n"); } writable = 0; } else { printf("WARNING: ignoring open integrity\n"); } } SLIST_FOREACH(udf_part_mapping, &udf_log_vol->part_mappings, next_mapping) { if (udf_part_mapping->udf_part_mapping_type == UDF_PART_MAPPING_META) { writable = 0; fprintf(stderr, "\t\t\t\t*** marked read-only due to read-only support for Metadata partition ***\n"); } } /* follow all mountpoints of this logical volume and set if they are writable */ SLIST_FOREACH(mp, &udf_log_vol->mountpoints, logvol_next) { mp->writable = writable; } udf_log_vol->writable = writable; /* WAS: */ /* udf_log_vol->primary->udf_session->writable = mark; */ return 0; } /* * udf_eliminate_predescessor_volumesets() * * We are faced with a curious problem : we are to examine the partitions and * determine which are successors of eachother. This is propably most * relevant only on WORM media though. We could consider the following rules : * 1) `glue' according to strict UDF level 1 rules ? * 2) use heuristics info i.e. NERO, DirectCD and mkisofs quirks ? * 3) use overlapping partitions to detect relationships ? * * Using 1 would imply no multi-volume discs and thus glue everything but that * could easily be wrong. Selecting by volumeset names is not possible for * Nero f.e. just creates random volumeset names every session and uses no * volume version information and thus also violates the UDF rules. * * Using 2 would be tricky; we know a few programs but what if more are * developped? We then would be at loss. * * Using 3 would imply some calculation but is fail-safe in both supporting * multiple volumes on one disc (they seperate) and in supporting * multi-session WORM media for these will refer to eachother. Offcource NERO * could faul this by just extending the zero partion to the whole disc in its * ignorance and thus create false overlapping over other independent * sessions. This is to be investigated. I don't know how NERO will react on * this situation. * * Propably method 3 would be good to try : * * Follow the disc and check for all sessions in order to mark the ones with * overlapping partitions as `inactive' and keep the latest one active. * Sessions with the `local' quirk are seperate allmost by default; should * be change the offsets? would not be too difficult but possible. */ void udf_eliminate_predescessor_volumesets(struct udf_discinfo *disc) { struct udf_volumeset *anc_vol_set; struct udf_volumeset *sib_vol_set; struct pri_vol_desc *anc_pri_vol; struct pri_vol_desc *sib_pri_vol; struct udf_partition *anc_part; struct udf_partition *sib_part; int anc_partnum; int sib_partnum; uint32_t anc_start, anc_end; uint32_t sib_start, sib_end; uint32_t overlap_start, overlap_end; uint32_t anc_session; uint32_t sib_session; SLIST_FOREACH(anc_vol_set, &udf_volumeset_list, next_volumeset) { anc_pri_vol = STAILQ_FIRST(&anc_vol_set->primaries)->pri_vol; sib_vol_set = SLIST_NEXT(anc_vol_set, next_volumeset); while (sib_vol_set) { sib_pri_vol = STAILQ_FIRST(&sib_vol_set->primaries)->pri_vol; DEBUG( printf("checking volset %s with volset %s\n", anc_pri_vol->volset_id+1, sib_pri_vol->volset_id+1) ); /* compare these two volume sets but only process partitions on _this_ disc */ SLIST_FOREACH(anc_part, &anc_vol_set->parts, next_partition) { if (anc_part->udf_session->disc != disc) continue; anc_session = anc_part->udf_session->session_num; anc_start = 0; #if 0 if (disc->session_quirks[anc_session] & CD_SESS_QUIRK_SESSION_LOCAL) anc_start += disc->session_start[anc_session]; #endif anc_start += udf_rw32(anc_part->partition->start_loc); anc_end = anc_start + udf_rw32(anc_part->partition->part_len); SLIST_FOREACH(sib_part, &sib_vol_set->parts, next_partition) { if (sib_part->udf_session->disc != disc) continue; sib_session = sib_part->udf_session->session_num; #if 0 /* can `session local' volumes even be considered part/successor ? */ if (disc->session_quirks[sib_session] & CD_SESS_QUIRK_SESSION_LOCAL) continue; #endif sib_start = 0; #if 0 if (disc->session_quirks[sib_session] & CD_SESS_QUIRK_SESSION_LOCAL) sib_start += disc->session_start[sib_session]; #endif sib_start += udf_rw32(sib_part->partition->start_loc); sib_end = sib_start + udf_rw32(sib_part->partition->part_len); DEBUG( anc_partnum = udf_rw16(anc_part->partition->part_num); sib_partnum = udf_rw16(sib_part->partition->part_num); printf("\t\tchecking partition %d with partition %d ([%d-%d] x [%d-%d])\n", anc_partnum, sib_partnum, anc_start, anc_end, sib_start, sib_end) ); overlap_start = MAX(sib_start, anc_start); overlap_end = MIN(sib_end, sib_end); if (overlap_start < overlap_end) { DEBUG( printf("\t\t\tOVERLAP!\n") ); if (sib_session < anc_session) { /* the sibbling is older */ UDF_VERBOSE_TABLES( printf("\tVolume set "); udf_dump_id(NULL, 128, anc_pri_vol->vol_id, &anc_pri_vol->desc_charset); printf(" is a newer version of volume set "); udf_dump_id(NULL, 128, sib_pri_vol->vol_id, &sib_pri_vol->desc_charset); printf("\n"); ); sib_vol_set->obsolete = 1; break; } } /* overlap */ if (sib_vol_set->obsolete) break; } /* sibling partition */ if (sib_vol_set->obsolete) break; } /* ancestor partition */ sib_vol_set = SLIST_NEXT(sib_vol_set, next_volumeset); } /* sibling volume set */ } /* ancestor volume set */ } int udf_add_session_to_discinfo(struct udf_discinfo *disc, int session, struct anchor_vdp *avdp, int error) { struct udf_session *udf_session; udf_session = calloc(1, sizeof(struct udf_session)); assert(udf_session); if (!error) { memcpy(&udf_session->anchor, avdp, sizeof(struct anchor_vdp)); } udf_session->disc = disc; udf_session->session_num = session; udf_session->session_offset = 0; udf_session->session_length = disc->session_end[session] - disc->session_start[session]; disc->session_quirks[session] = 0; /* writable session administration */ udf_session->writable = 0; /* default off */ error = udf_init_session_caches(udf_session); if (!error) { /* detect quirks */ /* XXX session local disabled due to wrong heuristic XXX */ #if 0 if (disc->session_start[session] > 0) { if ((udf_session->anchor.main_vds_ex.loc < disc->session_start[session])) { disc->session_quirks[session] |= CD_SESS_QUIRK_SESSION_LOCAL; udf_session->session_offset = disc->session_start[session]; } } #endif } /* add to tail of session list */ STAILQ_INSERT_TAIL(&disc->sessions, udf_session, next_session); disc->num_udf_sessions++; /* record status of this volume */ disc->session_is_UDF[session] = error ? 0 : 1; return error; } int udf_get_anchors(struct udf_discinfo *disc) { uint8_t *sector; union dscrptr *dscr; uint32_t session_start, session_end; int session, error; /* Get all anchors */ STAILQ_INIT(&disc->sessions); sector = NULL; for (session = 0; session < disc->num_sessions; session++) { /* check for anchors ; no volume recognition data ? */ session_start = disc->session_start[session]; session_end = disc->session_end [session]-1; sector = calloc(1, disc->sector_size); if (!sector) return ENOMEM; dscr = (union dscrptr *) sector; error = udf_read_physical_sectors(disc, session_end, 1, "Anchor", sector); if (!error) error = udf_check_tag_presence(dscr, TAGID_ANCHOR); if (!error) UDF_VERBOSE_TABLES(printf("Accepting anchor at session end (%d)\n", session_end)); if (error) { error = udf_read_physical_sectors(disc, session_end - 256, 1, "Anchor", sector); if (!error) error = udf_check_tag_presence(dscr, TAGID_ANCHOR); if (!error) UDF_VERBOSE_TABLES(printf("Accepting anchor at session end - 256 (%d)\n", session_end - 256)); if (error) { error = udf_read_physical_sectors(disc, session_start + 256, 1, "Anchor", sector); if (!error) error = udf_check_tag_presence(dscr, TAGID_ANCHOR); if (!error) UDF_VERBOSE_TABLES(printf("Accepting anchor at session sector 256 (%d)\n", session_start + 256)); if (error) { /* unclosed CD recordable case due to track reservation for iso9660 filesystems */ error = udf_read_physical_sectors(disc, session_start + 512, 1, "Anchor", sector); if (!error) error = udf_check_tag_presence(dscr, TAGID_ANCHOR); if (!error) UDF_VERBOSE_TABLES(printf("Accepting anchor at session sector 512 (%d)\n", session_start + 512)); } } } if (!error) { udf_add_session_to_discinfo(disc, session, (struct anchor_vdp *) sector, error); } else { free(sector); } } return 0; } int udf_get_volumeset_space(struct udf_discinfo *disc) { struct udf_session *udf_session; int one_good_found; int error; /* Rip all volume spaces */ one_good_found = 0; UDF_VERBOSE(printf("\tretrieving volume space\n")); STAILQ_FOREACH(udf_session, &disc->sessions, next_session) { UDF_VERBOSE_MAX(printf("Session %d volumes : \n", udf_session->session_num)); error = udf_retrieve_volume_space(disc, udf_session, &udf_session->anchor.main_vds_ex); if (error) { printf("\nError retrieving session %d's volume space; prosessing reserve\n", udf_session->session_num); error = udf_retrieve_volume_space(disc, udf_session, &udf_session->anchor.reserve_vds_ex); } if (!error) one_good_found = 1; } return one_good_found ? 0 : ENOENT; } int udf_get_logical_volumes_supporting_tables(struct udf_discinfo *disc, int mnt_flags) { struct udf_volumeset *udf_volumeset; struct udf_pri_vol *udf_pri_vol; struct udf_log_vol *udf_log_vol; int logvolint_error; int one_good_found; int error; one_good_found = 0; SLIST_FOREACH(udf_volumeset, &udf_volumeset_list, next_volumeset) { if (!udf_volumeset->obsolete) { STAILQ_FOREACH(udf_pri_vol, &udf_volumeset->primaries, next_primary) { if (udf_pri_vol->udf_session->disc == disc) { SLIST_FOREACH(udf_log_vol, &udf_pri_vol->log_vols, next_logvol) { /* retrieving logical volume integrity sequence */ UDF_VERBOSE(udf_dump_volume_name("\t\tLogical volume ", udf_log_vol)); UDF_VERBOSE(printf("\t\t\tintegrity\n")); logvolint_error = udf_proc_logvol_integrity_sequence(udf_log_vol); /* load in supporting tables */ UDF_VERBOSE(printf("\t\t\tsupporting tables\n")); error = udf_retrieve_supporting_tables(udf_log_vol); /* if the state is still marked `open', its dirty and we mount read-only for safety */ if (logvolint_error) { printf("\t\t\t*** marked read-only due to logvol integrity error ***\n"); mnt_flags |= UDF_MNT_RDONLY; } if (udf_log_vol->logvol_state == UDF_INTEGRITY_OPEN) { printf("\t\t\t*** marked read-only due to open logical volume ***\n"); mnt_flags |= UDF_MNT_RDONLY; } /* get fileset descriptors */ UDF_VERBOSE(printf("\t\t\tfileset(s)\n")); if (!error) error = udf_retrieve_fileset_descriptor(udf_log_vol); /* check if the logical volume is writable */ UDF_VERBOSE(printf("\t\t\tchecking writable filesets\n")); if (!error) error = udf_check_writable_filesets(udf_log_vol, mnt_flags); /* load in free/used space tables for writable volsets */ UDF_VERBOSE(printf("\t\t\tused/freed space tables\n")); if (!error) error = udf_retrieve_space_tables(udf_log_vol); if (error) { udf_log_vol->broken = 1; } else { one_good_found = 1; } } /* logical */ } /* disc */ } /* primary */ } /* if */ } /* volumeset */ return one_good_found? 0 : ENOENT; } /****************************************************************************************** * * Disc sync * ******************************************************************************************/ void udf_sync_tables_callback(int reason, struct udf_wrcallback *wrcallback, int error, uint8_t *sectordata) { /* struct udf_node *udf_node = (struct udf_node *) wrcallback->structure; */ wrcallback = wrcallback; /* not used now */ sectordata = sectordata; if (reason == UDF_WRCALLBACK_REASON_PENDING) { /* what to do? */ return; } if (reason == UDF_WRCALLBACK_REASON_ANULATE) { /* what to do? */ return; } assert(reason == UDF_WRCALLBACK_REASON_WRITTEN); if (error) { printf("UDF error: sync tables write errors in syncnode not fixed!\n"); return; } } /* TODO space tables are not coupled on a logical volume but on a partition/disc, so call them on that instead of logvol */ int udf_sync_space_tables(struct udf_log_vol *udf_log_vol) { struct udf_partition *udf_partition; struct udf_part_mapping *part_mapping; struct part_hdr_desc *part_hdr_desc; struct udf_wrcallback wr_callback; union dscrptr *dscrptr; uint64_t length; uint32_t sector; uint32_t lb_size, part_len; uint16_t dscr_ver; int part_num; int error; lb_size = udf_log_vol->lb_size; wr_callback.function = udf_sync_tables_callback; SLIST_FOREACH(part_mapping, &udf_log_vol->part_mappings, next_mapping) { part_num = part_mapping->udf_virt_part_num; UDF_VERBOSE_TABLES(printf("\tFor partition mapping %d->%d\n", part_num, part_mapping->udf_phys_part_num)); /* retrieve and process unallocated- and freed-space information for all used partitions of the logvol */ error = udf_logvol_vpart_to_partition(udf_log_vol, part_num, NULL, &udf_partition); assert(udf_partition); part_hdr_desc = &udf_partition->partition->pd_part_hdr; // part_start = udf_rw32(udf_partition->partition->start_loc); part_len = udf_rw32(udf_partition->partition->part_len); dscr_ver = udf_rw16(udf_partition->partition->tag.descriptor_ver); sector = udf_rw32(part_hdr_desc->unalloc_space_table.lb_num); length = udf_rw32(part_hdr_desc->unalloc_space_table.len); /* needed? */ if (length) { printf("UDF: Can't write space tables yet\n"); #if 0 error = udf_read_logvol_descriptor(udf_log_vol, part_num, sector, "Unallocated space table", &dscrptr, NULL); UDF_VERBOSE_MAX(printf("\tUnalloced space table\n")); UDF_VERBOSE_MAX(udf_dump_descriptor(dscrptr)); //udf_process_space_table(&udf_partition->unalloc_space, dscrptr); free(dscrptr); #endif } sector = udf_rw32(part_hdr_desc->unalloc_space_bitmap.lb_num); length = udf_rw32(part_hdr_desc->unalloc_space_bitmap.len); /* printf("unalloc dscr at partition sector %d\n", sector); */ if (length) { /* read it in and modify */ dscrptr = (union dscrptr *) udf_partition->unalloc_space_bitmap; if (!dscrptr) { printf("Warning: creating empty unallocated space bitmap for partition's is gone\n"); error = udf_create_empty_space_bitmap(lb_size, dscr_ver, /* num_lbs */ part_len, (struct space_bitmap_desc **) &dscrptr); assert(!error); assert(udf_calc_tag_malloc_size(dscrptr, lb_size) <= length); udf_partition->unalloc_space_bitmap = &dscrptr->sbd; } udf_sync_space_bitmap(&udf_partition->unalloc_space_queue, &dscrptr->sbd, lb_size); UDF_VERBOSE_MAX(printf("\tWriteout unallocated space bitmap\n")); UDF_VERBOSE_MAX(udf_validate_tag_and_crc_sums((union dscrptr *) dscrptr); udf_dump_descriptor(dscrptr)); udf_write_partition_descriptor(udf_partition, sector, "Unallocated space bitmap", dscrptr, &wr_callback); /* SESSION descriptor!! */ } sector = udf_rw32(part_hdr_desc->freed_space_table.lb_num); length = udf_rw32(part_hdr_desc->freed_space_table.len); if (length) { printf("UDF: Can't write space tables yet\n"); #if 0 error = udf_read_logvol_descriptor(udf_log_vol, part_num, sector, "Freed space table", &dscrptr, NULL); UDF_VERBOSE_MAX(printf("\tFreed space table\n")); UDF_VERBOSE_MAX(udf_dump_descriptor(dscrptr)); //udf_process_space_table(&udf_partition->freed_space, dscrptr); free(dscrptr); #endif } sector = udf_rw32(part_hdr_desc->freed_space_bitmap.lb_num); length = udf_rw32(part_hdr_desc->freed_space_bitmap.len); /* printf("freed dscr at partition sector %d\n", sector); */ if (length) { /* read it in and modify */ dscrptr = (union dscrptr *) udf_partition->freed_space_bitmap; if (!dscrptr) { printf("Warning: creating empty freed space bitmap for partition's is gone\n"); error = udf_create_empty_space_bitmap(lb_size, dscr_ver, part_len, (struct space_bitmap_desc **) &dscrptr); assert(!error); assert(udf_calc_tag_malloc_size(dscrptr, lb_size) <= length); udf_partition->freed_space_bitmap = &dscrptr->sbd; } udf_sync_space_bitmap(&udf_partition->freed_space_queue, &dscrptr->sbd, lb_size); UDF_VERBOSE_MAX(printf("\tWriteout freed space bitmap\n")); UDF_VERBOSE_MAX(udf_validate_tag_and_crc_sums((union dscrptr *) dscrptr); udf_dump_descriptor(dscrptr)); udf_write_partition_descriptor(udf_partition, sector, "Freed space bitmap", dscrptr, &wr_callback); /* SESSION descriptor!! */ } } UDF_VERBOSE_TABLES(printf("\n")); return 0; } int udf_writeout_LVID(struct udf_log_vol *udf_log_vol, int type) { union dscrptr *dscr; struct logvol_int_desc *intdesc; struct udf_logvol_info *impl; struct udf_session *session; struct udf_partition *udf_partition; struct udf_part_mapping *part_mapping; struct desc_tag *terminator; struct udf_wrcallback wr_callback; uint32_t sector, lvid_sector, term_sector; uint32_t part_num, *free_space_pos, *size_pos, lb_size; uint32_t len, length, lvid_len, num_sectors; int error, dscr_ver, tagid; /* create a new `fresh' logvol integrity */ session = udf_log_vol->primary->udf_session; lb_size = udf_log_vol->lb_size; num_sectors = lb_size / session->disc->sector_size; intdesc = calloc(1, udf_log_vol->lb_size); if (!intdesc) return ENOMEM; sector = udf_rw32(udf_log_vol->log_vol->integrity_seq_loc.loc); length = udf_rw32(udf_log_vol->log_vol->integrity_seq_loc.len); if (!length) return ENOENT; /* search insertion place */ lvid_sector = 0; term_sector = 0; while (length) { error = udf_read_session_descriptor(udf_log_vol->primary->udf_session, sector, "Logical volume integrity descriptor (LVID)", &dscr, &lvid_len); /* getting a terminator tag or zero is an OK condition */ if (error) { tagid = 0; } else { tagid = udf_rw16(dscr->tag.id); } if ((tagid == TAGID_TERM) || (tagid == 0)) { lvid_sector = sector; if (length > lb_size) { /* space for a terminator */ term_sector = sector + num_sectors; } break; /* while */ } length -= lb_size; sector += num_sectors; if (udf_rw32(dscr->lvid.next_extent.len)) { sector = udf_rw32(dscr->lvid.next_extent.loc); length = udf_rw32(dscr->lvid.next_extent.len); } /* free consumed descriptor */ free(dscr); dscr = NULL; } if (dscr) free(dscr); if ((!lvid_sector) || (length == 0)) { sector = udf_rw32(udf_log_vol->log_vol->integrity_seq_loc.loc); length = udf_rw32(udf_log_vol->log_vol->integrity_seq_loc.len); lvid_sector = sector; if (length > lb_size) { /* space for a terminator */ term_sector = lvid_sector + num_sectors; } } assert(lvid_sector); /* build up integrity descriptor and write it out */ dscr_ver = udf_rw16(udf_log_vol->log_vol->tag.descriptor_ver); udf_init_desc_tag(&intdesc->tag, TAGID_LOGVOL_INTEGRITY, dscr_ver, udf_log_vol->integrity_serial); udf_set_timestamp_now(&intdesc->time); intdesc->integrity_type = udf_rw32(type); intdesc->lvint_next_unique_id = udf_rw64(udf_log_vol->next_unique_id); /* calculate and fill in free space */ intdesc->num_part = udf_rw32(udf_log_vol->num_part_mappings); free_space_pos = &intdesc->tables[0]; size_pos = &intdesc->tables[udf_log_vol->num_part_mappings]; SLIST_FOREACH(part_mapping, &udf_log_vol->part_mappings, next_mapping) { part_num = part_mapping->udf_virt_part_num; udf_logvol_vpart_to_partition(udf_log_vol, part_num, NULL, &udf_partition); assert(udf_partition); *size_pos++ = udf_partition->partition->part_len; *free_space_pos++ = udf_rw32(udf_partition->free_unalloc_space / udf_log_vol->lb_size); } /* fill in UDF implementation use parameters */ impl = (struct udf_logvol_info *) (&intdesc->tables[2*udf_log_vol->num_part_mappings]); udf_set_imp_id(&impl->impl_id); impl->num_files = udf_rw32(udf_log_vol->num_files); impl->num_directories = udf_rw32(udf_log_vol->num_directories); impl->min_udf_readver = udf_rw16(udf_log_vol->min_udf_readver); impl->min_udf_writever = udf_rw16(udf_log_vol->min_udf_writever); impl->max_udf_writever = udf_rw16(udf_log_vol->max_udf_writever); intdesc->l_iu = udf_rw32(sizeof(struct udf_logvol_info)); /* ECMA 3/10.10.7, UDF 2.2.6.4. */ len = sizeof(struct logvol_int_desc) - sizeof(uint32_t); /* length of logvol_int_desc without the extra table entry */ len += sizeof(uint32_t) * 2 * udf_log_vol->num_part_mappings; /* size and free space */ len += sizeof(struct udf_logvol_info); /* extra implementation use area */ len -= UDF_DESC_TAG_LENGTH; /* without header */ intdesc->tag.desc_crc_len = udf_rw16(len); udf_write_session_descriptor(session, lvid_sector, "Logvol integrity descriptor (LVID)", (union dscrptr *) intdesc, &wr_callback); if (session->disc->rewritable && term_sector) { /* only when there is space and its a rewritable media add a terminor */ error = udf_create_empty_terminator_descriptor(lb_size, dscr_ver, &terminator); if (!error) { udf_write_session_descriptor(session, term_sector, "Logvol integrity sequence descriptor sequence terminator", (union dscrptr *) terminator, &wr_callback); free(terminator); } } free(intdesc); return 0; } /* mark the logical volume `open'; for non-rewritables (CD-R/DVD+R/DVD-R) this is allmost a no-op */ int udf_open_logvol(struct udf_log_vol *udf_log_vol) { int error; if (!udf_log_vol->writable) { udf_dump_volume_name("\nLogical volume marked read only: ", udf_log_vol); return EROFS; } /* will return many times for each write */ if (udf_log_vol->logvol_state == UDF_INTEGRITY_OPEN) return 0; /* * Opening and closing logical volumes is derived from the state of * the primaries disc. */ udf_dump_volume_name("Opening logical volume", udf_log_vol); if (!udf_log_vol->primary->udf_session->disc->sequential) { error = udf_writeout_LVID(udf_log_vol, UDF_INTEGRITY_OPEN); assert(!error); /* sync caches to make sure all is written out */ udf_sync_caches(udf_log_vol); /* FIXME (callback) XXX ought to wait until we get the ALL-OK signal from the writeout-LVID action XXX */ } else { /* sequential recordable; any write just opens it; the descriptor is allready marked open */ } /* mark it open */ udf_log_vol->logvol_state = UDF_INTEGRITY_OPEN; return 0; } /* mark the logical volume in a `closed' state; close the integrity when possible for recordables writeout VAT */ int udf_close_logvol(struct udf_log_vol *udf_log_vol) { int error; if (udf_log_vol->logvol_state == UDF_INTEGRITY_CLOSED) { DEBUG(printf("close logvol: integrity allready closed\n")); return 0; } /* * Opening and closing logical volumes is derived from the state of * the primaries disc. */ udf_dump_volume_name("Closing logical volume", udf_log_vol); if (!udf_log_vol->primary->udf_session->disc->sequential) { error = udf_writeout_LVID(udf_log_vol, UDF_INTEGRITY_CLOSED); assert(!error); } else { /* XXX TODO XXX */ fprintf(stderr, "write out virtual sectors, compile VAT and write out VAT : not implemented\n"); return EIO; } /* sync caches to make sure all is written out */ udf_sync_caches(udf_log_vol); /* FIXME (callback) XXX ought to wait until we get the ALL-OK signal from the writeout-LVID action XXX */ /* mark it closed again */ udf_log_vol->logvol_state = UDF_INTEGRITY_CLOSED; return 0; } int udf_sync_logvol(struct udf_log_vol *udf_log_vol) { struct udf_node *udf_node; uint32_t num_dirty, count, prnt; int error; if (!udf_log_vol->writable) return 0; if (udf_log_vol->logvol_state == UDF_INTEGRITY_CLOSED) { DEBUG(printf("close logvol: its closed so no sync nessisary\n")); return 0; } UDF_VERBOSE(udf_dump_volume_name("\tsyncing ", udf_log_vol)); /* sync all nodes */ /* XXX syncing logvol sequential due to insertion sort in add node XXX */ num_dirty = 0; TAILQ_FOREACH(udf_node, &udf_log_vol->dirty_nodes, next_dirty) { num_dirty++; } /* * Purge all data out first, this will speed things up later (not * strickly nessissary since syncing a node will wait for all the data * to be written out first anyway */ count = num_dirty; prnt = 0; UDF_VERBOSE(printf("\t\tsyncing data\n")); TAILQ_FOREACH(udf_node, &udf_log_vol->dirty_nodes, next_dirty) { UDF_VERBOSE(printf("\r%8d", count); fflush(stdout)); udf_sync_udf_node(udf_node, "Sync Logvol"); count--; prnt = 1; } if (prnt) UDF_VERBOSE(printf("\r \r")); /* * Purge all nodes out... they ought to have no dirty buffers anymore * but they will write them out if deemed nessisary */ count = num_dirty; prnt = 0; UDF_VERBOSE(printf("\t\tsyncing nodes\n")); TAILQ_FOREACH(udf_node, &udf_log_vol->dirty_nodes, next_dirty) { UDF_VERBOSE(printf("\r%8d", count); fflush(stdout)); DEBUG(printf("N"); fflush(stdout)); udf_writeout_udf_node(udf_node, "Sync Logvol"); count--; prnt = 1; } if (prnt) UDF_VERBOSE(printf("\r \r")); /* shouldn't be nessisary */ udf_bufcache->flushall = 1; udf_purgethread_kick("Sync Logvol"); usleep(1); if (udf_bufcache->lru_len_dirty_metadata + udf_bufcache->lru_len_dirty_data) { printf("Warning: after syncing logvol dirty counts != 0 (%d, %d); please contact author.\n", udf_bufcache->lru_len_dirty_metadata, udf_bufcache->lru_len_dirty_data); } /* sync free and used space tables for writable volsets */ UDF_VERBOSE(printf("\t\tused/freed space tables\n")); error = udf_sync_space_tables(udf_log_vol); /* close logical volume */ udf_close_logvol(udf_log_vol); return error; } /* convenience routine */ int udf_sync_disc(struct udf_discinfo *disc) { struct udf_volumeset *udf_volumeset; struct udf_pri_vol *udf_pri_vol; struct udf_log_vol *udf_log_vol; SLIST_FOREACH(udf_volumeset, &udf_volumeset_list, next_volumeset) { if (!udf_volumeset->obsolete) { STAILQ_FOREACH(udf_pri_vol, &udf_volumeset->primaries, next_primary) { if (udf_pri_vol->udf_session->disc == disc) { SLIST_FOREACH(udf_log_vol, &udf_pri_vol->log_vols, next_logvol) { udf_sync_logvol(udf_log_vol); } /* logical */ } /* disc */ } /* primary */ } /* if */ } /* volumeset */ return 0; } /****************************************************************************************** * * UDF descriptor buildup and update functions * ******************************************************************************************/ static void udf_init_desc_tag(struct desc_tag *tag, uint16_t id, uint16_t dscr_ver, uint16_t serial_num) { bzero(tag, sizeof(struct desc_tag)); tag->id = udf_rw16(id); tag->descriptor_ver = udf_rw16(dscr_ver); tag->serial_num = udf_rw16(serial_num); /* the rest gets filled in when we write */ } static void udf_osta_charset(struct charspec *charspec) { bzero(charspec, sizeof(struct charspec)); charspec->type = 0; strcpy((char *) charspec->inf, "OSTA Compressed Unicode"); } static void udf_encode_osta_id(char *osta_id, uint16_t len, char *text) { uint16_t u16_name[1024]; uint8_t *pos; uint16_t *pos16; bzero(osta_id, len); if (!text) return; bzero(u16_name, sizeof(uint16_t) * 1023); /* convert ascii to 16 bits unicode */ pos = (uint8_t *) text; pos16 = u16_name; while (*pos) { *pos16 = *pos; pos++; pos16++; } *pos16 = 0; udf_CompressUnicode(len, 8, (unicode_t *) u16_name, (byte *) osta_id); /* Ecma 167/7.2.13 states that the length is recorded in the last byte */ osta_id[len-1] = strlen(text)+1; } static void udf_set_app_id(struct regid *regid) { bzero(regid, sizeof(struct regid)); regid->flags = 0; /* not dirty and not protected */ strcpy((char *) regid->id, APP_NAME); regid->id_suffix[0] = APP_VERSION_MAIN; regid->id_suffix[1] = APP_VERSION_SUB; } static void udf_set_imp_id(struct regid *regid) { bzero(regid, sizeof(struct regid)); regid->flags = 0; /* not dirty and not protected */ strcpy((char *) regid->id, IMPL_NAME); regid->id_suffix[0] = 4; /* unix */ regid->id_suffix[1] = 0; /* generic */ #if defined(__ANONYMOUSUDF__) #elif defined(__NetBSD__) regid->id_suffix[1] = 8; /* NetBSD */ #elif defined(__FreeBSD__) regid->id_suffix[1] = 7; /* FreeBSD */ #elif defined(LINUX) regid->id_suffix[1] = 5; /* Linux */ #endif } static void udf_set_entity_id(struct regid *regid, char *name, uint16_t UDF_version) { uint16_t *ver; bzero(regid, sizeof(struct regid)); regid->flags = 0; /* not dirty and not protected */ strcpy((char *) regid->id, name); ver = (uint16_t *) regid->id_suffix; *ver = udf_rw16(UDF_version); regid->id_suffix[2] = 4; /* unix */ regid->id_suffix[3] = 0; /* generic */ #if defined(__ANONYMOUSUDF__) #elif defined(__NetBSD__) regid->id_suffix[3] = 8; /* NetBSD */ #elif defined(__FreeBSD__) regid->id_suffix[3] = 7; /* FreeBSD */ #elif defined(LINUX) regid->id_suffix[3] = 5; /* Linux */ #endif } void udf_set_contents_id(struct regid *regid, char *content_id) { bzero(regid, sizeof(struct regid)); regid->flags = 0; strcpy((char *) regid->id, content_id); } /* XXX creators of empty descriptors could be externalised */ /* * result can be further processed using modify functions if demanded and then * processed trough udf_proc_pri_vol * [ int udf_proc_pri_vol(struct udf_session *udf_session, struct udf_pri_vol **current, struct pri_vol_desc *incomming); ] * */ int udf_create_empty_primary_volume_descriptor(uint32_t sector_size, uint16_t dscr_ver, uint16_t serial, char *volset_id, char *privol_name, int vds_num, int max_vol_seq, struct pri_vol_desc **dscrptr) { struct pri_vol_desc *dscr; assert(dscrptr); *dscrptr = NULL; /* allocate and populate an empty primary volume descriptor */ dscr = malloc(sector_size); if (!dscr) return ENOMEM; bzero(dscr, sector_size); udf_init_desc_tag(&dscr->tag, TAGID_PRI_VOL, dscr_ver, 1); dscr->pvd_num = udf_rw32(serial); udf_encode_osta_id(dscr->vol_id, 32, privol_name); dscr->vds_num = udf_rw16(vds_num); dscr->max_vol_seq = udf_rw16(max_vol_seq); if (max_vol_seq > 1) { dscr->ichg_lvl = udf_rw16(3); /* signal its a single volume intended to be in a set */ dscr->max_ichg_lvl = udf_rw16(3); /* ,, */ dscr->flags = udf_rw16(1); /* signal relevance volumeset id */ } else { dscr->ichg_lvl = udf_rw16(2); /* signal its volume intended not to be in a set */ dscr->max_ichg_lvl = udf_rw16(2); /* ,, */ dscr->flags = udf_rw16(0); /* signal relevance volumeset id */ } dscr->charset_list = udf_rw32(1); /* only CS0 */ dscr->max_charset_list = udf_rw32(1); udf_encode_osta_id(dscr->volset_id, 128, volset_id); udf_osta_charset(&dscr->desc_charset); udf_osta_charset(&dscr->explanatory_charset); udf_set_app_id(&dscr->app_id); udf_set_imp_id(&dscr->imp_id); udf_set_timestamp_now(&dscr->time); dscr->tag.desc_crc_len = udf_rw16(sizeof(struct pri_vol_desc) - UDF_DESC_TAG_LENGTH); *dscrptr = dscr; return 0; } int udf_create_empty_partition_descriptor(uint32_t sector_size, uint16_t dscr_ver, uint16_t serial, uint16_t part_num, uint32_t access_type, uint32_t start_loc, uint32_t part_len, uint32_t space_bitmap_size, uint32_t unalloc_space_bitmap, struct part_desc **dscrptr) { struct part_desc *dscr; struct part_hdr_desc *part_hdr; assert(dscrptr); *dscrptr = NULL; /* allocate and populate empty partition descriptor */ dscr = malloc(sector_size); /* only descriptor, no bitmap! */ if (!dscr) return ENOMEM; bzero(dscr, sector_size); udf_init_desc_tag(&dscr->tag, TAGID_PARTITION, dscr_ver, 1); dscr->seq_num = udf_rw32(serial); dscr->flags = udf_rw16(1); /* bit 0 : space is allocated */ dscr->part_num = udf_rw16(part_num); if (dscr_ver == 2) udf_set_contents_id(&dscr->contents, "+NSR02"); if (dscr_ver == 3) udf_set_contents_id(&dscr->contents, "+NSR03"); part_hdr = &dscr->pd_part_hdr; part_hdr->unalloc_space_bitmap.len = udf_rw32(space_bitmap_size); part_hdr->unalloc_space_bitmap.lb_num = udf_rw32(unalloc_space_bitmap); dscr->access_type = udf_rw32(access_type); dscr->start_loc = udf_rw32(start_loc); dscr->part_len = udf_rw32(part_len); udf_set_imp_id(&dscr->imp_id); /* why is this ignored? */ dscr->tag.desc_crc_len = udf_rw16(sizeof(struct part_desc) - UDF_DESC_TAG_LENGTH); *dscrptr = dscr; return 0; } int udf_create_empty_unallocated_space_descriptor(uint32_t sector_size, uint16_t dscr_ver, uint16_t serial, struct unalloc_sp_desc **dscrptr) { struct unalloc_sp_desc *dscr; assert(dscrptr); *dscrptr = NULL; /* allocate and populate an empty unallocated space descriptor */ dscr = malloc(sector_size); if (!dscr) return ENOMEM; bzero(dscr, sector_size); udf_init_desc_tag(&dscr->tag, TAGID_UNALLOC_SPACE, dscr_ver, 1); dscr->seq_num = udf_rw32(serial); dscr->tag.desc_crc_len = udf_rw16(sizeof(struct unalloc_sp_desc) - sizeof(struct extent_ad) - UDF_DESC_TAG_LENGTH); *dscrptr = dscr; return 0; } int udf_create_empty_implementation_use_volume_descriptor(uint32_t sector_size, uint16_t dscr_ver, uint16_t serial, char *logvol_name, struct impvol_desc **dscrptr) { struct impvol_desc *dscr; struct udf_lv_info *lv_info; assert(dscrptr); *dscrptr = NULL; /* allocate and populate an empty implementation use volume descriptor */ dscr = malloc(sector_size); if (!dscr) return ENOMEM; bzero(dscr, sector_size); udf_init_desc_tag(&dscr->tag, TAGID_IMP_VOL, dscr_ver, 1); dscr->seq_num = udf_rw32(serial); udf_set_entity_id(&dscr->impl_id, "*UDF LV Info", 0x102); /* just pick one; it'll be modifed later */ lv_info = &dscr->_impl_use.lv_info; udf_osta_charset(&lv_info->lvi_charset); udf_encode_osta_id(lv_info->logvol_id, 128, logvol_name); udf_encode_osta_id(lv_info->lvinfo1, 36, NULL); udf_encode_osta_id(lv_info->lvinfo2, 36, NULL); udf_encode_osta_id(lv_info->lvinfo3, 36, NULL); udf_set_imp_id(&lv_info->impl_id); dscr->tag.desc_crc_len = udf_rw16(sizeof(struct impvol_desc) - UDF_DESC_TAG_LENGTH); *dscrptr = dscr; return 0; } int udf_create_empty_logical_volume_descriptor(uint32_t sector_size, uint16_t dscr_ver, uint16_t serial, char *logvol_name, uint32_t lb_size, uint32_t integrity_start, uint32_t integrity_length, struct logvol_desc **dscrptr) { struct logvol_desc *dscr; assert(dscrptr); *dscrptr = NULL; /* allocate and populate an empty logical volume descriptor */ dscr = malloc(sector_size); if (!dscr) return ENOMEM; bzero(dscr, sector_size); udf_init_desc_tag(&dscr->tag, TAGID_LOGVOL, dscr_ver, 1); dscr->seq_num = udf_rw32(serial); udf_osta_charset(&dscr->desc_charset); udf_encode_osta_id(dscr->logvol_id, 128, logvol_name); dscr->lb_size = udf_rw32(lb_size); udf_set_contents_id(&dscr->domain_id, "*OSTA UDF Compliant"); /* no fsd yet nor partition mapping */ udf_set_imp_id(&dscr->imp_id); dscr->integrity_seq_loc.loc = udf_rw32(integrity_start); dscr->integrity_seq_loc.len = udf_rw32(integrity_length * lb_size); dscr->tag.desc_crc_len = udf_rw16(sizeof(struct logvol_desc) - 1 - UDF_DESC_TAG_LENGTH); *dscrptr = dscr; return 0; } int udf_create_empty_space_bitmap(uint32_t sector_size, uint16_t dscr_ver, uint32_t num_lbs, struct space_bitmap_desc **dscrptr) { struct space_bitmap_desc *dscr; uint64_t bits; uint32_t bytes, space_bitmap_size; assert(dscrptr); *dscrptr = NULL; /* reserve space for unallocated space bitmap */ bits = num_lbs; bytes = (bits + 7)/8; space_bitmap_size = (bytes + sizeof(struct space_bitmap_desc)-1); /* round space bitmap size to sector size */ space_bitmap_size = ((space_bitmap_size + sector_size - 1) / sector_size) * sector_size; /* allocate and populate an empty space bitmap descriptor */ dscr = malloc(space_bitmap_size); if (!dscr) return ENOMEM; bzero(dscr, space_bitmap_size); udf_init_desc_tag(&dscr->tag, TAGID_SPACE_BITMAP, dscr_ver, 1); /* crc length 8 is recommended, UDF 2.3.1.2, 2.3.8.1, errata DCN-5108 for UDF 2.50 and lower. */ dscr->tag.desc_crc_len = udf_rw16(8); dscr->num_bits = udf_rw32(bits); dscr->num_bytes = udf_rw32(bytes); *dscrptr = dscr; return 0; } /* FIXME: no rootdir setting yet */ /* FIXME: fileset desc. is disc sector size or lb_size ? */ int udf_create_empty_fileset_desc(uint32_t sector_size, uint16_t dscr_ver, uint32_t fileset_num, char *logvol_name, char *fileset_name, struct fileset_desc **dscrptr) { struct fileset_desc *dscr; assert(dscrptr); *dscrptr = NULL; /* allocate and populate an empty logical volume descriptor */ dscr = malloc(sector_size); if (!dscr) return ENOMEM; bzero(dscr, sector_size); udf_init_desc_tag(&dscr->tag, TAGID_FSD, dscr_ver, 1); udf_set_timestamp_now(&dscr->time); dscr->ichg_lvl = udf_rw16(3); /* fixed? */ dscr->max_ichg_lvl = udf_rw16(3); /* fixed? */ dscr->charset_list = udf_rw32(1); /* only CS0 */ dscr->max_charset_list = udf_rw32(1); /* only CS0 */ dscr->fileset_num = udf_rw32(fileset_num); /* key for fileset */ dscr->fileset_desc_num = udf_rw32(0); /* fileset descriptor number as in copy # */ udf_osta_charset(&dscr->logvol_id_charset); udf_encode_osta_id(dscr->logvol_id, 128, logvol_name); udf_osta_charset(&dscr->fileset_charset); udf_encode_osta_id(dscr->fileset_id, 32, fileset_name); udf_encode_osta_id(dscr->copyright_file_id, 32, NULL); udf_encode_osta_id(dscr->abstract_file_id, 32, NULL); udf_set_contents_id(&dscr->domain_id, "*OSTA UDF Compliant"); dscr->tag.desc_crc_len = udf_rw16(sizeof(struct fileset_desc) - UDF_DESC_TAG_LENGTH); *dscrptr = dscr; return 0; } int udf_create_empty_anchor_volume_descriptor(uint32_t sector_size, uint16_t dscr_ver, uint32_t main_vds_loc, uint32_t reserve_vds_loc, uint32_t length, struct anchor_vdp **vdp) { assert(vdp); assert(main_vds_loc - reserve_vds_loc >= length); *vdp = malloc(sector_size); if (!*vdp) return ENOMEM; bzero(*vdp, sector_size); udf_init_desc_tag(&(*vdp)->tag, TAGID_ANCHOR, dscr_ver, 1); (*vdp)->main_vds_ex.loc = udf_rw32(main_vds_loc); (*vdp)->main_vds_ex.len = udf_rw32(length * sector_size); (*vdp)->reserve_vds_ex.loc = udf_rw32(reserve_vds_loc); (*vdp)->reserve_vds_ex.len = udf_rw32(length * sector_size); (*vdp)->tag.desc_crc_len = udf_rw16(512-UDF_DESC_TAG_LENGTH); /* fixed size in Ecma */ return 0; } int udf_create_empty_terminator_descriptor(uint32_t sector_size, uint16_t dscr_ver, struct desc_tag **tag) { assert(tag); *tag = malloc(sector_size); if (!*tag) return ENOMEM; bzero(*tag, sector_size); udf_init_desc_tag(*tag, TAGID_TERM, dscr_ver, 1); (*tag)->desc_crc_len = udf_rw16(512-UDF_DESC_TAG_LENGTH); /* fixed size in Ecma */ return 0; } /****************************************************************************************** * * Basic `open' and `close' disc functions * ******************************************************************************************/ static void udf_process_session_range(struct udf_discinfo *disc, int *enabled, int low, int high) { int session; if (!disc) return; high = MIN(high, disc->num_sessions-1); session = low; for (session = low; session <= high; session++) { enabled[session] = 1; } } /* range is specified in -3,5,7 or 5-6,8- etc */ static int udf_process_session_range_string(struct udf_discinfo *disc, char *range) { struct udf_session *udf_session, *next_udf_session; char *pos, *nop; int low, high, len, session; int enabled[MAX_SESSIONS]; if (!range) return 0; DEBUG(printf("UDF range debugging string '%s'\n", range)); if (disc) { /* disable all */ for (session = 0; session < disc->num_sessions; session++) { enabled[session] = 0; } } /* parse string */ nop = strdup(range); pos = range; if (sscanf(pos, "-%u%n%s", &high, &len, nop) >= 1) { DEBUG(printf("UDF range match till %d\n", high)); udf_process_session_range(disc, enabled, 0, high); pos += len; } if (*pos && *pos == ',') pos++; while (*pos) { if (sscanf(pos, "%u%n%s", &low, &len, nop) >= 1) { pos += len; if (*pos == '-') { pos++; if (!*pos) { DEBUG(printf("UDF range match from %d\n", low)); udf_process_session_range(disc, enabled, low, INT_MAX); free(nop); return 0; } if (sscanf(pos, "%u%n%s", &high, &len, nop) >= 1) { pos += len; DEBUG(printf("UDF range match from %d to %d\n", low, high)); udf_process_session_range(disc, enabled, low, high); } } else { if (!*pos || (*pos == ',')) { DEBUG(printf("UDF range match %d\n", low)); udf_process_session_range(disc, enabled, low, low); } } if (*pos && (*pos != ',')) { fprintf(stderr, "UDF range matching : ',' expected at %s\n", pos); free(nop); return ENOENT; } pos++; } else { fprintf(stderr, "UDF range matching : number expected at %s\n", pos); free(nop); return ENOENT; } } free(nop); DEBUG(printf("UDF range matching : all ok till the end\n")); if (!disc) return 0; udf_session = STAILQ_FIRST(&disc->sessions); while (udf_session) { next_udf_session = STAILQ_NEXT(udf_session, next_session); session = udf_session->session_num; if (!enabled[session]) { /* remove this session */ fprintf(stderr, "UDF: disabling UDF session %d on request\n", session); STAILQ_REMOVE(&disc->sessions, udf_session, udf_session, next_session); free(udf_session); disc->session_is_UDF[session] = 0; } udf_session = next_udf_session; } return 0; } int udf_check_session_range(char *range) { return udf_process_session_range_string(NULL, range); } void udf_init(void) { udf_unix_init(); udf_start_unix_thread(); dirhash_init(); SLIST_INIT(&udf_discs_list); } int udf_mount_disc(char *devname, char *range, uint32_t sector_size, int mnt_flags, struct udf_discinfo **disc) { int discop_flags, error; discop_flags = mnt_flags & UDF_MNT_BSWAP ? UDF_DISCOP_BSWAP : 0; error = udf_open_disc(devname, discop_flags, disc); if ((!error) && sector_size) error = udf_discinfo_alter_perception(*disc, sector_size, 0); if (error) return error; error = udf_get_anchors(*disc); UDF_VERBOSE(udf_dump_disc_anchors(*disc)); if (range) { UDF_VERBOSE(printf("Selecting UDF sessions '%s' as specified\n", range)); udf_process_session_range_string(*disc, range); UDF_VERBOSE(udf_dump_disc_anchors(*disc)); } /* no UDF partitions so bail out */ if ((*disc)->num_udf_sessions == 0) return 0; UDF_VERBOSE(printf("Start mounting\n")); error = udf_get_volumeset_space(*disc); if (error) return error; UDF_VERBOSE(printf("\teliminating predescessors\n")); udf_eliminate_predescessor_volumesets(*disc); UDF_VERBOSE_TABLES(udf_dump_alive_sets()); UDF_VERBOSE(printf("\tretrieving logical volume dependencies %p\n", *disc)); error = udf_get_logical_volumes_supporting_tables(*disc, mnt_flags); UDF_VERBOSE_TABLES(udf_dump_alive_sets()); /* insert disc in the disc list */ SLIST_INSERT_HEAD(&udf_discs_list, *disc, next_disc); return error; } int udf_dismount_disc(struct udf_discinfo *disc) { UDF_VERBOSE(printf("Dismounting disc\n")); if (!disc->recordable) { /* easy way out: it was a read-only system */ UDF_VERBOSE(printf("\tdismounting readonly disc\n")); udf_stop_unix_thread(); udf_close_disc(disc); return 0; } /* Sync disc before closing it */ UDF_VERBOSE(printf("\tsyncing disc\n")); udf_sync_disc(disc); /* wait for the disc to idle */ UDF_VERBOSE(printf("\twait for syncing disc to idle\n")); while (!udf_discinfo_check_disc_ready(disc)) { sleep(1); } /* stop threads and finish writing to it */ udf_stop_unix_thread(); UDF_VERBOSE(printf("\tsignal disc its finished with writing\n")); udf_discinfo_finish_writing(disc); /* wait for the disc to idle again */ UDF_VERBOSE(printf("\twait for final disc idling\n")); while (!udf_discinfo_check_disc_ready(disc)) { sleep(1); } UDF_VERBOSE(printf("\tclose device\n")); udf_close_disc(disc); return 0; } /****************************************************************************************** * * Directory and other conversion UDF logic * Move to udf_unix.c / udf_vnops.c one day? * ******************************************************************************************/ static int udf_translate_icb_filetype_to_dirent_filetype(int udf_filetype) { int d_type; switch (udf_filetype) { case UDF_ICB_FILETYPE_DIRECTORY : d_type = DT_DIR; break; case UDF_ICB_FILETYPE_STREAMDIR : d_type = DT_DIR; break; case UDF_ICB_FILETYPE_FIFO : d_type = DT_FIFO; break; case UDF_ICB_FILETYPE_CHARDEVICE : d_type = DT_CHR; break; case UDF_ICB_FILETYPE_BLOCKDEVICE : d_type = DT_BLK; break; case UDF_ICB_FILETYPE_RANDOMACCESS : d_type = DT_REG; break; case UDF_ICB_FILETYPE_SYMLINK : d_type = DT_LNK; break; case UDF_ICB_FILETYPE_SOCKET : d_type = DT_SOCK; break; default : d_type = DT_UNKNOWN; break; } return d_type; } /* VOP_GETATTR */ /* allmost NOOP since we remember the stat in the inode */ int udf_getattr(struct udf_node *udf_node, struct stat *stat) { *stat = udf_node->stat; /* special: updatables */ stat->st_nlink = udf_node->link_cnt; stat->st_blocks = (stat->st_size + 512 -1)/512; /* blocks are hardcoded 512 bytes/sector in stat :-/ */ return 0; } /* VOP_SETATTR */ /* allmost NOOP since we remember the stat in the inode */ /* note VOP_SETATTR can selectively set attrs */ int udf_setattr(struct udf_node *udf_node, struct stat *stat) { if (!udf_node) return ENOENT; if (udf_open_logvol(udf_node->udf_log_vol)) return EROFS; /* FIXME please don't just copy everything ... XXX */ udf_node->stat = *stat; /* not attribute change time */ udf_set_timespec_now(&udf_node->stat.st_ctimespec); udf_node_mark_dirty(udf_node); return 0; } void udf_resync_fid_stream(uint8_t *buffer, uint32_t *pfid_pos, uint32_t max_fid_pos, int *phas_fids) { struct fileid_desc *fid; uint32_t fid_pos; int has_fids; assert(buffer); assert(pfid_pos); assert(phas_fids); has_fids = 0; fid_pos = *pfid_pos; while (!has_fids) { while (fid_pos <= max_fid_pos) { fid = (struct fileid_desc *) (buffer + fid_pos); if (udf_rw16(fid->tag.id) == TAGID_FID) break; /* fid's can only exist 4 bytes aligned */ fid_pos += 4; } if (fid_pos > max_fid_pos) { /* shouldn't happen ! to prevent chaos, do nothing */ /* XXX ought to give a warning? XXX */ has_fids = 0; break; } else { /* check if we found a valid FID */ fid = (struct fileid_desc *) (buffer + fid_pos); has_fids = (udf_check_tag((union dscrptr *) fid) == 0); if (has_fids) { assert(udf_rw16(fid->tag.id) == TAGID_FID); break; } } } *pfid_pos = fid_pos; *phas_fids = has_fids; } /* read one fid and process it into a dirent and advance to the next */ /* (*fid) has to be allocated a logical block in size, (*dirent) struct dirent length */ int udf_read_fid_stream(struct udf_node *dir_node, uint64_t *offset, struct fileid_desc *fid, struct dirent *dirent) { struct uio dir_uio; struct iovec dir_iovec; char *fid_name; uint32_t entry_length, lb_size; int enough, error; assert(fid); assert(dirent); assert(dir_node); assert(offset); assert(*offset != 1); lb_size = dir_node->udf_log_vol->lb_size; entry_length = 0; bzero(dirent, sizeof(struct dirent)); bzero(fid, lb_size); if (*offset >= (uint64_t) dir_node->stat.st_size) return EINVAL; bzero(&dir_uio, sizeof(struct uio)); dir_uio.uio_rw = UIO_WRITE; /* write into this space */ dir_uio.uio_iovcnt = 1; dir_uio.uio_iov = &dir_iovec; dir_iovec.iov_base = fid; dir_iovec.iov_len = lb_size; dir_uio.uio_offset = *offset; dir_uio.uio_resid = MIN(dir_node->stat.st_size - (*offset), lb_size); error = udf_read_file_part_uio(dir_node, "file id" /* udf_node->dirent.d_name */, UDF_C_FIDS, &dir_uio); if (error) return error; /* * Check if we got a whole descriptor. * XXX Try to `resync' directory stream when something is very wrong. * */ enough = (dir_uio.uio_offset - (*offset) >= UDF_FID_SIZE); if (!enough) { /* short dir ... */ return EIO; } error = udf_check_tag((union dscrptr *) fid); if (!error) { entry_length = udf_calc_tag_malloc_size((union dscrptr *) fid, lb_size); enough = (dir_uio.uio_offset - (*offset) >= entry_length); } if (!enough) { /* short dir ... */ return EIO; } if (!error) error = udf_check_tag_payload((union dscrptr *) fid); if (error) { printf("BROKEN DIRECTORY ENTRY\n"); #if 0 // udf_dump_desc(&fid->tag); // udf_dump_fileid(fid); #endif /* RESYNC? */ /* TODO: use udf_resync_fid_stream */ return EIO; } /* we got a whole and valid descriptor */ /* create resulting dirent structure */ fid_name = (char *) fid->data + udf_rw16(fid->l_iu); dirent->d_fileno = udf_rw32(fid->icb.impl.im_used.unique_id); /* only 32 bits salvageable */ #if !defined(__DragonFly__) dirent->d_reclen = sizeof(struct dirent); #endif dirent->d_type = DT_UNKNOWN; udf_to_unix_name(dirent->d_name, fid_name, fid->l_fi, &dir_node->udf_log_vol->log_vol->desc_charset); #ifndef NO_DIRENT_NAMLEN dirent->d_namlen = strlen(dirent->d_name); #endif if (fid->file_char & UDF_FILE_CHAR_DIR) dirent->d_type = DT_DIR; if (fid->file_char & UDF_FILE_CHAR_PAR) strcpy(dirent->d_name, ".."); /* advance */ *offset += entry_length; return error; } /* VOP_READDIR */ /* read in dirent's until the result_uio can't hold another */ int udf_readdir(struct udf_node *dir_node, struct uio *result_uio, int *eof_res /* int *cookies, int ncookies */) { struct fileid_desc *fid; struct dirent dirent; uint64_t diroffset, transoffset; uint32_t lb_size; int eof; int error; assert(eof_res); if (!dir_node) return EINVAL; if (!dir_node->udf_log_vol) return EINVAL; assert(result_uio->uio_resid >= sizeof(struct dirent)); lb_size = dir_node->udf_log_vol->lb_size; fid = malloc(lb_size); if (!fid) return ENOMEM; /* check if we ought to insert dummy `.' node */ if (result_uio->uio_offset == 0) { bzero(&dirent, sizeof(struct dirent)); strcpy(dirent.d_name, "."); dirent.d_type = DT_DIR; #ifndef NO_DIRENT_NAMLEN dirent.d_namlen = 2; #endif uiomove(&dirent, sizeof(struct dirent), result_uio); /* mark with magic value (yeah it suxxs) that we have done the dummy */ result_uio->uio_offset = 1; } /* start directory reading */ diroffset = result_uio->uio_offset; transoffset = diroffset; while (diroffset < (uint64_t) dir_node->stat.st_size) { /* read just the offset when its flagged */ if (diroffset == 1) { diroffset = result_uio->uio_offset = 0; } /* read in FIDs */ error = udf_read_fid_stream(dir_node, &diroffset, fid, &dirent); if (error) { printf("Error while reading directory file: %s\n", strerror(error)); free(fid); return error; } /* if there is not enough space for the dirent break off read */ if (result_uio->uio_resid < sizeof(struct dirent)) break; /* remember the last entry we transfered */ transoffset = diroffset; /* skip deleted entries */ if (fid->file_char & UDF_FILE_CHAR_DEL) continue; /* skip not visible entries */ if (fid->file_char & UDF_FILE_CHAR_VIS) continue; uiomove(&dirent, sizeof(struct dirent), result_uio); } /* pass on last transfered offset */ result_uio->uio_offset = transoffset; free(fid); eof = (result_uio->uio_offset >= (int64_t) dir_node->stat.st_size); if (eof_res) *eof_res = 1; *eof_res = eof; return 0; } static int dirhash_fill(struct udf_node *dir_node) { struct dirhash *dirh; struct fileid_desc *fid; struct dirent *dirent; uint64_t file_size, pre_diroffset, diroffset; uint32_t lb_size; int error; /* make sure we have a dirhash to work on */ dirh = dir_node->dir_hash; assert(dirh); assert(dirh->refcnt > 0); if (dirh->flags & DIRH_BROKEN) return EIO; if (dirh->flags & DIRH_COMPLETE) return 0; /* make sure we have a clean dirhash to add to */ dirhash_purge_entries(dirh); /* get directory filesize */ file_size = dir_node->stat.st_size; /* allocate temporary space for fid */ lb_size = dir_node->udf_log_vol->lb_size; fid = malloc(lb_size); assert(fid); /* allocate temporary space for dirent */ dirent = malloc(sizeof(struct dirent)); assert(dirent); error = 0; diroffset = 0; while (diroffset < file_size) { /* transfer a new fid/dirent */ pre_diroffset = diroffset; error = udf_read_fid_stream(dir_node, &diroffset, fid, dirent); if (error) { /* TODO what to do? continue but not add? */ dirh->flags |= DIRH_BROKEN; dirhash_purge_entries(dirh); break; } if ((fid->file_char & UDF_FILE_CHAR_DEL)) { /* register deleted extent for reuse */ dirhash_enter_freed(dirh, pre_diroffset, udf_fidsize(fid)); } else { /* append to the dirhash */ dirhash_enter(dirh, dirent, pre_diroffset, udf_fidsize(fid), 0); /* XXX speedup HACK: preread in our nodes to compensate for too lazy backend */ { struct udf_node *res_node; error = udf_readin_udf_node(dir_node, &fid->icb, fid, &res_node); } } } dirh->flags |= DIRH_COMPLETE; free(fid); free(dirent); return error; } /* XXX yes, move namelen to unsigned int */ int udf_lookup_name_in_dir(struct udf_node *dir_node, char *name, int namelen, struct long_ad *icb_loc, struct fileid_desc *fid, int *found) { struct dirhash *dirh; struct dirhash_entry *dirh_ep; struct dirent *dirent; uint64_t diroffset; int hit, error; /* set default return */ *found = 0; /* get our dirhash and make sure its read in */ dirhash_get(&dir_node->dir_hash); error = dirhash_fill(dir_node); if (error) { dirhash_put(dir_node->dir_hash); return error; } dirh = dir_node->dir_hash; /* allocate temporary space for dirent */ dirent = malloc(sizeof(struct dirent)); if (!dirent) return ENOMEM; DEBUG(printf("dirhash_lookup looking for `%*.*s`\n", namelen, namelen, name)); /* search our dirhash hits */ memset(icb_loc, 0, sizeof(*icb_loc)); dirh_ep = NULL; for (;;) { hit = dirhash_lookup(dirh, name, namelen, &dirh_ep); /* if no hit, abort the search */ if (!hit) break; /* check this hit */ diroffset = dirh_ep->offset; /* transfer a new fid/dirent */ error = udf_read_fid_stream(dir_node, &diroffset, fid, dirent); if (error) break; DEBUG(printf("dirhash_lookup\tchecking `%*.*s`\n", (int) DIRENT_NAMLEN(dirent), (int) DIRENT_NAMLEN(dirent), dirent->d_name)); /* see if its our entry */ assert(DIRENT_NAMLEN(dirent) == (unsigned int) namelen); if (strncmp(dirent->d_name, name, namelen) == 0) { *found = 1; *icb_loc = fid->icb; break; } } free(dirent); dirhash_put(dir_node->dir_hash); return error; } static int udf_count_direntries(struct udf_node *dir_node, int count_dotdot, uint32_t *dir_entries) { struct fileid_desc *fid; struct dirent dirent; uint64_t pos; uint32_t lb_size; int eof; int error; if (!dir_node) return EINVAL; lb_size = dir_node->udf_log_vol->lb_size; /* count all directory entries with optional the dotdot too */ /* only defined in directories XXX DT_COMP also possible XXX */ if ((dir_node->stat.st_mode & S_IFDIR) == 0) return ENOTDIR; /* get space to read fid in */ fid = malloc(lb_size); if (!fid) return ENOMEM; /* start directory reading */ *dir_entries = 0; pos = 0; eof = (pos == (uint64_t) dir_node->stat.st_size); while (!eof) { /* read in FIDs */ error = udf_read_fid_stream(dir_node, &pos, fid, &dirent); if (error) { printf("Error while counting directory entries : %s\n", strerror(error)); free(fid); return error; } /* process this FID/dirent */ if ((fid->file_char & UDF_FILE_CHAR_DEL) == 0) { if (fid->file_char & UDF_FILE_CHAR_PAR) { if (count_dotdot) *dir_entries = *dir_entries + 1; } else { *dir_entries = *dir_entries + 1; } } /* pos is automatically advanced */ eof = (pos == (uint64_t) dir_node->stat.st_size); } /* end of directory */ free(fid); return 0; } static int udf_writeout_fid_info(struct udf_node *dir_node, struct fileid_desc *fid, uint64_t offset, uint16_t fid_len) { struct uio uio; struct iovec iovec; int flags; bzero(&uio, sizeof(struct uio)); uio.uio_rw = UIO_READ; /* read from this space */ uio.uio_iovcnt = 1; uio.uio_iov = &iovec; iovec.iov_base = fid; iovec.iov_len = fid_len; uio.uio_offset = offset; uio.uio_resid = fid_len; flags = UDF_C_FIDS; return udf_write_file_part_uio(dir_node, "file id.", flags, &uio); } /* search for a space to record the fid in, not checking if it is allready in it ! */ /* ALERT: not to be used to update a fid ... use writeout_fid_info for that */ /* ONLY used by udf_create_directory_entry */ static int udf_insert_fid_info(struct udf_node *dir_node, struct udf_node *udf_node, struct fileid_desc *i_fid, uint16_t fidsize) { struct dirhash *dirh; struct dirhash_entry *dirh_ep; struct fileid_desc *fid; struct dirent dirent; uint64_t dir_size, fid_pos, chosen_fid_pos, end_fid_pos; uint32_t this_fidsize, chosen_size; uint32_t lb_size, lb_rest; uint32_t size_diff, chosen_size_diff; char *fid_name; int descr_ver, hit, error; udf_node = udf_node; /* passed only for printing diagnostic info if required */ if (!dir_node) return EINVAL; /* only defined in directories XXX DT_COMP also possible XXX */ if ((dir_node->stat.st_mode & S_IFDIR) == 0) return ENOTDIR; /* needs to be 4 bytes aligned to be legal! if not, something is seriously wrong so abort */ assert((fidsize & 3) == 0); /* get our dirhash and make sure its read in */ dirhash_get(&dir_node->dir_hash); error = dirhash_fill(dir_node); if (error) { dirhash_put(dir_node->dir_hash); return error; } dirh = dir_node->dir_hash; /* get info */ lb_size = dir_node->udf_log_vol->lb_size; dir_size = dir_node->stat.st_size; descr_ver = udf_rw16(dir_node->udf_log_vol->log_vol->tag.descriptor_ver); /* get space to read fid in */ fid = malloc(lb_size); if (!fid) return ENOMEM; /* find position that will fit the FID */ chosen_fid_pos = dir_size; chosen_size = 0; chosen_size_diff = UINT_MAX; /* shut up gcc */ #ifndef NO_DIRENT_NAMLEN dirent.d_namlen = 0; #endif /* search our dirhash hits */ error = 0; dirh_ep = NULL; for (;;) { hit = dirhash_lookup_freed(dirh, fidsize, &dirh_ep); /* if no hit, abort the search */ if (!hit) break; /* check this hit for size */ this_fidsize = dirh_ep->entry_size; /* check this hit */ fid_pos = dirh_ep->offset; end_fid_pos = fid_pos + this_fidsize; size_diff = this_fidsize - fidsize; lb_rest = lb_size - (end_fid_pos % lb_size); /* select if not splitting the tag and its smaller */ if ((size_diff <= chosen_size_diff) && (lb_rest >= sizeof(struct desc_tag))) { /* UDF 2.3.4.2+3 specifies rules for iu size */ if ((size_diff == 0) || (size_diff >= 32)) { chosen_fid_pos = fid_pos; chosen_size = this_fidsize; chosen_size_diff = size_diff; } } } /* extend directory if no other candidate found */ if (chosen_size == 0) { chosen_fid_pos = dir_size; chosen_size = fidsize; /* special case UDF 2.00+ 2.3.4.4, no splitting up fid tag */ if (dir_node->addr_type == UDF_ICB_INTERN_ALLOC) { /* pre-grow directory to see if we're to switch */ // udf_grow_node(dir_node, dir_size + chosen_size); error = udf_truncate_node(dir_node, chosen_fid_pos + chosen_size); assert(!error); } /* make sure the next fid desc_tag won't be splitted */ if (dir_node->addr_type != UDF_ICB_INTERN_ALLOC) { end_fid_pos = chosen_fid_pos + chosen_size; lb_rest = lb_size - (end_fid_pos % lb_size); /* pad with implementation use regid if needed */ if (lb_rest < sizeof(struct desc_tag)) chosen_size += 32; } } chosen_size_diff = chosen_size - fidsize; /* populate the FID */ memset(fid, 0, lb_size); udf_init_desc_tag(&fid->tag, TAGID_FID, descr_ver, 1); /* tag serial number */ fid->file_version_num = i_fid->file_version_num; fid->file_char = i_fid->file_char; fid->icb = i_fid->icb; fid->l_iu = udf_rw16(0); if (chosen_size > fidsize) { /* insert implementation-use regid to space it correctly */ fid->l_iu = udf_rw16(chosen_size_diff); /* set implementation use */ udf_set_imp_id((struct regid *) fid->data); } /* copy name */ fid->l_fi = i_fid->l_fi; memcpy(fid->data + udf_rw16(fid->l_iu), i_fid->data, fid->l_fi); fid->tag.desc_crc_len = chosen_size - UDF_DESC_TAG_LENGTH; /* writeout modified piece */ udf_validate_tag_and_crc_sums((union dscrptr *) fid); error = udf_writeout_fid_info(dir_node, fid, chosen_fid_pos, chosen_size); assert(!error); /* append to the dirhash */ fid_name = (char *) fid->data + udf_rw16(fid->l_iu); dirent.d_fileno = udf_rw32(fid->icb.impl.im_used.unique_id); /* only 32 bits salvageable */ #if !defined(__DragonFly__) dirent.d_reclen = sizeof(struct dirent); #endif dirent.d_type = DT_UNKNOWN; udf_to_unix_name(dirent.d_name, fid_name, fid->l_fi, &dir_node->udf_log_vol->log_vol->desc_charset); #ifndef NO_DIRENT_NAMLEN dirent.d_namlen = strlen(dirent.d_name); #endif if (fid->file_char & UDF_FILE_CHAR_DIR) dirent.d_type = DT_DIR; if (fid->file_char & UDF_FILE_CHAR_PAR) strcpy(dirent.d_name, ".."); dirhash_enter(dirh, &dirent, chosen_fid_pos, udf_fidsize(fid), 1); free(fid); dirhash_put(dir_node->dir_hash); return error; } /* create a file in the given directory with the given name and attributes using udf's file_char and udf'd filetype */ /* note * 1) that with `refering' node specified its effectively `link()' * 2) that with `refering' node specified, `filetype' is discarded as it ought to be the same as the `refering' one * * XXX this function needs to be splitted into node creation and directory * attachment; its now doing both in one go. */ int udf_create_directory_entry(struct udf_node *dir_node, char *name, int filetype, int filechar, struct udf_node *refering, struct stat *stat, struct udf_node **new_node) { struct udf_allocentry *alloc_entry; struct udf_log_vol *udf_log_vol; struct udf_node *udf_node; struct charspec osta_charspec; struct fileid_desc *fid; struct long_ad icb_loc; uint32_t lb_num, lb_size; uint16_t vpart_num, descr_ver, len; int found, error; assert(dir_node); assert(name); assert(dir_node->udf_log_vol); udf_log_vol = dir_node->udf_log_vol; lb_size = udf_log_vol->lb_size; descr_ver = udf_rw16(udf_log_vol->log_vol->tag.descriptor_ver); *new_node = NULL; /* lookup if it allready exists (sanity mainly) */ fid = malloc(lb_size); assert(fid); error = udf_lookup_name_in_dir(dir_node, name, strlen(name), &icb_loc, fid, &found); if (!error && found) { /* it existed! allready there */ free(fid); return EEXIST; } if (!refering) { /* * Get ourselves an empty node and space to record file * descriptor in. */ error = udf_init_udf_node(dir_node->mountpoint, udf_log_vol, "New direntry", &udf_node); if (error) { free(fid); return error; } udf_node->udf_filetype = filetype; udf_node->udf_filechar = filechar; udf_node->unique_id = udf_increment_unique_id(udf_log_vol); /* snif */ error = udf_allocate_udf_node_on_disc(udf_node); if (error) { assert(udf_node != dir_node); udf_dispose_udf_node(udf_node); free(fid); return error; } udf_node->stat = *stat; /* note passed creation times; do sanitise them */ #ifndef NO_STAT_BIRTHTIME if (udf_insanetimespec(&stat->st_birthtimespec)) udf_set_timespec_now(&udf_node->stat.st_birthtimespec); #endif if (udf_insanetimespec(&stat->st_ctimespec)) udf_set_timespec_now(&udf_node->stat.st_ctimespec); if (udf_insanetimespec(&stat->st_atimespec)) udf_set_timespec_now(&udf_node->stat.st_atimespec); if (udf_insanetimespec(&stat->st_mtimespec)) udf_set_timespec_now(&udf_node->stat.st_mtimespec); } else { /* refering->ignore passed stat info */ udf_node = refering; filetype = udf_node->udf_filetype; /* linking changes metadata modification */ udf_set_timespec_now(&udf_node->stat.st_ctimespec); } alloc_entry = TAILQ_FIRST(&udf_node->dscr_allocs); vpart_num = alloc_entry->vpart_num; lb_num = alloc_entry->lb_num; /* build up new directory entry */ memset(fid, 0, lb_size); udf_osta_charset(&osta_charspec); udf_init_desc_tag(&fid->tag, TAGID_FID, descr_ver, 1); /* tag serial number */ if (filechar & UDF_FILE_CHAR_PAR) { /* parent or `..' is not allowed to have a name length ... wierd but ok */ fid->l_fi = 0; } else { unix_to_udf_name((char *) fid->data, name, &fid->l_fi, &osta_charspec); } fid->file_version_num = udf_rw16(1); /* new file/dir; version starts at 1 */ fid->file_char = filechar; /* what is it */ fid->l_iu = udf_rw32(0); /* no impl. use */ fid->icb.len = udf_rw32(lb_size); /* fill in location */ fid->icb.loc.part_num = udf_rw16(vpart_num); fid->icb.loc.lb_num = udf_rw32(lb_num); /* fill in lower 32 bits of unique ID (UDF 3/3.2.2.1) in the impl use part of the FID's long_ad */ fid->icb.impl.im_used.unique_id = udf_rw32(((udf_node->unique_id << 32) >> 32)); /* calculate minimum size needed for directory entry */ len = UDF_FID_SIZE + fid->l_fi; len = (len + 3) & ~3; fid->tag.desc_crc_len = udf_rw16(len - UDF_DESC_TAG_LENGTH); error = udf_insert_fid_info(dir_node, udf_node, fid, len); free(fid); /* Ahum... easily forgotten here */ if (error) { fprintf(stderr, "UDF: fid insertion failed : %s\n", strerror(error)); if (!refering) udf_dispose_udf_node(udf_node); return error; } if (udf_node) { /* only insert file in hashlist if its not an explicit reference */ if (!refering) { udf_insert_node_in_hash(udf_node); } else { refering->link_cnt++; udf_node_mark_dirty(refering); } udf_node_mark_dirty(udf_node); } *new_node = udf_node; return error; } /* * Rename file from old_name to new_name. `present' is the file to be replaced * if found present allready. Care should be taken that the directory tree is * kept intact. To prevent this no path should be possible from the new parent * to the node to be renamed if it considers a directory and the new_parent is * not equal to the old parent. */ /* * VOP_RENAME(struct vnode *fdvp, struct vnode *vp, * struct componentname *fcnp, struct componentname *tdvp, * struct vnode *tvp, struct componentname *tcnp * ); */ int udf_rename(struct udf_node *old_parent, struct udf_node *rename_me, char *old_name, struct udf_node *new_parent, struct udf_node *present, char *new_name) { struct udf_node *new_node; int error; /* sanity */ if (!old_parent) return ENOENT; if (!new_parent) return ENOENT; if (!rename_me) return ENOENT; if (!(old_parent->stat.st_mode & S_IFDIR)) return ENOTDIR; if (!(new_parent->stat.st_mode & S_IFDIR)) return ENOTDIR; if (udf_open_logvol(old_parent->udf_log_vol)) return EROFS; if (udf_open_logvol(new_parent->udf_log_vol)) return EROFS; if ((present && (present->stat.st_mode & S_IFDIR)) || (old_parent != new_parent)) { /* cross directory moves */ fprintf(stderr, "Cross directory renaming is not implemented yet.\n"); return ENOTSUP; } /* if it was present, delete old contents; reference counting is done */ if (present) { /* TODO what about non dir, non file entries? */ if (present->stat.st_mode & S_IFDIR) { error = udf_remove_directory(new_parent, present, new_name); } else { error = udf_remove_file(new_parent, present, new_name); } if (error) return error; } /* insert new_name HARD-linked to the `rename_me' node */ error = udf_create_directory_entry(new_parent, new_name, rename_me->udf_filetype, rename_me->udf_filechar, rename_me, NULL, &new_node); if (error) return error; /* extra sanity */ if (!new_node) return ENOENT; /* 3) remove old link and mark directories dirty */ error = udf_remove_directory_entry(old_parent, rename_me, old_name); udf_node_mark_dirty(old_parent); udf_node_mark_dirty(new_parent); return error; } /* VOP_CREATE */ int udf_create_file(struct udf_node *dir_node, char *componentname, struct stat *stat, struct udf_node **new_node) { struct udf_log_vol *udf_log_vol; struct udf_node *udf_node; uint32_t lb_size; int error; if (!dir_node) return EINVAL; udf_log_vol = dir_node->udf_log_vol; if (!udf_log_vol) return EINVAL; lb_size = udf_log_vol->lb_size; if (!udf_confirm_freespace(udf_log_vol, UDF_C_NODE, lb_size)) return ENOSPC; if (udf_open_logvol(dir_node->udf_log_vol)) return EROFS; error = udf_create_directory_entry(dir_node, componentname, UDF_ICB_FILETYPE_RANDOMACCESS, 0, NULL, stat, new_node); if ((!error) && (*new_node)) { udf_node = *new_node; /* update sizes */ udf_node->stat.st_size = 0; udf_node->stat.st_blksize = dir_node->udf_log_vol->lb_size; udf_node->stat.st_blocks = 0; /* not 1? */ udf_node->udf_log_vol->num_files++; udf_node_mark_dirty(udf_node); } return error; } /* VOP_MKDIR */ int udf_create_directory(struct udf_node *dir_node, char *componentname, struct stat *stat, struct udf_node **new_node) { struct udf_log_vol *udf_log_vol; struct udf_node *udf_node, *dummy_node; uint32_t lb_size; int error; if (!dir_node) return EINVAL; udf_log_vol = dir_node->udf_log_vol; if (!udf_log_vol) return EINVAL; lb_size = udf_log_vol->lb_size; if (!udf_confirm_freespace(udf_log_vol, UDF_C_NODE, 2*lb_size)) return ENOSPC; if (udf_open_logvol(dir_node->udf_log_vol)) return EROFS; stat->st_mode |= S_IFDIR; error = udf_create_directory_entry(dir_node, componentname, UDF_ICB_FILETYPE_DIRECTORY, UDF_FILE_CHAR_DIR, NULL, stat, new_node); if ((!error) && (*new_node)) { udf_node = *new_node; /* update sizes */ udf_node->stat.st_size = 0; udf_node->stat.st_blksize = dir_node->udf_log_vol->lb_size; udf_node->stat.st_blocks = 0; /* not 1? */ udf_node->udf_log_vol->num_directories++; udf_node_mark_dirty(udf_node); /* create `..' directory entry */ error = udf_create_directory_entry(udf_node, "..", UDF_ICB_FILETYPE_DIRECTORY, UDF_FILE_CHAR_DIR | UDF_FILE_CHAR_PAR, dir_node, stat, &dummy_node); if (error) { /* use of _prim for dir counting might not go well due to aborted creation */ error = udf_remove_directory_prim(dir_node, udf_node, componentname); } } return error; } /* really deletes all space referenced to this udf node including descriptor spaces and removes it from the administration */ int udf_unlink_node(struct udf_node *udf_node) { struct udf_allocentry *alloc_entry; uint32_t lbnum, len; uint16_t vpart; int error; /* just in case its called from outside */ if (udf_open_logvol(udf_node->udf_log_vol)) return EROFS; /* unlinking changes metadata modification */ udf_set_timespec_now(&udf_node->stat.st_ctimespec); udf_node->link_cnt--; udf_node_mark_dirty(udf_node); if (udf_node->link_cnt > 0) return 0; /* trunc node */ udf_truncate_node(udf_node, (uint64_t) 0); /* get rid of file contents */ /* free descriptors from dscr_allocs queue */ TAILQ_FOREACH(alloc_entry, &udf_node->dscr_allocs, next_alloc) { vpart = alloc_entry->vpart_num; lbnum = alloc_entry->lb_num; /* flags = alloc_entry->flags; */ len = alloc_entry->len; error = udf_release_lbs(udf_node->udf_log_vol, vpart, lbnum, len); /* what if an error occures? */ assert(error == 0); } /* delete from administration */ udf_dispose_udf_node(udf_node); return 0; } /* NOTE: Dont use the EXTENT erased part; its for non sequential WORM only */ /* UDF 2.3.10.1, ECMA 4/48.14.1.1 */ /* fid->icb.impl.im_used.flags = udf_rw16(UDF_ADIMP_FLAGS_EXTENT_ERASED); */ static int udf_remove_directory_entry(struct udf_node *dir_node, struct udf_node *udf_node, char *name) { struct dirhash *dirh; struct dirhash_entry *dirh_ep; struct fileid_desc *fid; struct dirent *dirent; uint64_t diroffset; uint32_t lb_size, namelen, fidsize; int hit, found; int error; assert(dir_node); assert(udf_node); assert(udf_node->udf_log_vol); assert(name); namelen = strlen(name); if (strncmp(name, "..", 3) == 0) { printf("Asked to remove `..' parent directory identifier; not allowed!\n"); return ENOENT; } if (strncmp(name, ".", 2) == 0) { printf("Asked to remove `.' current directory identifier; not allowed!\n"); return ENOENT; } /* only lookup in directories XXX DT_COMP also possible XXX */ if ((dir_node->stat.st_mode & S_IFDIR) == 0) return ENOTDIR; /* get our dirhash and make sure its read in */ dirhash_get(&dir_node->dir_hash); error = dirhash_fill(dir_node); if (error) { dirhash_put(dir_node->dir_hash); return error; } dirh = dir_node->dir_hash; /* allocate temporary space for fid */ lb_size = udf_node->udf_log_vol->lb_size; fid = malloc(lb_size); dirent = malloc(sizeof(struct dirent)); if (!fid || !dirent) { error = ENOMEM; goto error_out; } /* search our dirhash hits */ found = 0; dirh_ep = NULL; for (;;) { hit = dirhash_lookup(dirh, name, namelen, &dirh_ep); /* if no hit, abort the search */ if (!hit) break; /* check this hit */ diroffset = dirh_ep->offset; /* transfer a new fid/dirent */ error = udf_read_fid_stream(dir_node, &diroffset, fid, dirent); if (error) break; /* see if its our entry */ assert(DIRENT_NAMLEN(dirent) == namelen); if (strncmp(dirent->d_name, name, namelen) == 0) { found = 1; break; } } if (!found) error = ENOENT; if (error) goto error_out; /* get size of fid and compensate for the read_fid_stream advance */ fidsize = udf_fidsize(fid); diroffset -= fidsize; /* mark fid as deleted */ fid->file_char |= UDF_FILE_CHAR_DEL; bzero(&fid->icb, sizeof(struct long_ad)); udf_validate_tag_and_crc_sums((union dscrptr *) fid); udf_writeout_fid_info(dir_node, fid, diroffset, fidsize); /* remove from the dirhash */ dirhash_mark_freed(dirh, dirh_ep, dirent); /* delete node and its administration if refcount indicates so */ udf_unlink_node(udf_node); error_out: if (fid) free(fid); if (dirent) free(dirent); dirhash_put(dir_node->dir_hash); return error; } /* VOP_REMOVE */ int udf_remove_file(struct udf_node *dir_node, struct udf_node *udf_node, char *componentname) { int error; if (udf_open_logvol(dir_node->udf_log_vol)) return EROFS; if (udf_node->stat.st_mode & S_IFDIR) { /* only remove files with this call */ return EISDIR; } error = udf_remove_directory_entry(dir_node, udf_node, componentname); if (!error) { dir_node->udf_log_vol->num_files--; } /* else? */ return error; } static int udf_remove_directory_prim(struct udf_node *dir_node, struct udf_node *udf_node, char *componentname) { int error; if (udf_open_logvol(dir_node->udf_log_vol)) return EROFS; /* remove the entry */ error = udf_remove_directory_entry(dir_node, udf_node, componentname); if (!error) { dir_node->link_cnt--; udf_node_mark_dirty(dir_node); dir_node->udf_log_vol->num_directories--; } else { /* whoah! something went wrong, mark the .. as present again */ printf("UDF warning: filesystem might by in compromised state\n"); assert(udf_node); udf_node->link_cnt++; } return error; } /* VOP_RMDIR */ int udf_remove_directory(struct udf_node *dir_node, struct udf_node *udf_node, char *componentname) { uint32_t num_nodes; int error; if (!(udf_node->stat.st_mode & S_IFDIR)) { /* only remove directories with this call */ return ENOTDIR; } error = udf_count_direntries(udf_node, 0, &num_nodes); if (error) return error; if (num_nodes != 0) return ENOTEMPTY; error = udf_remove_directory_prim(dir_node, udf_node, componentname); return error; } /* end of udf.c */ UDFclient.0.8.8/udf_allocentries.c010066400001470000000000000261761307041400500163610ustar reinoudwheel/* $NetBSD$ */ /* * File "udf_allocentries.c" is part of the UDFclient toolkit. * File $Id: udf_allocentries.c,v 1.13 2016/04/25 21:01:40 reinoud Exp $ $Name: $ * * Copyright (c) 2003, 2004, 2005, 2006, 2011 * Reinoud Zandijk * All rights reserved. * * The UDFclient toolkit is distributed under the Clarified Artistic Licence. * A copy of the licence is included in the distribution as * `LICENCE.clearified.artistic' and a copy of the licence can also be * requested at the GNU foundantion's website. * * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* XXX strip list to bare minimum XXX */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "uscsilib.h" /* for locals */ #include "udf.h" #include "udf_bswap.h" #include "udf_discop.h" #include "uio.h" #include /* for scsilib */ extern const char *dvname; #ifndef MAX # define MAX(a,b) ((a)>(b)?(a):(b)) # define MIN(a,b) ((a)<(b)?(a):(b)) #endif /* #define DEBUG(a) { a; } */ #define DEBUG(a) if (0) { a; } /* XXX TODO support non lb_size splits ?? TODO XXX */ /****************************************************************************************** * * Basic operations on udf_alloc_entries queues * ******************************************************************************************/ void udf_merge_allocentry_queue(struct udf_alloc_entries *queue, uint32_t lb_size) { struct udf_allocentry *alloc_entry, *next_alloc; uint64_t this_end, next_start; int merge; TAILQ_FOREACH(alloc_entry, queue, next_alloc) { do { merge = 0; /* only non busy ; prolly old cruft? */ if (alloc_entry->flags == UDF_SPACE_FREED) break; next_alloc = TAILQ_NEXT(alloc_entry, next_alloc); if (next_alloc) { if (next_alloc->flags != alloc_entry->flags) break; if (alloc_entry->flags == UDF_SPACE_ALLOCATED) { /* merge on virtual/physical lb_num base; they are automatically adjacent on offset */ if (next_alloc->vpart_num != alloc_entry->vpart_num) break; this_end = alloc_entry->lb_num * lb_size + alloc_entry->len; next_start = next_alloc->lb_num * lb_size; if (this_end != next_start) break; } /* Only merge if merge would result in a legal UDF allocation size */ if (((uint64_t) alloc_entry->len + (uint64_t) next_alloc->len) > ((uint64_t) 1<<30)-1) break; /* merge! */ alloc_entry->len = alloc_entry->len + next_alloc->len; TAILQ_REMOVE(queue, next_alloc, next_alloc); free(next_alloc); merge = 1; } } while (merge); } /* foreach */ } /* Splits up allocated pieces so that there is a break on `offset' */ int udf_cut_allocentry_queue(struct udf_alloc_entries *queue, uint32_t lb_size, uint64_t offset) { struct udf_allocentry *entry, *new_entry; uint64_t cur_offset; uint64_t total_length, extra_length, max_slot, new_length; uint64_t entry_offset; total_length = 0; TAILQ_FOREACH(entry, queue, next_alloc) { total_length += entry->len; } /* printf("Cutting up at offset %ld (lb %ld)\n", offset, offset / lb_size); */ if (offset < total_length) { /* split */ cur_offset = 0; TAILQ_FOREACH(entry, queue, next_alloc) { if ((offset >= cur_offset) && (offset < cur_offset + entry->len)) { /* overlap */ entry_offset = offset - cur_offset; entry_offset = (entry_offset / lb_size) * lb_size; assert(entry_offset % lb_size == 0); if (entry_offset == 0) return 0; /* clone the current space */ new_entry = calloc(1, sizeof(struct udf_allocentry)); if (!new_entry) return ENOMEM; memcpy(new_entry, entry, sizeof(struct udf_allocentry)); /* split! */ /* printf("split up lb %d + lb %d due to lb offset = %ld\n", entry->lb_num, entry->len / lb_size, entry_offset); */ entry->len = entry_offset; new_entry->len -= entry_offset; new_entry->lb_num += entry_offset / lb_size; TAILQ_INSERT_AFTER(queue, entry, new_entry, next_alloc); DEBUG(printf("split up due to lb offset = %d\n", (int) entry_offset)); return 0; } cur_offset += entry->len; } printf("Sanity check: i can't be here\n"); exit(1); } /* no use to do more if we're there */ if (offset == total_length) return 0; /* * Glue extra piece on the queue (auto-extending) * see if we reached our `goal'; see if we can just extent the last * allocation entry but NEVER more or equal to one block size for that * would alter semantics. */ entry = TAILQ_LAST(queue, udf_alloc_entries); if (!TAILQ_EMPTY(queue)) { extra_length = (uint64_t) lb_size*(((uint64_t) entry->len + lb_size -1) / lb_size) - entry->len; extra_length = MIN(extra_length, (offset - total_length)); /* keep semantics: only meant for extending upto blocksize */ if (extra_length < lb_size) { entry->len += extra_length; total_length += extra_length; } } max_slot = ((((uint64_t) 1<<30)-1) / lb_size) * lb_size; while (offset > total_length) { /* grow queue by adding difference as a zero unallocated space */ new_length = offset - total_length; new_length = MIN(max_slot, new_length); new_entry = calloc(1, sizeof(struct udf_allocentry)); if (!new_entry) return ENOMEM; new_entry->len = new_length; new_entry->flags = UDF_SPACE_FREE; TAILQ_INSERT_TAIL(queue, new_entry, next_alloc); total_length += new_entry->len; } /* while */ return 0; } /* Splits up allocated pieces so that there is a break on `data_offset' and on `data_offset + data_length' */ int udf_splitup_allocentry_queue(struct udf_alloc_entries *queue, uint32_t lb_size, uint64_t data_offset, uint64_t data_length, struct udf_allocentry **res_firstae, struct udf_allocentry **res_lastae) { struct udf_allocentry *entry, *prev_entry; uint64_t cur_offset, len; entry = prev_entry = NULL; #if 0 printf("Split %ld + %ld : \n", data_offset, data_length); printf("PRE SPLIT block = lb %d + lb %d (%ld bytes)\n", (int) (data_offset / lb_size), (int) (data_length / lb_size), data_length); TAILQ_FOREACH(entry, queue, next_alloc) { printf("\t(lb %08d + lb %08d[+ %d]) flag %d\n", entry->lb_num, entry->len/lb_size, entry->len % lb_size, entry->flags); } printf("END PRE\n"); #endif /* cut the string at the specified places */ (void) udf_cut_allocentry_queue(queue, lb_size, data_offset); (void) udf_cut_allocentry_queue(queue, lb_size, data_offset + data_length); #if 0 printf("POST SPLIT\n"); TAILQ_FOREACH(entry, queue, next_alloc) { printf("\t(lb %08d + lb %08d[+ %d]) flag %d\n", entry->lb_num, entry->len/lb_size, entry->len % lb_size, entry->flags); } printf("END POST\n\n"); #endif if ((res_firstae == NULL) && (res_lastae == NULL)) return 0; if (res_firstae) *res_firstae = NULL; if (res_lastae) *res_lastae = NULL; DEBUG(printf("SEARCH SPLIT block = %"PRIu64" + %"PRIu64"\n", (data_offset / lb_size), (data_length / lb_size))); /* search the element-range this splitting induced */ cur_offset = 0; entry = TAILQ_FIRST(queue); while (entry) { len = entry->len; DEBUG(printf("\t(%d + %d) flag %d\n", (int) entry->lb_num, (int) entry->len, (int) entry->flags)); if (cur_offset + len > data_offset) { if (res_firstae) *res_firstae = entry; DEBUG(printf("\t\tReturned as first\n")); break; } /* advance */ cur_offset += len; entry = TAILQ_NEXT(entry, next_alloc); } prev_entry = entry; while (entry) { len = entry->len; if (cur_offset + len > data_offset + data_length) { break; } DEBUG(printf("\t(%d + %d) flag %d\n", (int) entry->lb_num, (int) entry->len, (int) entry->flags)); /* advance */ cur_offset += len; prev_entry = entry; entry = TAILQ_NEXT(entry, next_alloc); } if (res_lastae) *res_lastae = prev_entry; DEBUG(printf("\t\tReturned as last\n\t\n")); DEBUG(printf("END POST\n\n")); if (res_firstae) assert(*res_firstae); if (res_lastae) assert(*res_lastae); return 0; } /* mark a piece with the specified `mark' with no side-effects */ /* tested OK */ int udf_mark_allocentry_queue(struct udf_alloc_entries *queue, uint32_t lb_size, uint64_t data_offset, uint64_t data_length, int mark, struct udf_allocentry **res_firstae, struct udf_allocentry **res_lastae) { struct udf_allocentry *alloc_entry, *first_alloc_entry, *last_alloc_entry; int error; DEBUG(printf("mark %d\n", mark)); /* first split up so we don't have to worry about boundaries */ error = udf_splitup_allocentry_queue(queue, lb_size, data_offset, data_length, &first_alloc_entry, &last_alloc_entry); assert(error == 0); alloc_entry = first_alloc_entry; /* inclusive last_alloc_entry */ last_alloc_entry = TAILQ_NEXT(last_alloc_entry, next_alloc); while (alloc_entry != last_alloc_entry) { DEBUG(printf("marking %d + %d into type %d\n", alloc_entry->lb_num, alloc_entry->len/lb_size, mark);) alloc_entry->flags = mark; alloc_entry = TAILQ_NEXT(alloc_entry, next_alloc); } if (res_firstae) *res_firstae = first_alloc_entry; if (res_lastae) *res_lastae = last_alloc_entry; return 0; } int udf_extent_properties(struct udf_alloc_entries *queue, uint32_t lb_size, uint64_t from, uint64_t to, int *res_all_allocated) { struct udf_allocentry *alloc_entry, *first_alloc_entry, *last_alloc_entry; int all_allocated, error; /* first split up so we don't have to worry about boundaries */ error = udf_splitup_allocentry_queue(queue, lb_size, from, to-from, &first_alloc_entry, &last_alloc_entry); assert(error == 0); /* inclusive last_alloc_entry */ alloc_entry = first_alloc_entry; last_alloc_entry = TAILQ_NEXT(last_alloc_entry, next_alloc); all_allocated = 1; while (alloc_entry != last_alloc_entry) { all_allocated = all_allocated && ((alloc_entry->flags == UDF_SPACE_ALLOCATED) || (alloc_entry->flags == UDF_SPACE_ALLOCATED_BUT_NOT_USED)); alloc_entry = TAILQ_NEXT(alloc_entry, next_alloc); } if (res_all_allocated) *res_all_allocated = all_allocated; return 0; } void udf_dump_allocentry_queue(char *msg, struct udf_alloc_entries *queue, uint32_t lb_size) { struct udf_allocentry *entry; uint64_t offset; printf("\n%s :", msg); offset = 0; TAILQ_FOREACH(entry, queue, next_alloc) { printf(" [%d : lb %08d till lb %08d] mapped on (lb %d + %d bytes) ", entry->flags, (uint32_t) (offset/lb_size), (uint32_t) (offset + entry->len)/lb_size-1, (uint32_t) (entry->lb_num/lb_size), (uint32_t) entry->len); offset += entry->len; } printf("\n"); } /* end of udf_allocentries.c */ UDFclient.0.8.8/configure010075500001470000000000004422431307041400500145750ustar reinoudwheel#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for udfclient 0.8.8. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and reinoud@NetBSD.org $0: about your system, including any error possibly output $0: before this message. Then install a modern shell, or $0: manually run the script under such a shell if you do $0: have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='udfclient' PACKAGE_TARNAME='udfclient' PACKAGE_VERSION='0.8.8' PACKAGE_STRING='udfclient 0.8.8' PACKAGE_BUGREPORT='reinoud@NetBSD.org' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS SCSI_LIB BUILD_APPS EGREP GREP CPP TIMELIB THREADLIB INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC host_os host_vendor host_cpu host build_os build_vendor build_cpu build target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures udfclient 0.8.8 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/udfclient] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of udfclient 0.8.8:";; esac cat <<\_ACEOF Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF udfclient configure 0.8.8 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## --------------------------------- ## ## Report this to reinoud@NetBSD.org ## ## --------------------------------- ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES # ---------------------------------------------------- # Tries to find if the field MEMBER exists in type AGGR, after including # INCLUDES, setting cache variable VAR accordingly. ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 $as_echo_n "checking for $2.$3... " >&6; } if eval \${$4+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int main () { static $2 ac_aggr; if (sizeof ac_aggr.$3) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$4=yes" else eval "$4=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$4 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_member cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by udfclient $as_me 0.8.8, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu #AC_CONFIG_SRCDIR([udf.c]) ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac #AC_CONFIG_HEADER([config.h]) # # Checks for programs. # ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' # # Check for OS dependent flags # case $host_os in linux*) CPPFLAGS="$CPPFLAGS -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=500 -D__USE_BSD -D_FILE_OFFSET_BITS=64" ;; darwin*) # CPPFLAGS="-D_POSIX_C_SOURCE" COPTS="$COPTS -fnested-functions" esac # # Checks for libraries. # # Rudimentary check for pthread library: if libpthread is found, then # link it in, otherwise pray it'll be in libc like FreeBSD's. # THREADLIB="$with_thread_libs" if test "$THREADLIB" = ""; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 $as_echo_n "checking for pthread_create in -lpthread... " >&6; } if ${ac_cv_lib_pthread_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_create (); int main () { return pthread_create (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread_pthread_create=yes else ac_cv_lib_pthread_pthread_create=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 $as_echo "$ac_cv_lib_pthread_pthread_create" >&6; } if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then : THREADLIB="-lpthread" fi fi if test "$THREADLIB" = ""; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc_r" >&5 $as_echo_n "checking for pthread_create in -lc_r... " >&6; } if ${ac_cv_lib_c_r_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lc_r $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_create (); int main () { return pthread_create (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_c_r_pthread_create=yes else ac_cv_lib_c_r_pthread_create=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_create" >&5 $as_echo "$ac_cv_lib_c_r_pthread_create" >&6; } if test "x$ac_cv_lib_c_r_pthread_create" = xyes; then : THREADLIB="-lc_r" fi fi if test "$THREADLIB" = ""; then THREADLIB= fi CPPFLAGS="$CPPFLAGS $with_pthread_cflags" # # Check where to find clock_gettime. In Linux it is found in librt where # in BSD its in libc. # TIMELIB="$with_time_lib" if test "$TIMELIB" = ""; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lc" >&5 $as_echo_n "checking for clock_gettime in -lc... " >&6; } if ${ac_cv_lib_c_clock_gettime+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char clock_gettime (); int main () { return clock_gettime (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_c_clock_gettime=yes else ac_cv_lib_c_clock_gettime=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_clock_gettime" >&5 $as_echo "$ac_cv_lib_c_clock_gettime" >&6; } if test "x$ac_cv_lib_c_clock_gettime" = xyes; then : TIMELIB="-lc" fi fi if test "$TIMELIB" = ""; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 $as_echo_n "checking for clock_gettime in -lrt... " >&6; } if ${ac_cv_lib_rt_clock_gettime+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char clock_gettime (); int main () { return clock_gettime (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_rt_clock_gettime=yes else ac_cv_lib_rt_clock_gettime=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 $as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : TIMELIB="-lrt" fi fi if test "$TIMELIB" = ""; then TIMELIB= fi CPPFLAGS="$CPPFLAGS $with_time_cflags" # # Checks for various header files. # ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in endian.h sys/endian.h machine/endian.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in machine/bswap.h sys/bswap.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in machine/int_fmtio.h do : ac_fn_c_check_header_mongrel "$LINENO" "machine/int_fmtio.h" "ac_cv_header_machine_int_fmtio_h" "$ac_includes_default" if test "x$ac_cv_header_machine_int_fmtio_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_MACHINE_INT_FMTIO_H 1 _ACEOF : else CPPFLAGS="$CPPFLAGS -DNO_INT_FMTIO" fi done # # Check if we have the strlcpy function allready or have to emulate it # ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy" if test "x$ac_cv_func_strlcpy" = xyes; then : : else CPPFLAGS="$CPPFLAGS -DNO_STRLCPY" fi # # Check struct stat # stat_cppflags="" ac_fn_c_check_member "$LINENO" "struct stat" "st_atimespec" "ac_cv_member_struct_stat_st_atimespec" "$ac_includes_default" if test "x$ac_cv_member_struct_stat_st_atimespec" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_ATIMESPEC 1 _ACEOF : else # Non Posix struct stat, assume Linux ac_fn_c_check_member "$LINENO" "struct stat" "st_atim" "ac_cv_member_struct_stat_st_atim" "$ac_includes_default" if test "x$ac_cv_member_struct_stat_st_atim" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_ATIM 1 _ACEOF stat_cppflags="-Dst_atimespec=st_atim -Dst_ctimespec=st_ctim -Dst_mtimespec=st_mtim" else echo "Failed to determine struct stat's timespec names" exit fi fi ac_fn_c_check_member "$LINENO" "struct stat" "st_birthtimespec" "ac_cv_member_struct_stat_st_birthtimespec" "$ac_includes_default" if test "x$ac_cv_member_struct_stat_st_birthtimespec" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC 1 _ACEOF : else stat_cppflags="$stat_cppflags -DNO_STAT_BIRTHTIME" fi CPPFLAGS="$CPPFLAGS $stat_cppflags" # # Check struct dirent # dirent_cppflags="" ac_fn_c_check_member "$LINENO" "struct dirent" "d_namlen" "ac_cv_member_struct_dirent_d_namlen" "$ac_includes_default" if test "x$ac_cv_member_struct_dirent_d_namlen" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_DIRENT_D_NAMLEN 1 _ACEOF : else dirent_cppflags="$dirent_cppflags -DNO_DIRENT_NAMLEN" fi CPPFLAGS="$CPPFLAGS $dirent_cppflags" # # Check for SCSI implementations # HAVE_SCSI="yes" SCSI_CFLAGS="$with_scsi_cflags" SCSI_LIB="$with_uscsi_lib" if test "$SCSI_CFLAGS" = ""; then HAVE_SCSI=no fi # NetBSD SCSI stack if test "$HAVE_SCSI" = "no"; then for ac_header in dev/scsipi/scsipi_all.h do : ac_fn_c_check_header_mongrel "$LINENO" "dev/scsipi/scsipi_all.h" "ac_cv_header_dev_scsipi_scsipi_all_h" "$ac_includes_default" if test "x$ac_cv_header_dev_scsipi_scsipi_all_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DEV_SCSIPI_SCSIPI_ALL_H 1 _ACEOF SCSI_CFLAGS="-DUSCSI_SCSIPI" HAVE_SCSI=yes fi done fi # Linux SCSI stack if test "$HAVE_SCSI" = "no"; then for ac_header in scsi/sg.h do : ac_fn_c_check_header_mongrel "$LINENO" "scsi/sg.h" "ac_cv_header_scsi_sg_h" "$ac_includes_default" if test "x$ac_cv_header_scsi_sg_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SCSI_SG_H 1 _ACEOF SCSI_CFLAGS="-DUSCSI_LINUX_SCSI" HAVE_SCSI=yes fi done fi # FreeBSD SCSI stack if test "$HAVE_SCSI" = "no"; then for ac_header in camlib.h do : ac_fn_c_check_header_mongrel "$LINENO" "camlib.h" "ac_cv_header_camlib_h" "$ac_includes_default" if test "x$ac_cv_header_camlib_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_CAMLIB_H 1 _ACEOF SCSI_CFLAGS="-DUSCSI_FREEBSD_CAM" HAVE_SCSI=yes SCSI_LIB="-lcam" fi done fi # OpenBSD SCSI stack if test "$HAVE_SCSI" = "no"; then for ac_header in scsi/scsi_all.h do : ac_fn_c_check_header_mongrel "$LINENO" "scsi/scsi_all.h" "ac_cv_header_scsi_scsi_all_h" "$ac_includes_default" if test "x$ac_cv_header_scsi_scsi_all_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SCSI_SCSI_ALL_H 1 _ACEOF CPPFLAGS="$CPPFLAGS -DUSCSI_SCSIPI" HAVE_SCSI=yes fi done fi # process SCSI stack presence results if test "$HAVE_SCSI" = "yes"; then CPPFLAGS="$CPPFLAGS -DSCSI $SCSI_CFLAGS" BUILD_APPS="\$(APPS) \$(SCSI_APPS)" else SCSI_LIB= BUILD_APPS="\$(APPS)" fi # # Generate output files # ac_config_files="$ac_config_files Makefile" # AC_CONFIG_FILES([config.h]) cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by udfclient $as_me 0.8.8, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ udfclient config.status 0.8.8 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi echo "" echo "Compile the project with Posix compliant make; possibly installed as bmake or pmake" UDFclient.0.8.8/config.guess010075500001470000000000001253041307041400500152020ustar reinoudwheel#! /bin/sh # # $NetBSD: config.guess,v 1.8 2004/08/14 19:13:55 schmonz Exp $ # # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003 Free Software Foundation, Inc. timestamp='2004-06-11' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit 0 ;; amd64:OpenBSD:*:*) echo x86_64-unknown-openbsd${UNAME_RELEASE} exit 0 ;; amiga:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; arc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; cats:OpenBSD:*:*) echo arm-unknown-openbsd${UNAME_RELEASE} exit 0 ;; hp300:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; luna88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mac68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; macppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvmeppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; pmax:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sgi:OpenBSD:*:*) echo mipseb-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sun3:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; wgrisc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:OpenBSD:*:*) echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit 0 ;; macppc:MirBSD:*:*) echo powerppc-unknown-mirbsd${UNAME_RELEASE} exit 0 ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit 0 ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit 0 ;; Alpha*:OpenVMS:*:*) echo alpha-hp-vms exit 0 ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit 0 ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit 0 ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit 0;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit 0 ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit 0 ;; *:OS/390:*:*) echo i370-ibm-openedition exit 0 ;; *:OS400:*:*) echo powerpc-ibm-os400 exit 0 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit 0;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit 0;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit 0 ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit 0 ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit 0 ;; DRS?6000:UNIX_SV:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7 && exit 0 ;; esac ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit 0 ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit 0 ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit 0 ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit 0 ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit 0 ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit 0 ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit 0 ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit 0 ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit 0 ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit 0 ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit 0 ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit 0 ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit 0 ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c \ && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ && exit 0 echo mips-mips-riscos${UNAME_RELEASE} exit 0 ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit 0 ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit 0 ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit 0 ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit 0 ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit 0 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit 0 ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit 0 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit 0 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit 0 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit 0 ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit 0 ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit 0 ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 echo rs6000-ibm-aix3.2.5 elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit 0 ;; *:AIX:*:[45]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:*:*) echo rs6000-ibm-aix exit 0 ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit 0 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit 0 ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit 0 ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit 0 ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit 0 ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit 0 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then # avoid double evaluation of $set_cc_for_build test -n "$CC_FOR_BUILD" || eval $set_cc_for_build if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit 0 ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit 0 ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 echo unknown-hitachi-hiuxwe2 exit 0 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit 0 ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit 0 ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit 0 ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit 0 ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit 0 ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit 0 ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit 0 ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit 0 ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit 0 ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit 0 ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit 0 ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; *:UNICOS/mp:*:*) echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit 0 ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:FreeBSD:*:*) # Determine whether the default compiler uses glibc. eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #if __GLIBC__ >= 2 LIBC=gnu #else LIBC= #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` # GNU/KFreeBSD systems have a "k" prefix to indicate we are using # FreeBSD's kernel, but not the complete OS. case ${LIBC} in gnu) kernel_only='k' ;; esac echo ${UNAME_MACHINE}-unknown-${kernel_only}freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC} exit 0 ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit 0 ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit 0 ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit 0 ;; x86:Interix*:[34]*) echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' exit 0 ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit 0 ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit 0 ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit 0 ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit 0 ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit 0 ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit 0 ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit 0 ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit 0 ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit 0 ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit 0 ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit 0 ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit 0 ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit 0 ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit 0 ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit 0 ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit 0 ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit 0 ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit 0 ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #ifdef __INTEL_COMPILER LIBC=gnu #else LIBC=gnuaout #endif #endif #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0 test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit 0 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit 0 ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit 0 ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit 0 ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit 0 ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit 0 ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit 0 ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit 0 ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit 0 ;; i*86:*:5:[78]*) case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit 0 ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit 0 ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit 0 ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit 0 ;; paragon:*:*:*) echo i860-intel-osf1 exit 0 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit 0 ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit 0 ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit 0 ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit 0 ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4.3${OS_REL} && exit 0 /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4 && exit 0 ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit 0 ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit 0 ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit 0 ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit 0 ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit 0 ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit 0 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit 0 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit 0 ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit 0 ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit 0 ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit 0 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit 0 ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit 0 ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit 0 ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit 0 ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit 0 ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit 0 ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit 0 ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Darwin:*:*) case `uname -p` in *86) UNAME_PROCESSOR=i686 ;; powerpc) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit 0 ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit 0 ;; *:QNX:*:4*) echo i386-pc-qnx exit 0 ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit 0 ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit 0 ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit 0 ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit 0 ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit 0 ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit 0 ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit 0 ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit 0 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit 0 ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit 0 ;; *:ITS:*:*) echo pdp10-unknown-its exit 0 ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit 0 ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit 0 ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0 # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit 0 ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; c34*) echo c34-convex-bsd exit 0 ;; c38*) echo c38-convex-bsd exit 0 ;; c4*) echo c4-convex-bsd exit 0 ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: UDFclient.0.8.8/config.sub010075500001470000000000000750451307041400500146530ustar reinoudwheel#! /bin/sh # # $NetBSD: config.sub,v 1.7 2004/08/14 19:14:42 schmonz Exp $ # # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003 Free Software Foundation, Inc. timestamp='2004-03-12' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit 0;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | m32r | m32rle | m68000 | m68k | m88k | mcore \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64vr | mips64vrel \ | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | msp430 \ | ns16k | ns32k \ | openrisc | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv8 | sparcv9 | sparcv9b \ | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xscale | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* \ | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64vr-* | mips64vrel-* \ | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | msp430-* \ | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ | xtensa-* \ | ymp-* \ | z8k-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; c90) basic_machine=c90-cray os=-unicos ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; cr16c) basic_machine=cr16c-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; mmix*) basic_machine=mmix-knuth os=-mmixware ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nv1) basic_machine=nv1-cray os=-unicosmp ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; or32 | or32-*) basic_machine=or32-unknown os=-coff ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: UDFclient.0.8.8/configure.ac010064400001470000000000000073211307041400500151460ustar reinoudwheel# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ(2.57) AC_INIT([udfclient], [0.8.8], [reinoud@NetBSD.org]) #AC_CONFIG_SRCDIR([udf.c]) AC_CANONICAL_HOST #AC_CONFIG_HEADER([config.h]) # # Checks for programs. # AC_PROG_CC AC_PROG_INSTALL # # Check for OS dependent flags # case $host_os in linux*) CPPFLAGS="$CPPFLAGS -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=500 -D__USE_BSD -D_FILE_OFFSET_BITS=64" ;; darwin*) # CPPFLAGS="-D_POSIX_C_SOURCE" COPTS="$COPTS -fnested-functions" esac # # Checks for libraries. # # Rudimentary check for pthread library: if libpthread is found, then # link it in, otherwise pray it'll be in libc like FreeBSD's. # THREADLIB="$with_thread_libs" if test "$THREADLIB" = ""; then AC_CHECK_LIB(pthread, pthread_create, [THREADLIB="-lpthread"]) fi if test "$THREADLIB" = ""; then AC_CHECK_LIB(c_r, pthread_create, [THREADLIB="-lc_r"]) fi if test "$THREADLIB" = ""; then THREADLIB= fi AC_SUBST(THREADLIB) CPPFLAGS="$CPPFLAGS $with_pthread_cflags" # # Check where to find clock_gettime. In Linux it is found in librt where # in BSD its in libc. # TIMELIB="$with_time_lib" if test "$TIMELIB" = ""; then AC_CHECK_LIB(c, clock_gettime, [TIMELIB="-lc"]) fi if test "$TIMELIB" = ""; then AC_CHECK_LIB(rt, clock_gettime, [TIMELIB="-lrt"]) fi if test "$TIMELIB" = ""; then TIMELIB= fi AC_SUBST(TIMELIB) CPPFLAGS="$CPPFLAGS $with_time_cflags" # # Checks for various header files. # AC_HEADER_STDC AC_CHECK_HEADERS([endian.h sys/endian.h machine/endian.h]) AC_CHECK_HEADERS([machine/bswap.h sys/bswap.h]) AC_CHECK_HEADERS([machine/int_fmtio.h], [:], [ CPPFLAGS="$CPPFLAGS -DNO_INT_FMTIO" ]) # # Check if we have the strlcpy function allready or have to emulate it # AC_CHECK_FUNC([strlcpy], [:], [ CPPFLAGS="$CPPFLAGS -DNO_STRLCPY" ]) # # Check struct stat # stat_cppflags="" AC_CHECK_MEMBERS([struct stat.st_atimespec], [:], [ # Non Posix struct stat, assume Linux AC_CHECK_MEMBERS([struct stat.st_atim], [ stat_cppflags="-Dst_atimespec=st_atim -Dst_ctimespec=st_ctim -Dst_mtimespec=st_mtim" ], [ echo "Failed to determine struct stat's timespec names" exit ]) ]) AC_CHECK_MEMBERS([struct stat.st_birthtimespec], [:], [ stat_cppflags="$stat_cppflags -DNO_STAT_BIRTHTIME" ]) CPPFLAGS="$CPPFLAGS $stat_cppflags" # # Check struct dirent # dirent_cppflags="" AC_CHECK_MEMBERS([struct dirent.d_namlen], [:], [ dirent_cppflags="$dirent_cppflags -DNO_DIRENT_NAMLEN" ]) CPPFLAGS="$CPPFLAGS $dirent_cppflags" # # Check for SCSI implementations # HAVE_SCSI="yes" SCSI_CFLAGS="$with_scsi_cflags" SCSI_LIB="$with_uscsi_lib" if test "$SCSI_CFLAGS" = ""; then HAVE_SCSI=no fi # NetBSD SCSI stack if test "$HAVE_SCSI" = "no"; then AC_CHECK_HEADERS([dev/scsipi/scsipi_all.h], [ SCSI_CFLAGS="-DUSCSI_SCSIPI" HAVE_SCSI=yes ]) fi # Linux SCSI stack if test "$HAVE_SCSI" = "no"; then AC_CHECK_HEADERS([scsi/sg.h], [ SCSI_CFLAGS="-DUSCSI_LINUX_SCSI" HAVE_SCSI=yes ]) fi # FreeBSD SCSI stack if test "$HAVE_SCSI" = "no"; then AC_CHECK_HEADERS([camlib.h], [ SCSI_CFLAGS="-DUSCSI_FREEBSD_CAM" HAVE_SCSI=yes SCSI_LIB="-lcam" ]) fi # OpenBSD SCSI stack if test "$HAVE_SCSI" = "no"; then AC_CHECK_HEADERS([scsi/scsi_all.h], [ CPPFLAGS="$CPPFLAGS -DUSCSI_SCSIPI" HAVE_SCSI=yes ]) fi # process SCSI stack presence results if test "$HAVE_SCSI" = "yes"; then CPPFLAGS="$CPPFLAGS -DSCSI $SCSI_CFLAGS" BUILD_APPS="\$(APPS) \$(SCSI_APPS)" else SCSI_LIB= BUILD_APPS="\$(APPS)" fi AC_SUBST(BUILD_APPS) AC_SUBST(SCSI_LIB) AC_SUBST(CPPFLAGS) # # Generate output files # AC_CONFIG_FILES([Makefile]) # AC_CONFIG_FILES([config.h]) AC_OUTPUT echo "" echo "Compile the project with Posix compliant make; possibly installed as bmake or pmake" UDFclient.0.8.8/cd_disect.c010066400001470000000000002217251307041400500147550ustar reinoudwheel/* $NetBSD$ */ /* * File "cd_disect.c" is part of the UDFclient toolkit. * File $Id: cd_disect.c,v 1.81 2017/04/03 08:48:51 reinoud Exp $ $Name: $ * * Copyright (c) 2003, 2004, 2005, 2006, 2011 * Reinoud Zandijk * All rights reserved. * * The UDFclient toolkit is distributed under the Clarified Artistic Licence. * A copy of the licence is included in the distribution as * `LICENCE.clearified.artistic' and a copy of the licence can also be * requested at the GNU foundantion's website. * * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include #include #include "uscsilib.h" #ifndef MAX # define MAX(a,b) ((a)>(b)?(a):(b)) # define MIN(a,b) ((a)<(b)?(a):(b)) #endif /* * from inquiry preriph. device type; used to saveguard MMC specific * operations. See spc2. */ #define DEVICE_TYPE_MMC 0x05 /* globals */ struct uscsi_dev dev; /* helper functions */ static int read_cd_hex2(int val) { int nl, nh; nl = val & 15; nh = val >> 4; if (nl >= 'A') nl -= 'A' + 10; if (nh >= 'A') nh -= 'A' + 10; return (nh*16) + nl; } static int read_cd_bcd(int val) { int nl, nh; nl = (val & 15) - '0'; nh = (val >> 4) - '0'; if ((nl < 0 || nl > 9) || (nh < 0 || nh > 9)) return val; return nh*10 + nl; } static int32_t cd_msf2lba(int h, int m, int s, int f) { return 270000*h + 4500*m + 75*s + f - 150; } /* start of discect functions */ static char *print_disc_type(int type) { switch (type) { case 0x00 : return "CD-DA or CD-ROM Disc or non CD"; case 0x10 : return "CD-I Disc"; case 0x20 : return "CD-ROM XA Disc"; case 0xFF : return "Undefined"; } return "Reserved"; } static char *print_disc_state(int state) { switch (state) { case 0 : return "empty disc"; case 1 : return "incomplete (appendable)"; case 2 : return "full (not appendable)"; case 3 : return "random writable"; } return "unknown disc state"; } static char *print_session_state(int state) { switch (state) { case 0 : return "empty"; case 1 : return "incomplete"; case 2 : return "reserved/damaged"; case 3 : return "complete/closed disc"; } return "unknown session_state"; } static char *print_mmc_profile(int profile) { static char scrap[100]; switch (profile) { case 0x00 : return "Unknown[0] profile"; case 0x01 : return "Non removeble disc"; case 0x02 : return "Removable disc"; case 0x03 : return "Magneto Optical with sector erase"; case 0x04 : return "Magneto Optical write once"; case 0x05 : return "Advance Storage Magneto Optical"; case 0x08 : return "CD-ROM"; case 0x09 : return "CD-R recordable"; case 0x0a : return "CD-RW rewritable"; case 0x10 : return "DVD-ROM"; case 0x11 : return "DVD-R sequential"; case 0x12 : return "DVD-RAM rewritable"; case 0x13 : return "DVD-RW restricted overwrite"; case 0x14 : return "DVD-RW sequential"; case 0x15 : return "DVD-R dual layer sequential"; case 0x16 : return "DVD-R dual layer jump"; case 0x17 : return "DVD-RW dual layer"; case 0x18 : return "DVD-Download disc"; case 0x1a : return "DVD+RW rewritable"; case 0x1b : return "DVD+R recordable"; case 0x20 : return "DDCD readonly (retracted)"; case 0x21 : return "DDCD-R recordable (retracted)"; case 0x22 : return "DDCD-RW rewritable (retracted)"; case 0x2a : return "DVD+RW double layer"; case 0x2b : return "DVD+R double layer"; case 0x40 : return "BD-ROM"; case 0x41 : return "BD-R Sequential Recording (SRM)"; case 0x42 : return "BD-R Random Recording (RRM)"; case 0x43 : return "BD-RE rewritable"; case 0x50 : return "HD DVD-ROM (retracted)"; case 0x51 : return "HD DVD-R (retracted)"; case 0x52 : return "HD DVD-RAM (retracted)"; case 0x53 : return "HD DVD-RW (retracted)"; case 0x58 : return "HD DVD-R dual layer (retracted)"; case 0x5a : return "HD DVD-RW dual layer (retracted)"; } sprintf(scrap, "Reserved profile 0x%02x", profile); return scrap; } static char *print_write_type(int type) { switch (type) { case 0x00 : return "Packet/Incremental"; case 0x01 : return "Track-at-once"; case 0x02 : return "Session-at-one"; case 0x03 : return "Raw"; } return "unknown write type"; } static char *print_data_block_type(int type) { static char scrap[100]; switch (type) { case 0 : return "raw data 2352 bytes"; case 1 : return "raw data 2368 bytes with P and Q channel"; case 2 : return "raw data 2352 bytes (+96) P-W subchannel appended"; case 3 : return "raw data 2352 bytes (+96) raw P-W subchannel appended"; case 8 : return "ISO mode 1 with 2048 bytes data"; case 9 : return "ISO mode 2 with 2336 bytes data, formless"; case 10 : return "ISO mode 2 with 2048 bytes data (CDROM-XA, form 1), subheader from write parameters"; case 11 : return "ISO mode 2 with 2048 bytes data (CDROM-XA, form 1), 8 bytes for subheader first"; case 12 : return "ISO mode 2 with 2324 bytes data (CDROM-XA, form 2), subheader from write parameters"; case 13 : return "ISO mode 2 with 2332 bytes data (CDROM-XA, form 1 or 2 or mixed), 8 bytes for subheader first"; } sprintf(scrap, "Unknown/reserved data block type 0x%02x", type); return scrap; } static char *print_Q_control(int cntrl) { static char scrap[100]; strcpy(scrap, ""); if ((cntrl & 12) == 4) { strcat(scrap, "data track "); if (cntrl & 1) strcat(scrap, "; incremental "); else strcat(scrap, "; uninterrupted"); } else { strcat(scrap, "audio track"); if (cntrl & 1) strcat(scrap, "; pre-emphasis of 50/15 microseconds"); else strcat(scrap, "; no pre-emphasis"); } if (cntrl & 2) strcat(scrap, "; copy prohibited"); return scrap; } static char *print_session_format(int format) { static char scrap[100]; switch (format) { case 0x00 : return "CD-DA, CD-ROM or other data discs"; case 0x10 : return "CD-I disc"; case 0x20 : return "CD-ROM XA disc or DDCD disc"; } sprintf(scrap, "Unknown/reserved session format type 0x%02x", format); return scrap; } /* why disc_type is not equal to session_format is not clear yet; its reported in the TOC/PMA/ATI format 010b */ static char *print_TOC_disc_type(int type) { static char scrap[100]; switch (type) { case 0x00 : return "CD-DA or CD Data disc with first track in Mode 1"; case 0x10 : return "CD-I disc"; case 0x20 : return "CD data XA disc with first track in Mode 2"; } sprintf(scrap, "Unknown/reserved TOC disc type type 0x%02x", type); return scrap; } static char *print_inactivity_time(int time) { static char scrap[100]; switch (time) { case 0x0 : return "Vendor specific"; case 0x1 : return "125 ms"; case 0x2 : return "250 ms"; case 0x3 : return "500 ms"; case 0x4 : return "1 sec"; case 0x5 : return "2 sec"; case 0x6 : return "4 sec"; case 0x7 : return "8 sec"; case 0x8 : return "16 sec"; case 0x9 : return "32 sec"; case 0xa : return "1 min"; case 0xb : return "2 min"; case 0xc : return "4 min"; case 0xd : return "8 min"; case 0xe : return "16 min"; case 0xf : return "32 min"; } sprintf(scrap, "Unknown/reserved inactivity timeout 0x%02x", time); return scrap; } static char *printdevice_type(int type) { static char scrap[100]; switch (type) { case 0x00 : return "Direct-access device (e.g., magnetic disk)"; case 0x01 : return "Sequential-access device (e.g., magnetic tape)"; case 0x02 : return "Printer device"; case 0x03 : return "Processor device"; case 0x04 : return "Write-once device (e.g., some optical disks)"; case 0x05 : return "CD-ROM device"; case 0x06 : return "Scanner"; case 0x07 : return "Optical memory device (e.g., some optical disks)"; case 0x08 : return "Medium changer device (e.g., jukeboxes)"; case 0x09 : return "Communications device"; case 0x0a : /* fall trough */ case 0x0b : return "Defined by ASC IT8 (Graphic arts pre-press devices)"; case 0x0c : return "Storage array controller device (e.g., RAID)"; case 0x0d : return "Enclosure services device"; case 0x0e : return "Simplified direct-access device (e.g., magnetic disk)"; case 0x0f : return "Optical card reader/writer device"; case 0x10 : return "Reserved/used for Bridging Expanders"; case 0x11 : return "Object-based Storage Device"; } sprintf(scrap, "Unknown/reserved device type 0x%02x", type); return scrap; } static char *printdevice_qualifier(int device_qualifier) { static char scrap[100]; switch (device_qualifier) { case 0x00 : return "Device server is capable and device is connected"; case 0x01 : return "Device server is capable but device is not connected"; case 0x02 : return "Reserved"; case 0x03 : return "Device server is not capable of supporting this device"; } sprintf(scrap, "Unknown/reserved device qualifier 0x%02x", device_qualifier); return scrap; } static char *printstandards_version(int version) { static char scrap[100]; switch (version) { case 0x00 : return "Does not claim conformance to any standard"; case 0x01 : return "SCSI (obsolete)"; case 0x03 : return "The device complies to ANSI INCITS 301-1997 (SPC)"; case 0x04 : return "The device complies to ANSI INCITS 351-2001 (SPC-2)"; case 0x05 : return "The device complies to ANSI INCITS T10/1416-D (SPC-3)"; } sprintf(scrap, "Unknown/Obsolete/reserved (0x%02x)", version); return scrap; } static char *print_normal_string(uint8_t *buf, int len) { static char scrap[100]; char *pos; int i; memset(scrap, 0, 100); pos = scrap; for (i = 0; i < len; i++) { if (isprint(buf[i])) *pos++ = buf[i]; } *pos = (char) 0; return scrap; } void dump_drive_identify(int *device_type) { scsicmd cmd; uint8_t buf[100]; int device_qual, rmb, version, additional_len, total_len; int i, error; /* go for SCB for a start */ *device_type = 0; bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x12; /* INQUIRY */ cmd[1] = 0; /* basic inquiry */ cmd[2] = 0; /* no page or operation code */ cmd[3] = 0; /* reserved/MSB result */ cmd[4] = 96; /* all but vendor specific */ cmd[5] = 0; /* control */ error = uscsi_command(SCSI_READCMD, &dev, cmd, 6, buf, 96, 30000, NULL); if (error) { fprintf(stderr, "Device Inquiry returned error : %s\n", strerror(error)); return; } *device_type = buf[0] & 0x1f; device_qual = buf[0] >> 16; rmb = buf[1] & 0x80; version = buf[2]; additional_len = buf[4]; total_len = additional_len + 4; printf("\n"); printf("\tDevice qualfier\t\t: %s\n", printdevice_qualifier(device_qual)); printf("\tDevice type\t\t: %s\n", printdevice_type(*device_type)); printf("\tMedia type\t\t: %s\n", rmb? "Removable": "Fixed"); printf("\tConforming to standard\t: %s\n", printstandards_version(version)); printf("\tVendor identification\t: %s\n", print_normal_string(buf + 8, 8)); printf("\tProduct identification\t: %s\n", print_normal_string(buf + 16, 16)); printf("\tProduct revision level\t: %s\n", print_normal_string(buf + 32, 4)); if (total_len < 36) goto out; printf("\tVendor specific\t\t: %s\n", print_normal_string(buf + 36, 19)); if (total_len < 58) goto out; printf("\tComplies to:\n"); for (i = 58; i <= 72; i+=2) { if (i >= total_len) break; version = buf[i+1] | (buf[i] << 8); printf("\t\t0x%04x\n", version); } out: printf("\t\n"); printf("\n"); } void dump_recorded_capacity(void) { scsicmd cmd; uint8_t buf[36]; uint32_t lba, blk_len; int error; bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x25; /* CD READ RECORDED CAPACITY */ error = uscsi_command(SCSI_READCMD, &dev, cmd, 10, buf, 8, 30000, NULL); if (error) { fprintf(stderr, "Read recorded capacity SCSI call returned : %s\n", strerror(error)); return; } lba = buf[3] | (buf[2]<<8) | (buf[1]<<16) | (buf[0]<<24); blk_len = buf[7] | (buf[6]<<8) | (buf[5]<<16) | (buf[4]<<24); printf("\nCD recorded capacity is LBA %d (%d blocks), blk_len %d\n", lba, lba/4, blk_len); } void dump_feature(uint8_t *fpos) { uint32_t feature, cnt, profile; uint32_t feature_len, feature_ver, feature_cur, feature_pers; uint32_t interface, blocking, log_blk_size, last_log_blk_addr; uint32_t datablock_types, num_link_sizes, cuesheet_len; uint32_t num_vol_levels, dcb_entry; uint32_t century, year, day, month, hour, minute, second; uint8_t *pos; feature = fpos[1] | (fpos[0] << 8); feature_ver = (fpos[2] >> 2) & 15; feature_cur = (fpos[2] & 1); feature_pers= (fpos[2] & 2); feature_len = fpos[3]; printf("\t\tFeature 0x%04x (%2d bytes) version %2d; persistent %s; currently active %s\n", feature, feature_len, feature_ver, feature_pers?"yes":" no", feature_cur?"yes":" no"); pos = &fpos[4]; switch (feature) { case 0x0000: printf("\t\tProfile list; supporting profiles\n"); for (cnt=0; cnt < feature_len; cnt += 4) { profile = pos[1] | (pos[0] << 8); printf("\t\t\t%s %s\n", pos[2] & 1 ?"ACTIVE ":"inactive", print_mmc_profile(profile)); pos += 4; } break; case 0x0001: interface = pos[3] | (pos[2] << 8) | (pos[1] << 16) | (pos[0] << 24); printf("\t\tCore features : physical interface standard commands for `"); switch (interface) { case 0 : printf("Unspecified"); break; case 1 : printf("SCSI family"); break; case 2 : printf("ATAPI"); break; case 3 : printf("IEEE 1394 - 1995"); break; case 4 : printf("IEEE 1394A"); break; case 5 : printf("Fibre channel"); break; case 6 : printf("IEEE 1394B"); break; case 7 : printf("Serial ATAPI"); break; case 8 : printf("USB (1.1 or 2.0)"); break; case 0xffff : printf("Vendor specific"); break; default : printf("", interface); break; } printf("'\n"); break; case 0x0002: printf("\t\tMorphing command set; %ssupport for ASYNC\n", (pos[0] & 1)?"":"no "); break; case 0x0003: printf("\t\tRemovable medium features\n"); if (feature_ver > 1) { printf("\t\t\tUnknown flags\n"); break; } if (pos[0] & 1) printf("\t\t\tDevice can be locked against removal\n"); printf("\t\t\tDevice will go into the %slocked state by default\n", (pos[0] & 4)?"":"un-"); printf("\t\t\tDevice %s eject the media with START/STOP with eject bit\n", (pos[0] & 8)?"can":"can't"); printf("\t\t\tLoading mechanism : "); switch (pos[0] >> 5) { case 0 : printf("Caddy"); break; case 1 : printf("Tray"); break; case 2 : printf("Pop-up"); break; case 4 : printf("Embedded changer with separate discs"); break; case 5 : printf("Embedded changes using magazines"); break; default : printf("Unknown/Reserved"); } printf("\n"); break; case 0x0004: printf("\t\tWrite protect features :"); if (pos[0] & 2) printf(" SPWP"); if (pos[0] & 1) printf(" SSWPP"); printf("\n"); break; case 0x0010: printf("\t\tRandom readable\n"); log_blk_size = pos[3] | (pos[2] << 8) | (pos[1] << 16) | (pos[0] << 24); blocking = pos[5] | (pos[4] << 8); printf("\t\t\tLogical block size %u bytes\n", log_blk_size); printf("\t\t\tDevice blocking number %d logical blocks\n", blocking); if (pos[6] & 1) printf("\t\t\tHas RW error recovery mode page\n"); break; case 0x001d: printf("\t\tMulti-read; The Logical Unit can read all CD media types; based on OSTA MultiRead\n"); break; case 0x001e: printf("\t\tAbility to read CD specific structures\n"); printf("\t\t\tDevice does %ssupport C2 error pointers\n", (pos[0] & 2)?"":"NOT "); printf("\t\t\tDevice does %ssupport CD-Text\n", (pos[0] & 1)?"":"NOT "); break; case 0x001f: printf("\t\tAbility to read DVD specific structures\n"); break; case 0x0020: printf("\t\tRandom writable\n"); last_log_blk_addr = pos[3] | (pos[2] << 8) | (pos[1] << 16) | (pos[0] << 24); log_blk_size = pos[7] | (pos[6] << 8) | (pos[5] << 16) | (pos[4] << 24); blocking = pos[9] | (pos[8] << 8); printf("\t\t\tLast writable logic block address is %u ", last_log_blk_addr); printf("(approx %u Mb)\n", (uint32_t) ((uint64_t) last_log_blk_addr*log_blk_size/(1024*1024))); printf("\t\t\tLogical block size %u bytes\n", log_blk_size); printf("\t\t\tDevice blocking number %d logical blocks\n", blocking); if (pos[10] & 1) printf("\t\t\tHas RW error recovery mode page\n"); break; case 0x0021: printf("\t\tIncremental streaming writable\n"); datablock_types = pos[1] | (pos[0] << 8); num_link_sizes = pos[3]; printf("\t\t\tDevice is %scapable of `Zero loss linking'\n", (pos[2] & 1)?"":"NOT "); printf("\t\t\tDevice supported data types (bitfield) 0x%04x\n", datablock_types); printf("\t\t\tDevice supports %d link size%s :", num_link_sizes, (num_link_sizes != 1)?"s":""); for (cnt=0; cnt < num_link_sizes; cnt++) { printf(" %d", pos[4+cnt]); } printf("\n"); break; case 0x0022: printf("\t\tCan erase/support for erasing media (OBSOLETE)\n"); break; case 0x0023: printf("\t\tSupport for formatting media\n"); break; case 0x0024: printf("\t\tHas defect handling; i.e. apparently defect-free space\n"); printf("\t\t\tDevice does %ssupport read `Space Area Information' (DVD)\n", (pos[0] & 128)?"":"NOT "); break; case 0x0025: printf("\t\tSupport for writing any unrecorded logical block on write once media in random order\n"); log_blk_size = pos[3] | (pos[2] << 8) | (pos[1] << 16) | (pos[0] << 24); blocking = pos[5] | (pos[4] << 8); printf("\t\t\tLogical block size %u bytes\n", log_blk_size); printf("\t\t\tDevice blocking number %d logical blocks\n", blocking); if (pos[6] & 1) printf("\t\t\tHas RW error recovery mode page\n"); break; case 0x0026: printf("\t\tSupport for restricted overwrite; i.e. on blocking boundaries only\n"); break; case 0x0027: printf("\t\tCD-RW CAV Write; The ability to write high speed CD-RW media\n"); /* parameters all reserved */ break; case 0x0028: printf("\t\tMRW formatted media support\n"); printf("\t\t\tDevice can read MRW formatted media\n"); printf("\t\t\tDevice %swrite/format media in MRW format\n", (pos[0] & 1)?"can ":"can't"); break; case 0x002a: printf("\t\tDVD+RW media reading/writing support\n"); if (pos[0] & 1) { printf("\t\t\tDevice can write and background format DVD+RW media\n"); if (pos[1] & 1) printf("\t\t\tDevice only supports read compatibility format stop\n"); } else { printf("\t\t\tDevice can only recognise and read DVD+RW\n"); } break; case 0x002b: printf("\t\tThe ability to read/write DVD+R recorded media\n"); if (pos[0] & 1) { printf("\t\t\tDevice can write DVD+R media\n"); } else { printf("\t\t\tDevice can only recognise and read DVD+R\n"); } break; case 0x002c: printf("\t\tSupport for rigid restricted overwrite only (CD-RW)\n"); if (pos[0] & 8) printf("\t\t\tDevice can generate direct status data during formatting\n"); if (pos[0] & 4) printf("\t\t\tDevice can read the defect status data recorded on media\n"); if (pos[0] & 2) printf("\t\t\tDevice allows writing on immediate state sessions and quick formatting\n"); printf("\t\t\tDevice does %ssupport blanking of media\n", (pos[0] & 1)?"":"NOT "); break; case 0x002d: printf("\t\tTrack at once recording support\n"); datablock_types = pos[3] | (pos[2] << 8); if (pos[0] & 64) printf("\t\t\tDevice is capable of zero-loss linking\n"); if (pos[0] & 16) printf("\t\t\tDevice is capable of writing R-W Sub code in RAW mode\n"); if (pos[0] & 8) printf("\t\t\tDevice is capable of writing R-W Sub code in Packet mode\n"); printf("\t\t\tDevice does %ssupport test writes (i.e. laser off)\n", (pos[0] & 4)?"": "NOT "); if (pos[0] & 2) printf("\t\t\tDevice supports overwriting a track using track at once\n"); if (pos[0] & 1) printf("\t\t\tDevice supports writing R-W Sub channels with user data\n"); printf("\t\t\tTrack at once data types supported (bitfield) 0x%04x\n", datablock_types); break; case 0x002e: printf("\t\tSession at once or RAW writing support; CD Mastering\n"); cuesheet_len = pos[3] | (pos[2] << 8) | (pos[1] << 16); if (pos[0] & 64) printf("\t\t\tDevice is capable of zero-loss linking\n"); printf("\t\t\tDevice can %swrite using the Session at Once write type\n", (pos[0] & 32)?"":"CANT "); if (pos[0] & 16) printf("\t\t\tDevice is capable of writing multi-session in RAW mode\n"); printf("\t\t\tDevice can %swrite using the raw write type\n", (pos[0] & 8)?"":"CANT "); printf("\t\t\tDevice does %ssupport test writes (i.e. laser off)\n", (pos[0] & 4)?"": "NOT "); if (pos[0] & 2) printf("\t\t\tDevice supports overwriting previous recorded media\n"); if (pos[0] & 1) printf("\t\t\tDevice supports writing R-W Sub channels with user data\n"); printf("\t\t\tMaximum cue sheet length %d bytes\n", cuesheet_len); break; case 0x002f: printf("\t\tDVD-R/-RW Write; The ability to write DVD specific structures\n"); if (pos[0] & 64) printf("\t\t\tDevice is capable of zero-loss linking\n"); printf("\t\t\tDevice does %ssupport test writes (i.e. laser off)\n", (pos[0] & 4)?"": "NOT "); if (pos[0] & 2) printf("\t\t\tDevice supports overwriting previous recorded media\n"); break; case 0x0030: printf("\t\tCan read DDCD user data\n"); break; case 0x0031: printf("\t\tCan write and read DDCD-R media\n"); printf("\t\t\tDevice does %ssupport test writes (i.e. laser off)\n", (pos[0] & 4)?"": "NOT "); break; case 0x0032: printf("\t\tCan write and read DDCD-RW media\n"); if (pos[0] & 2) printf("\t\t\tDevice allows writing on immediate state sessions and quick formatting\n"); printf("\t\t\tDevice does %ssupport blanking of media\n", (pos[0] & 1)?"":"NOT "); break; case 0x0033: printf("\t\tLayer jump recording feature\n"); num_link_sizes = pos[3]; printf("\t\t\tDevice supports %d link size%s :", num_link_sizes, (num_link_sizes != 1)?"s":""); for (cnt=0; cnt < num_link_sizes; cnt++) { printf(" %d", pos[4+cnt]); } printf("\n"); break; case 0x0037: printf("\t\tCD-RW Media Write Support\n"); printf("\t\t\tCan %swrite media subtype 0\n", (pos[1] & 1) ? "": "NOT "); printf("\t\t\tCan %swrite media subtype 1\n", (pos[1] & 2) ? "": "NOT "); printf("\t\t\tCan %swrite media subtype 2\n", (pos[1] & 4) ? "": "NOT "); printf("\t\t\tCan %swrite media subtype 3\n", (pos[1] & 8) ? "": "NOT "); printf("\t\t\tCan %swrite media subtype 4\n", (pos[1] & 16) ? "": "NOT "); printf("\t\t\tCan %swrite media subtype 5\n", (pos[1] & 32) ? "": "NOT "); printf("\t\t\tCan %swrite media subtype 6\n", (pos[1] & 64) ? "": "NOT "); printf("\t\t\tCan %swrite media subtype 7\n", (pos[1] & 128) ? "": "NOT "); break; case 0x0038: printf("\t\tBD-R Pseudo-Overwrite (POW) support feature\n"); break; case 0x003b: printf("\t\tDVD+R Double Layer support\n"); printf("\t\t\tDrive can read DVD+R double layer discs\n"); printf("\t\t\tDrive can %swrite DVD+R double layer discs (only valid when active)\n", (pos[1] & 1) ? "" : "NOT "); break; case 0x0040: printf("\t\tBluRay disc formats read support :\n"); printf("\t\t\tAble to read control structures and user data from the BD disc\n"); printf("\t\t\tDrive does %ssupport reporting disc BCA data\n", (pos[0] & 1)?"":"NOT "); printf("\t\t\tCan %sread BD-ROM media\n", (pos[21] & 2) ? "": "NOT "); printf("\t\t\tCan %sread BD-R media\n", (pos[13] & 2) ? "": "NOT "); printf("\t\t\tCan %sread BD-RE media version 1\n", (pos[5] & 2) ? "": "NOT "); printf("\t\t\tCan %sread BD-RE media version 2\n", (pos[5] & 4) ? "": "NOT "); if (feature_ver == 0) printf("\t\t\tOther obsolete BD version read flags not dumped\n"); break; case 0x0041: printf("\t\tBluRay disc formats write support :\n"); printf("\t\t\twrite command does %ssupport Verify-Not-Required (VNR) bit\n", (pos[0] & 1)?"":"NOT "); printf("\t\t\tCan %swrite BD-R media\n", (pos[13] & 2) ? "": "NOT "); printf("\t\t\tCan %swrite BD-RE media version 1\n", (pos[5] & 2) ? "": "NOT "); printf("\t\t\tCan %swrite BD-RE media version 2\n", (pos[5] & 4) ? "": "NOT "); break; case 0x0100: printf("\t\tPower management support\n"); break; case 0x0101: printf("\t\tS.M.A.R.T. (Self-Monitoring Analysis and Reporting Technology support)\n"); printf("\t\t\tDevice does %sprovide Fault/Failure Reporting Mode Page\n", (pos[0] & 1)?"":"NOT "); break; case 0x0102: printf("\t\tEmbedded changer feature\n"); printf("\t\t\tDevice is %scapable of switching media sides\n", (pos[0] & 16)?"":"NOT "); printf("\t\t\tDevice can %sreport disc presence after a reset of magazine change\n", (pos[0] & 4)?"":"NOT "); break; case 0x0103: printf("\t\tAbility to play audio CDs via the Logical Unit's own analog output\n"); num_vol_levels = pos[3] | (pos[2] << 8); printf("\t\t\tDevice does %ssupport the SCAN command\n", (pos[0] & 4)?"":"NOT "); printf("\t\t\tDevice %s mute separate channels\n", (pos[0] & 4)?"can":"can't"); printf("\t\t\tDevice %s set volumes for each channel separately\n", (pos[0] & 4)?"can":"can't"); printf("\t\t\tDevice has %d audio volume levels\n", num_vol_levels); break; case 0x0104: printf("\t\tAbility for the device to accept new microcode via the interface\n"); break; case 0x0105: printf("\t\tAbility to respond to all commands within a specific time\n"); break; case 0x0106: printf("\t\tAbility to perform DVD CSS/CPPM authentication and RPC\n"); printf("\t\t\tSupporting CCS version %d\n", pos[3]); break; case 0x0107: printf("\t\tAbility to read and write using Initiator requested performance parameters; realtime streaming\n"); printf("\t\t\tDevice does %shave the `read buffer capacity' command \n", (pos[0] & 16)?"":"NOT "); printf("\t\t\tDevice CD speed can %sbe set up\n", (pos[0] & 8)?"":"NOT "); printf("\t\t\tDevice write speed performance can %sbe queried\n", (pos[0] & 4)?"":"NOT "); printf("\t\t\tDevice does %shave a `set streaming' command\n", (pos[0] & 2)?"":"NOT "); printf("\t\t\tDevice does %ssupport stream recording operation\n", (pos[0] & 1)?"":"NOT "); break; case 0x0108: printf("\t\tThis device has an unique serialnumber : \""); for (cnt=0; cnt < feature_len; cnt++) { printf("%c", pos[cnt]); } printf("\"\n"); break; case 0x010a: printf("\t\tThe ability to read and/or write Disc Control Blocks (DVD only)\n"); for (cnt=0; cnt < feature_len; cnt+=4, pos+=4) { dcb_entry = pos[3] | (pos[2] << 8) | (pos[1] << 16); printf("\t\t\t\tSupported Disc Control Blocks content descriptor %d\n", dcb_entry); } printf("\n"); break; case 0x010b: printf("\t\tThe Logical Unit supports DVD CPRM authentication\n"); printf("\t\t\tSupporting CPRM version %d\n", pos[3]); break; case 0x010c: printf("\t\tFirmware Information feature :\n"); century = (pos[ 1] - '0') + 10*(pos[ 0] - '0'); year = (pos[ 3] - '0') + 10*(pos[ 2] - '0'); month = (pos[ 5] - '0') + 10*(pos[ 4] - '0'); day = (pos[ 7] - '0') + 10*(pos[ 6] - '0'); hour = (pos[ 9] - '0') + 10*(pos[ 8] - '0'); minute = (pos[11] - '0') + 10*(pos[10] - '0'); second = (pos[13] - '0') + 10*(pos[12] - '0'); printf("\t\t\tFirmware version date %d-%d-%2d%02d at time %02d:%02d:%02d\n", day, month, century, year, hour, minute, second); break; case 0x010d: printf("\t\tAACS feature :\n"); printf("\t\t\tDrive does %ssupports reading the drive certificate (RDC)\n", (pos[0] & 16)?"":"NOT "); printf("\t\t\tDrive does %ssupports reading the media key block (RMC)\n", (pos[0] & 8)?"":"NOT "); printf("\t\t\tDrive does %ssupport writing sectors with bus encription (WBE)\n", (pos[0] & 4)?"":"NOT "); printf("\t\t\tDrive does %ssupport bus encryption (BEC)\n", (pos[0] & 2)?"":"NOT "); printf("\t\t\tDrive does %ssupport generating the Binding-Nonce (%d blocks required)\n", (pos[0] & 1)?"":"NOT ", pos[1]); printf("\t\t\tDrive supports maximal %d AGID's concurrently\n", pos[2] & 15); printf("\t\t\tAACS version supported v %d\n", pos[3]); break; case 0x01ff: printf("\t\tFirmware creation date report :\n"); century = pos[ 1] | (pos[ 0] << 8); year = pos[ 3] | (pos[ 2] << 8); month = pos[ 5] | (pos[ 4] << 8); day = pos[ 7] | (pos[ 6] << 8); hour = pos[ 9] | (pos[ 8] << 8); minute = pos[11] | (pos[10] << 8); printf("\t\t\tFirmware version date %d-%d-%2d%2d at time %02d:%02d\n", day, month, century, year, hour, minute); break; default: break; } printf("\n"); } #define max_feat_tbl_len 64*1024 /* don't change */ void dump_drive_configuration(uint32_t feature_current) { scsicmd cmd; uint8_t features[max_feat_tbl_len], *fpos; uint32_t feature, last_feature, features_len, feat_tbl_len; uint32_t current_profile, pos; uint32_t feature_cur, feature_len; int error; printf("Getting drive configuration\n"); /* get total length */ last_feature = feature = 0; feat_tbl_len = 8; bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x46; /* Get configuration */ cmd[1] = 0; /* RT=0 -> all independent of current setting */ cmd[2] = (last_feature) >> 8; /* MSB feature number */ cmd[3] = (last_feature) & 0xff; /* LSB feature number */ cmd[7] = (feat_tbl_len) >> 8; /* MSB buffersize */ cmd[8] = (feat_tbl_len) & 0xff; /* LSB buffersize */ cmd[9] = 0; /* control */ error = uscsi_command(SCSI_READCMD, &dev, cmd, 10, features, feat_tbl_len, 10000, NULL); if (error) { fprintf(stderr, "While reading feature table length : %s\n", strerror(error)); return; } features_len = features[3] | (features[2]<<8) | (features[1]<<16) | (features[0]<<24); current_profile = features[7] | (features[6]<<8); printf("\tTotal features table length %d bytes\n", features_len); printf("\tCurrent profile 0x%04x `%s'\n", current_profile, print_mmc_profile(current_profile)); /* getting feature table size */ last_feature = feature = 0; do { feat_tbl_len = 8; bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x46; /* Get configuration */ cmd[1] = 0; /* RT=0 -> all independent of current setting */ cmd[2] = (last_feature) >> 8; /* MSB feature number */ cmd[3] = (last_feature) & 0xff; /* LSB feature number */ cmd[7] = (feat_tbl_len) >> 8; /* MSB buffersize */ cmd[8] = (feat_tbl_len) & 0xff; /* LSB buffersize */ cmd[9] = 0; /* control */ error = uscsi_command(SCSI_READCMD, &dev, cmd, 10, features, feat_tbl_len, 10000, NULL); if (error) { fprintf(stderr, "While reading feature table length : %s\n", strerror(error)); return; } /* actually request them */ feat_tbl_len = features[3] | (features[2]<<8) | (features[1]<<16) | (features[0]<<24); feat_tbl_len = MIN(max_feat_tbl_len, feat_tbl_len); bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x46; /* Get configuration */ cmd[1] = 0; /* RT=0 -> all independent of current setting */ cmd[2] = (last_feature) >> 8; /* MSB feature number */ cmd[3] = (last_feature) & 0xff; /* LSB feature number */ cmd[7] = (feat_tbl_len) >> 8; /* MSB buffersize */ cmd[8] = (feat_tbl_len) & 0xff; /* LSB buffersize */ cmd[9] = 0; /* control */ error = uscsi_command(SCSI_READCMD, &dev, cmd, 10, features, feat_tbl_len, 10000, NULL); if (error) { fprintf(stderr, "While reading feature table : %s\n", strerror(error)); return; } pos = 8; while (pos < feat_tbl_len) { fpos = &features[pos]; feature = fpos[1] | (fpos[0] << 8); feature_cur = (fpos[2] & 1); feature_len = fpos[3]; if (feature_cur == feature_current) dump_feature(fpos); last_feature = MAX(last_feature, feature); if ((feature_len & 3) != 0) { printf("\t\t*** drive returned bad feature length ***\n"); dump_feature(fpos); feature_len = (feature_len + 3) & ~3; } pos += 4 + feature_len; } if (feat_tbl_len >= 0xffff) printf("WARNING: requesting 2nd chunk, not tested\n"); } while (feat_tbl_len >= 0xffff); } #undef max_feat_tbl_len #define max_di_len 1000 #define max_ti_len 128 void dump_disc_information(void) { scsicmd cmd; uint8_t di[max_di_len], ti[max_ti_len]; int di_len = max_di_len, ti_len = max_ti_len; int disc_status, disc_type, last_session_state, eraseable; int num_sessions; int first_track, first_track_last_session, last_track_last_session; int data_length, is_track_number, is_session_number, is_track_mode, is_data_mode; int is_copy, is_damage, is_fixed_packet, is_packet_or_inc, is_blank, is_reserved; int nwa_valid, lra_valid; uint32_t track_start, next_writable_addr, free_blocks, packet_size, track_size, last_recorded_addr; uint32_t disc_id, disc_barcode_l, disc_barcode_h; uint64_t disc_barcode; int track, speed, pos, num_opc_tables; int printed, error; bzero(di, di_len); bzero(ti, ti_len); /* read in fixed part */ di_len = 34; bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x51; /* Read disc information */ cmd[7] = 0; /* MSB allocation length */ cmd[8] = di_len; /* LSB allocation length */ cmd[9] = 0; /* control */ error = uscsi_command(SCSI_READCMD, &dev, cmd, 10, di, di_len, 10000, NULL); if (error) { fprintf(stderr, "While reading disc information : %s\n", strerror(error)); return; } di_len = di[1] | (di[0]<<8); bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x51; /* Read disc information */ cmd[7] = di_len >> 8; /* MSB allocation length */ cmd[8] = di_len & 0xff; /* LSB allocation length */ cmd[9] = 0; /* control */ error = uscsi_command(SCSI_READCMD, &dev, cmd, 10, di, di_len, 10000, NULL); if (error) { fprintf(stderr, "While reading disc information : %s\n", strerror(error)); return; } di_len = di[1] | (di[0]<<8); printf("\tDrive returned %d bytes of data\n", di_len); disc_type = di[ 8]; disc_status = di[ 2] & 3; last_session_state = (di[ 2] >> 2) & 3; eraseable = di[ 2] & 16; first_track = di[ 3]; num_sessions = di[ 4] | (di[ 9] << 8); first_track_last_session = di[ 5] | (di[10] << 8); last_track_last_session = di[ 6] | (di[11] << 8); disc_id = di[15] | (di[14]<<8) | (di[13]<<16) | (di[12]<<24); disc_barcode_l = di[31] | (di[30]<<8) | (di[29]<<16) | (di[28]<<24); disc_barcode_h = di[27] | (di[26]<<8) | (di[25]<<16) | (di[24]<<24); disc_barcode = ((uint64_t) disc_barcode_h << 32) | disc_barcode_l; num_opc_tables = di[33]; if (di_len < 33) num_opc_tables = 0; printf("\tDisc type : %s\n", print_disc_type(disc_type)); printf("\tDisc status : %s\n", print_disc_state(disc_status)); printf("\tKind of disc : %s\n", eraseable ? "eraseable (rewritable disc)": "NOT eraseable (recordable disc)"); printf("\tFirst track number : %d\n", first_track); printf("\tNumber of sessions : %d\n", num_sessions); printf("\tDrive does %ssupport setting OPC information; num tables %d\n", num_opc_tables ? "": "NOT ", num_opc_tables); printf("\tLast session information :\n"); printf("\t\tState : %s\n", print_session_state(last_session_state)); printf("\t\tFrom track %d to track %d (including hidden)\n", first_track_last_session, last_track_last_session); printf("\tDisc is %sin 'Restricted Use Mode'\n", (di[7] & 32) ? "": "NOT "); switch (di[7] & 3) { case 0 : printf("\tBackground formatting not applicable"); break; case 1 : printf("\tDisc formatting was interrupted and not running now"); break; case 2 : printf("\tDisc is being formatted in the background"); break; case 3 : printf("\tDisc is formatted"); break; } printf("\n"); printf("\tDisc has %s valid 'Disc ID' : (0x%08"PRIx32")\n", (di[7] & 128) ? "a ": "NO", disc_id); printf("\tDisc has %s valid 'Disc Bar Code' : (0x%016"PRIx64")\n", (di[7] & 64) ? "a ": "NO", disc_barcode); printf("\tDisc has %s valid 'Disc Application code' : (0x%x)\n", (di[7] & 16) ? "a" : "NO", di[32]); printf("\tLast Session Lead-in Start Address not dumped\n"); printf("\tLast Possible Lead-out Start Address not dumped\n"); printf("\n"); if (di_len < 33) { printf("\tDrive reported no recording speeds and OPC data\n"); } else { printf("\tRecording speeds (in kB/sec) (OPC data not dumped) :\n\t\t"); pos = 34; printed = 0; while (pos < di_len) { speed = di[pos+1] | (di[pos] << 8); if (speed) { printed = 1; printf("%d", speed); if (pos < di_len-8) printf(", "); } pos += 8; } if (!printed) printf("\t\tAparently no speeds were returned"); printf("\n"); } printf("\nReading track and session information; track by track\n"); for (track = first_track; track <= last_track_last_session; track++) { ti_len = 39 + 1; /* make ATAPI happy */ bzero(cmd, SCSI_CMD_LEN); bzero(ti, ti_len); cmd[0] = 0x52; /* Read track information */ cmd[1] = 1; /* indexed on track */ cmd[4] = track >> 8; /* track number 0-0xff ? */ cmd[5] = track & 0xff; cmd[7] = ti_len >> 8; cmd[8] = ti_len & 0xff; cmd[9] = 0; error = uscsi_command(SCSI_READCMD, &dev, cmd, 10, ti, ti_len, 10000, NULL); if (error) { fprintf(stderr, "While reading track info : %s\n", strerror(error)); break; } data_length = ti[1] | (ti[0] << 8); is_track_number = ti[2] | (ti[32] << 8); is_session_number = ti[3] | (ti[33] << 8); is_track_mode = ti[5] & 15; is_copy = ti[5] & 16; is_damage = ti[5] & 32; is_data_mode = ti[6] & 15; is_fixed_packet = ti[6] & 16; is_packet_or_inc = ti[6] & 32; is_blank = ti[6] & 64; is_reserved = ti[6] & 128; is_data_mode = ti[6] & 15; nwa_valid = ti[7] & 1; lra_valid = ti[7] & 2; track_start = ti[11] | (ti[10]<<8) | (ti[ 9]<<16) | (ti[ 8]<<24); next_writable_addr = ti[15] | (ti[14]<<8) | (ti[13]<<16) | (ti[12]<<24); free_blocks = ti[19] | (ti[18]<<8) | (ti[17]<<16) | (ti[16]<<24); packet_size = ti[23] | (ti[22]<<8) | (ti[21]<<16) | (ti[20]<<24); track_size = ti[27] | (ti[26]<<8) | (ti[25]<<16) | (ti[24]<<24); last_recorded_addr = ti[31] | (ti[30]<<8) | (ti[29]<<16) | (ti[28]<<24); if (data_length <= 30) { /* 8 bits track and session numbers returned; last_recordable is invalid */ is_track_number &= 0xff; is_session_number &= 0xff; last_recorded_addr = 0; } printf("\tTrack %d of session %d\n", is_track_number, is_session_number); if (data_length < 27 && lra_valid) printf("\t\tLast recorded addres valid but not returned\n"); printf("\t\tStart at : %d\n", track_start); printf("\t\tLength : %d\n", track_size); printf("\t\tTrackmode : %s\n", print_Q_control(is_track_mode)); printf("\t\tDatamode : %s\n", (is_data_mode == 1) ? "mode 1" : "mode 2"); if (free_blocks) printf("\t\tFree blocks : %d\n", free_blocks); if (packet_size) printf("\t\tPacket size : %d\n", packet_size); if (nwa_valid) printf("\t\tNext writable : %d\n", next_writable_addr); if (lra_valid) printf("\t\tLast recorded : %d\n", last_recorded_addr); if (is_copy) printf("\t\tTrack is a copy\n"); if (is_damage) printf("\t\tTrack is damaged\n"); if (is_reserved) printf("\t\tReserved or Complete track\n"); if (is_blank) printf("\t\tBlank track\n"); if (is_packet_or_inc) printf("\t\tPacket mode track\n"); if (is_fixed_packet) printf("\t\tFixed packet sizes track\n"); if (data_length > ti_len) { printf("\t\tRest %d bytes undumed\n", data_length - ti_len); } } } #undef di_len #undef ti_len void dump_format_capabilities(void) { scsicmd cmd; uint8_t buf[512], *fcd; uint32_t num_blks, param; char *format_str, *nblks_str, *param_str; int dscr_type, list_length, format_type; int buf_len = 512, trans_len; int error; bzero(buf, buf_len); trans_len = 12; /* only fixed header first */ bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x23; /* Read format capabilities */ cmd[7] = trans_len >> 8; /* MSB allocation length */ cmd[8] = trans_len & 0xff; /* LSB allocation length */ cmd[9] = 0; /* control */ error = uscsi_command(SCSI_READCMD, &dev, cmd, 10, buf, trans_len, 10000, NULL); if (error) { fprintf(stderr, "While reading format capabilities : %s\n", strerror(error)); return; } list_length = buf[ 3]; printf("\tCurrent/max capacity followed by additional capacity, reported length of %d bytes (8/entry)\n", list_length); if (list_length % 8) { printf("\t\tWarning: violating SCSI spec, capacity list length ought to be multiple of 8\n"); printf("\t\tInterpreting as including header of 4 bytes\n"); assert(list_length % 8 == 4); list_length -= 4; } /* read in full capacity list */ trans_len = 12 + list_length; /* complete structure */ bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x23; /* Read format capabilities */ cmd[7] = trans_len >> 8; /* MSB allocation length */ cmd[8] = trans_len & 0xff; /* LSB allocation length */ cmd[9] = 0; /* control */ error = uscsi_command(SCSI_READCMD, &dev, cmd, 10, buf, trans_len, 10000, NULL); if (error) { fprintf(stderr, "While reading format capabilities : %s\n", strerror(error)); return; } fcd = buf + 4; list_length -= 4; /* seems to include the first entry */ while (list_length > 0) { num_blks = fcd[ 3] | (fcd[ 2] << 8) | (fcd[ 1] << 16) | (fcd[ 0] << 24); dscr_type = fcd[ 4] & 3; format_type = fcd[ 4] >> 2; param = fcd[ 7] | (fcd[ 6] << 8) | (fcd[ 5] << 16); format_str = nblks_str = param_str = "reserved"; switch (format_type) { case 0x00 : format_str = "full format capacity (non packet)"; nblks_str = "sectors"; param_str = "block length in bytes"; break; case 0x01 : format_str = "spare area expansion"; nblks_str = "extension in blocks"; param_str = "block length in bytes"; break; /* 0x02 - 0x03 reserved */ case 0x04 : format_str = "variable length zone'd format"; nblks_str = "zone length"; param_str = "zone number"; break; case 0x05 : format_str = "fixed length zone'd format"; nblks_str = "zone length"; param_str = "last zone number"; break; /* 0x06 - 0x0f reserved */ case 0x10 : format_str = "CD-RW/DVD-RW full packet format"; nblks_str = "adressable blocks"; param_str = "fixed packet size/ECC blocksize in sectors"; break; case 0x11 : format_str = "CD-RW/DVD-RW grow session"; nblks_str = "adressable blocks"; param_str = "fixed packet size/ECC blocksize in sectors"; break; case 0x12 : format_str = "CD-RW/DVD-RW add session"; nblks_str = "adressable blocks"; param_str = "maximum fixed packet size/ECC blocksize in sectors"; break; case 0x13 : format_str = "DVD-RW max growth of last complete session"; nblks_str = "adressable blocks"; param_str = "ECC blocksize in sectors"; break; case 0x14 : format_str = "DVD-RW max quick grow last session"; nblks_str = "adressable blocks"; param_str = "ECC blocksize in sectors"; break; case 0x15 : format_str = "DVD-RW quick full format"; nblks_str = "adressable blocks"; param_str = "ECC blocksize in sectors"; break; /* 0x16 - 0x23 reserved */ case 0x24 : format_str = "MRW format"; nblks_str = "Defect Management Area blocks"; param_str = "not used"; break; /* 0x25 reserved */ case 0x26 : format_str = "DVD+RW full format"; nblks_str = "sectors"; param_str = "not used"; break; /* 0x27 - 0x2f reserved */ case 0x30 : format_str = "BD-RE full format with spare area"; nblks_str = "blocks"; param_str = "total spare area size in clusters"; break; case 0x31 : format_str = "BD-RE full format without spare area"; nblks_str = "blocks"; param_str = "block length in bytes"; break; /* 0x32 - 0x3f reserved */ default : break; } printf("\n\tFormat type 0x%02x : %s\n", format_type, format_str); switch (dscr_type) { case 1 : printf("\t\tUnformatted media, maximum formatted capacity\n"); break; case 2 : printf("\t\tFormatted media, current formatted capacity\n"); break; case 3 : printf("\t\tNo media present or incomplete session, maximum formatted capacity\n"); break; default : printf("\t\tUnspecified descriptor type\n"); break; } printf("\t\tNumber of blocks : %12d\t(%s)\n", num_blks, nblks_str); printf("\t\tParameter : %12d\t(%s)\n", param, param_str); fcd += 8; list_length-=8; } printf("\n\tNote: last entry might be all zero due to deviation from SCSI standard\n"); } void dump_formatted_toc(void) { scsicmd cmd; uint8_t toc[10000]; uint32_t lba; int pos, toc_len, data_length; int cur_track, addr, tno, cntrl; int first_track, last_track; int min, sec, frame; int error; printf("\nFormatted TOC\n"); /* only fixed part first */ toc_len = 4; /* just TOC */ bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x43; /* READ TOC/PMA/ATIP INFO */ cmd[1] = 2; /* return HMSF */ cmd[2] = 0; /* format 0; formatted TOC */ cmd[6] = 1; /* start at first track */ cmd[7] = toc_len >> 8; cmd[8] = toc_len & 0xff; cmd[9] = 0; /* control */ error = uscsi_command(SCSI_READCMD, &dev, cmd, 10, toc, toc_len, 10000, NULL); if (error) { fprintf(stderr, "TOC reading of tracks failed : %s\n", strerror(error)); return; } first_track = read_cd_hex2(toc[2]); last_track = read_cd_hex2(toc[3]); printf("\tFirst track : %d\n", first_track); printf("\tLast track : %d\n", last_track); printf("\n"); /* complete formatted TOC */ data_length =toc[1] | (toc[0] << 8); toc_len = data_length + 2; cmd[7] = toc_len >> 8; cmd[8] = toc_len & 0xff; error = uscsi_command(SCSI_READCMD, &dev, cmd, 10, toc, toc_len, 10000, NULL); if (error) { fprintf(stderr, "TOC reading of complete formatted TOC failed : %s\n", strerror(error)); return; } /* dump formatted TOC */ data_length =toc[1] | (toc[0] << 8); pos = 4; cur_track = 0; while (pos < data_length + 2) { cntrl = (toc[pos + 1] ) & 15; addr = (toc[pos + 1] >> 4) & 15; tno = read_cd_bcd(toc[pos + 2]); /* hour = read_cd_bsd(toc[pos + 4]); symetry, though mandatory zero ? */ min = read_cd_bcd(toc[pos + 5]); sec = read_cd_bcd(toc[pos + 6]); frame = read_cd_bcd(toc[pos + 7]); lba = cd_msf2lba(0, min, sec, frame); if (tno != cur_track) { if (tno == 0xAA) { printf("\tLead-out area start"); } else { printf("\tTrack %d start\t", tno); } } cur_track = tno; printf("\t%02d:%02d:%02d (LBA %8d)\t", min, sec, frame, lba); printf(" (%s), ", print_Q_control(cntrl)); printf("Q sub-channel "); switch (addr) { case 0x0 : printf("not supplied"); break; case 0x1 : printf("encodes current position data"); break; case 0x2 : printf("encodes media catalog number"); break; case 0x3 : printf("encodes ISRC"); break; default : printf("encoding marked for reserved type (%d)", addr); } printf("\n"); pos += 8; } } void dump_raw_toc_pma_data(uint8_t *toc) { int pos, data_length; int cur_session, session, cntrl, addr, point; int min, sec, frame, pmin, psec, pframe, nwa, lba, extent; data_length = toc[1] | (toc[0] << 8); pos = 4; cur_session = 0; while (pos < data_length + 2) { session = read_cd_bcd(toc[pos+ 0]); cntrl = toc[pos+1] & 15; addr = toc[pos+1] >> 4; //tno = read_cd_bcd(toc[pos+ 2]); point = read_cd_bcd(toc[pos+ 3]); min = read_cd_bcd(toc[pos+ 4]); sec = read_cd_bcd(toc[pos+ 5]); frame = read_cd_bcd(toc[pos+ 6]); pmin = read_cd_bcd(toc[pos+ 8]); psec = read_cd_bcd(toc[pos+ 9]); pframe = read_cd_bcd(toc[pos+10]); if (session != cur_session) { if (session) printf("\tSession %d\n", session); cur_session = session; } /* if (tno == 0 && session) { */ if (1) { switch (addr) { case 1 : printf("\t\t"); switch (point) { case 0xa0 : printf("Disc type %s\n\t\t", print_TOC_disc_type(psec)); printf("First track number %d\t\t\t", pmin); break; case 0xa1 : printf("Last track number %d\t\t\t", pmin); break; case 0xa2 : lba = cd_msf2lba(0, pmin, psec, pframe); printf("Lead out %02d:%02d.%02d (LBA %8d)", pmin, psec, pframe, lba); break; default : lba = cd_msf2lba(0, pmin, psec, pframe); printf("Track start %02d:%02d.%02d (LBA %8d)", pmin, psec, pframe, lba); } if (min || sec || frame) printf("\n\t\tATIME (%02d:%02d.%02d)\t\t\t", min, sec, frame); break; case 2 : printf("\t\t"); printf("Media catalog number present\n"); break; case 3 : printf("\t\t"); printf("International Standard Recording Code (ISRC) present\n"); break; case 5 : printf("\t\t"); switch (point) { case 0xb0 : nwa = cd_msf2lba(0, min, sec, frame); extent = cd_msf2lba(0,pmin, psec, pframe); printf("Next writable at %02d:%02d.%02d (LBA %8d)", min, sec, frame, nwa); printf("\n\t\t"); printf("Lead out max at %02d:%02d.%02d (LBA %8d)", pmin, psec, pframe, extent); /* printf("\n\t\t"); */ /* printf("Disc surface used for %2d %%\t\t", (int) (100.0 * (float) nwa / (float) extent)); */ break; case 0xc0 : printf("Start first lead-in %02d:%02d.%02d (LBA %8d)", pmin, psec, pframe, cd_msf2lba(0, pmin, psec, pframe)); printf("\n\t\t"); printf("Optimum recording power %d\t\t", min); break; case 0xc1 : printf("Copy of A1 point from ATIP\t\t"); break; default : printf("\t\t", addr, cntrl, point); break; } break; default : printf("\t\t\t\t", addr, cntrl, point); break; } printf("\t ("); if ((cntrl & 12) == 4) { printf("data track "); if (cntrl & 1) printf("; incremental "); else printf("; uninterrupted"); } else { printf("audio track"); if (cntrl & 1) printf("; pre-emphasis of 50/15 microseconds"); else printf("; no pre-emphasis"); } if (cntrl & 2) printf("; copy prohibited"); printf(")\n"); } pos += 11; } } char *atip_speed(int speed) { static char scrap[100]; switch (speed) { case 0: return "Reserved"; case 1: return "2x"; case 2: return "4x"; case 3: return "8x"; case 4: return "16x"; case 5: return "32x"; case 6: return "52x(?)"; case 7: default: sprintf(scrap, "(%d)", speed); } return scrap; } void dump_atip_data(uint8_t *toc) { int pos, data_length; int writing_power, ref_speed, URU, disc_cdrw, disc_subtype, A1, A2, A3; int lowest_clv_rec, highest_clv_rec; int power_multi, target_y, rec_EW_ratio, hicap_cdr_min; int min, sec, frame, pmin, psec, pframe; data_length = toc[1] | (toc[0] << 8); pos = 4; writing_power = (toc[pos ] >> 4) & 15; ref_speed = toc[pos ] & 7; URU = toc[pos+ 1] & 64; disc_cdrw = toc[pos+ 2] & 64; disc_subtype = (toc[pos+ 2] >> 3) & 7; A1 = toc[pos+ 2] & 4; A2 = toc[pos+ 2] & 2; A3 = toc[pos+ 2] & 1; min = read_cd_bcd(toc[pos+ 4]); sec = read_cd_bcd(toc[pos+ 5]); frame = read_cd_bcd(toc[pos+ 6]); pmin = read_cd_bcd(toc[pos+ 8]); psec = read_cd_bcd(toc[pos+ 9]); pframe = read_cd_bcd(toc[pos+10]); lowest_clv_rec = (toc[pos+12] >> 4) & 7; highest_clv_rec = (toc[pos+12] ) & 15; power_multi = (toc[pos+13] >> 4) & 7; target_y = (toc[pos+13] >> 1) & 7; rec_EW_ratio = (toc[pos+14] >> 4) & 7; hicap_cdr_min = toc[pos+14] & 15; printf("\tS1 values\n"); printf("\t\tDisc type\t\t\t%s\n", disc_cdrw ? "CD-RW":"CD-R"); printf("\t\tDisc sub-type\t\t\t%d (media sensitivity/speed indicator)\n", disc_subtype); printf("\t\tIndicative Target Writing Power\t%d\n", writing_power); printf("\t\tDisc is%s in unrestricted use\n", URU ? "":" NOT"); printf("\t\tReference speed\t\t\t%s\n", atip_speed(ref_speed)); printf("\tS2 values\n"); printf("\t\tStart time of lead-in %02d:%02d.%02d (LBA %8d)\n", min, sec, frame, cd_msf2lba(0, min, sec, frame)); printf("\tS3 values\n"); if (hicap_cdr_min == 0) { printf("\t\tLast possible lead-out %02d:%02d.%02d (LBA %8d)\n", pmin, psec, pframe, cd_msf2lba(0, pmin, psec, pframe)); } else { printf("\t\tStart of hicap CD-R %02d:%02d.%02d (LBA %8d)\n", pmin, psec, pframe, cd_msf2lba(0, pmin, psec, pframe)); printf("\t\tExtra time in minutes %d (not sure if correct)\n", hicap_cdr_min); printf("\t\tResulting last lead-out %02d:%02d.%02d (LBA %8d)\n", pmin + hicap_cdr_min, psec, pframe, cd_msf2lba(0, pmin + hicap_cdr_min, psec, pframe)); } if (A1) { printf("\tA1 values\n"); printf("\t\tLowest CLV speed\t%s\n", atip_speed(lowest_clv_rec)); printf("\t\tHighest CLV speed\t%s\n", atip_speed(highest_clv_rec)); printf("\t\tPower multiplication factor\t\t\t%d\n", power_multi); printf("\t\tTarget y value of Modulation/Power function\t%d\n", target_y); printf("\t\tRecommended erase/write power ration\t\t%d\n", rec_EW_ratio); } else { printf("\tA1 values are not valid\n"); printf("\t\tLowest and highest CLV speed information not specified\n"); printf("\t\tNo power recommendations\n"); } if (A2) { printf("\tA2 values\n"); printf("\t\t0x%02x 0x%02x 0x%02x\n", toc[pos+16], toc[pos+17], toc[pos+18]); } else { printf("\tA2 values not valid\n"); } if (A3) { printf("\tA3 values\n"); printf("\t\t0x%02x 0x%02x 0x%02x\n", toc[pos+20], toc[pos+21], toc[pos+22]); } else { printf("\tA3 values not valid\n"); } if (data_length > 4+23) { printf("\tS4 values\n"); printf("\t\t0x%02x 0x%02x 0x%02x\n", toc[pos+24], toc[pos+25], toc[pos+26]); } else { printf("\tS4 values not transfered\n"); } printf("\n"); } void dump_raw_toc_pma_atip_info(void) { scsicmd cmd; uint8_t toc[10000]; int toc_len; int data_length; int first_session; int error; printf("\nRaw TOC\n"); printf("\tLba numbers are indicative only\n"); /* return only fixed part or multi-session info */ toc_len = 4; bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x43; /* READ TOC/PMA/ATIP INFO */ cmd[1] = 0; /* LBA's preferably (not relevant) */ cmd[2] = 1; /* format 1; multi-session info */ cmd[7] = (toc_len >> 8) & 0xff; cmd[8] = (toc_len ) & 0xff; cmd[9] = 0; /* control */ error = uscsi_command(SCSI_READCMD, &dev, cmd, 10, toc, toc_len, 10000, NULL); if (error) { fprintf(stderr, "TOC reading of multi-session info failed : %s\n", strerror(error)); fprintf(stderr, "\tassuming first session is sesion 1\n"); first_session = 1; } else { /* XXX or just toc[2] ? */ first_session = read_cd_hex2(toc[2]); } /* return only fixed part of raw TOC */ toc_len = 4; bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x43; /* READ TOC/PMA/ATIP INFO */ cmd[1] = 2; /* officially no LBA's are defined */ cmd[2] = 2; /* format 2; raw TOC */ cmd[6] = first_session; /* start at first session */ cmd[7] = toc_len >> 8; cmd[8] = toc_len & 0xff; cmd[9] = 0; /* control */ error = uscsi_command(SCSI_READCMD, &dev, cmd, 10, toc, toc_len, 10000, NULL); if (error) { fprintf(stderr, "TOC reading of fixed part of raw TOC failed : %s\n", strerror(error)); } else { /* read in complete raw TOC */ data_length = toc[1] | (toc[0] << 8); toc_len = data_length + 2; /* don't count length */ /* patch for ATAPI: make it even length */ if (toc_len & 1) toc_len++; cmd[7] = toc_len >> 8; cmd[8] = toc_len & 0xff; error = uscsi_command(SCSI_READCMD, &dev, cmd, 10, toc, toc_len, 10000, NULL); if (error) { fprintf(stderr, "TOC reading of complete raw TOC failed : %s\n", strerror(error)); } else { dump_raw_toc_pma_data(toc); } } printf("\nPMA\n"); printf("\tLba numbers are indicative only\n"); /* return only fixed part of PMA */ toc_len = 4; bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x43; /* READ TOC/PMA/ATIP INFO */ cmd[1] = 2; /* officially no LBA's are defined */ cmd[2] = 3; /* format 3; PMA */ cmd[6] = first_session; /* start at first session */ cmd[7] = toc_len >> 8; cmd[8] = toc_len & 0xff; cmd[9] = 0; /* control */ error = uscsi_command(SCSI_READCMD, &dev, cmd, 10, toc, toc_len, 10000, NULL); if (error) { fprintf(stderr, "Reading of fixed part of PMA failed : %s\n", strerror(error)); } else { /* read in complete PMA */ data_length =toc[1] | (toc[0] << 8); toc_len = data_length + 2; /* patch for ATAPI: make it even length */ if (toc_len & 1) toc_len++; cmd[7] = toc_len >> 8; cmd[8] = toc_len & 0xff; error = uscsi_command(SCSI_READCMD, &dev, cmd, 10, toc, toc_len, 10000, NULL); if (error) { fprintf(stderr, "Reading of complete PMA failed : %s\n", strerror(error)); } else { dump_raw_toc_pma_data(toc); } } printf("\nATIP\n"); printf("\tLba numbers are indicative only\n"); /* read in fixed part of response format 0100b */ toc_len = 4; bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x43; /* READ TOC/PMA/ATIP INFO */ cmd[1] = 2; /* officially no LBA's are defined */ cmd[2] = 4; /* format 4; ATIP */ cmd[6] = first_session; /* start at first session */ cmd[7] = toc_len >> 8; cmd[8] = toc_len & 0xff; cmd[9] = 0; /* control */ error = uscsi_command(SCSI_READCMD, &dev, cmd, 10, toc, toc_len, 10000, NULL); if (error) { fprintf(stderr, "Reading of fixed part of ATIP addition information failed : %s\n", strerror(error)); } else { /* read in complete format 0100b */ data_length =toc[1] | (toc[0] << 8); toc_len = data_length + 4; /* patch for ATAPI: make it even length */ if (toc_len & 1) toc_len++; cmd[7] = toc_len >> 8; cmd[8] = toc_len & 0xff; error = uscsi_command(SCSI_READCMD, &dev, cmd, 10, toc, toc_len, 10000, NULL); if (error) { fprintf(stderr, "Reading of complete ATIP additional information failed : %s\n", strerror(error)); } else { dump_atip_data(toc); } } } void dump_toc_pma_atip_info(void) { dump_formatted_toc(); dump_raw_toc_pma_atip_info(); } char *prchange(int val) { if (val) return "[changeable]"; return "[fixed] "; } void dump_parameter_page(uint8_t *pos, uint8_t *change) { int page_code, page_length; int write_type, track_mode, data_block_type, link_size; int testwrite, linksize_valid, zerolinking; int appl_code, session_format, packet_size, audio_pause; int multi_session, fixed_packets, copybit; uint32_t recovery_time_limit, inactiv_time_mult, S_per_MSF, F_per_MSF; uint32_t idle_timer_value, standby_timer_value, interval_timer_value; uint32_t group1_timeouts, group2_timeouts; int i, j, c, per_emcdr; page_code = pos[0] & 63; page_length = pos[1]; printf("\tGot page 0x%02x (%spersistent) : %2d bytes for ", page_code, pos[0] & 128? "":"non ", page_length); switch (page_code) { case 0x01 : printf("read/write error recovery page\n"); printf("\t\tError recovery behaviour %s %d\n", prchange(change[2]), pos[2]); printf("\t\t\tAutomatic Write Reallocation Enabled (AWRE) %s %s\n", prchange(change[2] & 128), pos[2] & 128 ? "On":"Off"); printf("\t\t\tAutomatic Read Reallocation Enabled (ARRE) %s %s\n", prchange(change[2] & 64), pos[2] & 64 ? "On":"Off"); printf("\t\tError recovery parameter %s %d\n", prchange(change[2] & 63), pos[2] & 63); printf("\t\t\tTransfer Block (TB) %s %s\n", prchange(change[2] & 32), pos[2] & 32 ? "On":"Off"); printf("\t\t\tRead Continuous (RC) %s %s\n", prchange(change[2] & 16), pos[2] & 16 ? "On":"Off"); printf("\t\t\t %s %s\n", prchange(change[2] & 8), pos[2] & 8 ? "On":"Off"); printf("\t\t\tPost Error (PER) %s %s\n", prchange(change[2] & 4), pos[2] & 4 ? "On":"Off"); printf("\t\t\tDisable Transfer on Error (DTE) %s %s\n", prchange(change[2] & 2), pos[2] & 2 ? "On":"Off"); printf("\t\t\tDisable Correction (DCR) %s %s\n", prchange(change[2] & 1), pos[2] & 1 ? "On":"Off"); printf("\t\tEnhanced Media Certification and Defect Reporting %s %d\n", prchange(change[7] & 3), pos[7] & 3); per_emcdr = (pos[2] & 4) + (pos[7] & 3); if (per_emcdr == 0) printf("\t\t\tNo certification of medium on read operations and it will not report recovered errors\n"); if (per_emcdr >=1) printf("\t\t\tCertification of medium on read and on verify operation enabled; "); if (per_emcdr == 1) printf("shall not report recovered error\n"); if (per_emcdr == 2) printf("shall report recovered error or unrecovered error on verify operation.\n"); if (per_emcdr == 3) printf("shall report recovered error or unrecovered error on read operation and verify operation\n"); if (per_emcdr == 4) printf("shall report recovered error if higher lever error correction is used\n"); if (per_emcdr >= 5) printf("shall report recovered error as RECOVERED ERROR/RECOVERED DATA - RECOMMEND REASSIGNMENT\n"); printf("\t\tRead retry count %s %d\n", prchange(change[3]), pos[3]); printf("\t\tWrite retry count %s %d\n", prchange(change[8]), pos[8]); recovery_time_limit = pos[11] + (pos[10] << 8); printf("\t\tRecovery time limit %s %d\n", prchange(change[11]), recovery_time_limit); printf("\n"); break; case 0x03 : printf("MRW mode page\n"); printf("\t\t`%s' LBA space selected\n", pos[3] & 1 ? "General Application Area" : "Defect Managed Area"); printf("\n"); break; case 0x05 : printf("write parameter page\n"); write_type = pos[2] & 15; track_mode = pos[3] & 15; data_block_type = pos[4] & 15; testwrite = pos[2] & 16; linksize_valid = pos[2] & 32; zerolinking = pos[2] & 64; multi_session = pos[3] >> 6; fixed_packets = pos[3] & 32; copybit = pos[3] & 16; link_size = pos[5]; appl_code = pos[7] & 63; session_format = pos[8]; packet_size = pos[13] + (pos[12] << 8) + (pos[11] << 16) + (pos[10] << 24); audio_pause = pos[15] + (pos[14] << 8); printf("\t\tWrite type %s %s\n", prchange(change[2] & 15), print_write_type(write_type)); printf("\t\tTrack mode %s %d (mode 1 Q subchannel control nibble)\n", prchange(change[3] & 15), track_mode); printf("\t\tData block type %s %s\n", prchange(change[4] & 15), print_data_block_type(data_block_type)); printf("\t\tTestwriting %s %s\n", prchange(change[2] & 16), testwrite ? "On":"Off"); printf("\t\tLinksize %s %d sectors (%s)\n", prchange(change[5]), link_size, linksize_valid ? "valid": "not valid (7)"); printf("\t\tZerolinking support %s %s\n", prchange(change[2] & 64), zerolinking ? "On":"Off"); printf("\t\tApplication code %s %d\n", prchange(change[7] & 63), appl_code); printf("\t\tSession format %s %s\n", prchange(change[8]), print_session_format(session_format)); printf("\t\tUsing fixed packets %s %s\n", prchange(change[3] & 32), fixed_packets ? "On":"Off"); printf("\t\tCopybit %s %s\n", prchange(change[3] & 16), copybit ? "On":"Off"); printf("\t\tMulti session field %s %d\n", prchange(change[3] >> 6), multi_session); printf("\t\tPacket size %s %d\n", prchange(change[13]), packet_size); printf("\t\tAudio pause length %s %d\n", prchange(change[15]), audio_pause); printf("\t\tMedia catalog number %s 0x", prchange(change[31])); for (i = 31; i >= 16; i--) printf("%02x", pos[i]); printf("\n"); printf("\t\tInitiational standard recording code %s 0x", prchange(change[47])); for (i = 47; i >= 32; i--) printf("%02x", pos[i]); printf("\n"); printf("\t\tSubheader byte 0 %s 0x%02x\n", prchange(change[48]), pos[48]); printf("\t\tSubheader byte 1 %s 0x%02x\n", prchange(change[49]), pos[49]); printf("\t\tSubheader byte 2 %s 0x%02x\n", prchange(change[50]), pos[50]); printf("\t\tSubheader byte 3 %s 0x%02x\n", prchange(change[51]), pos[51]); printf("\n"); break; case 0x07 : printf("verify error recovery mode page\n"); printf("\t\tNot dumped yet. (And not permitted for MM LUs)\n"); printf("\n"); break; case 0x08 : printf("caching mode page\n"); printf("\t\tWrite cache %s %s\n", prchange(change[2] & 4), pos[2] & 4 ? "enabled" : "disabled"); printf("\t\tRead cache %s %s\n", prchange(change[2] & 1), pos[2] & 1 ? "disabled" : "enabled"); printf("\n"); break; case 0x0b : printf("media types supported page\n"); printf("\t\tNot dumped yet. (And not permitted for MM LUs)\n"); printf("\n"); break; case 0x0d : printf("cd device parameters page\n"); inactiv_time_mult = pos[3] & 15; S_per_MSF = pos[5] + (pos[4] << 8); F_per_MSF = pos[7] + (pos[6] << 8); printf("\t\tHold track inactivity time %s value %d (%s)\n", prchange(change[3] & 15), inactiv_time_mult, print_inactivity_time(inactiv_time_mult)); printf("\t\tSeconds per MSF %s %d\n", prchange(change[5]), S_per_MSF); printf("\t\tFrames per MSF %s %d\n", prchange(change[7]), F_per_MSF); printf("\n"); break; case 0x0e : printf("cd audio control page\n"); printf("\t\tStop on track crossing %s %s\n", prchange(change[ 2] & 2 ), pos[2] & 2 ? "On":"Off"); printf("\t\tCDDA output port 0 channel %s %d\n", prchange(change[ 8] & 31), pos[ 8] & 31); printf("\t\tOutput port 0 volume %s %d\n", prchange(change[ 9] ), pos[ 9]); printf("\t\tCDDA output port 1 channel %s %d\n", prchange(change[10] & 31), pos[10] & 31); printf("\t\tOutput port 1 volume %s %d\n", prchange(change[11] ), pos[11]); printf("\t\tCDDA output port 2 channel %s %d\n", prchange(change[12] & 31), pos[12] & 31); printf("\t\tOutput port 2 volume %s %d\n", prchange(change[13] ), pos[13]); printf("\t\tCDDA output port 3 channel %s %d\n", prchange(change[14] & 31), pos[14] & 31); printf("\t\tOutput port 3 volume %s %d\n", prchange(change[15] ), pos[15]); printf("\n"); break; case 0x1a : printf("power condition page\n"); idle_timer_value = pos[ 7] + (pos[ 6] << 8) + (pos[ 5] << 16) + (pos[ 4] << 24); standby_timer_value = pos[11] + (pos[10] << 8) + (pos[ 9] << 16) + (pos[ 8] << 24); printf("\t\tIdle timer activate %s %s\n", prchange(change[3] & 2 ), pos[3] & 2 ? "On":"Off"); printf("\t\tStandby timer active %s %s\n", prchange(change[3] & 1 ), pos[3] & 1 ? "On":"Off"); printf("\t\tIdle timer start value %s %d * 100ms\n", prchange(change[ 7] & 1 ), idle_timer_value); printf("\t\tStandby timer start value %s %d * 100ms\n", prchange(change[11] & 1 ), standby_timer_value); printf("\n"); break; case 0x1c : printf("informational exceptions control page (not checked yet)\n"); interval_timer_value = pos[ 7] + (pos[ 6] << 8) + (pos[ 5] << 16) + (pos[ 4] << 24); printf("\t\tLogging %s %s\n", prchange(pos[2] & 1), pos[2] & 1 ? "standard" : "vendor specific"); printf("\t\tTest device failure notification generation %s %s\n", prchange(pos[2] & 4), pos[2] & 4 ? "On" : "Off"); printf("\t\tInterval timer if enabled %s %d * 100ms (?)\n", prchange(pos[7] & 1), interval_timer_value); printf("\t\tRest undumped\n"); printf("\n"); break; case 0x1d : printf("timeout and protect page\n"); group1_timeouts = pos[7] + (pos[6] << 8); group2_timeouts = pos[9] + (pos[8] << 8); printf("\t\tTimeouts commands enabled %s %s\n", prchange(change[4] & 4), pos[4] & 4 ? "On":"Off"); printf("\t\tDisable device till powerd. %s %s\n", prchange(change[4] & 2), pos[4] & 2 ? "On":"Off"); printf("\t\tSoftware write protect %s %s\n", prchange(change[4] & 1), pos[4] & 1 ? "On":"Off"); if (page_length >= 8) printf("\t\tGroup 1 minimum time outs %s %d\n", prchange(change[7]), group1_timeouts); if (page_length >= 10) printf("\t\tGroup 2 minimum time outs %s %d\n", prchange(change[9]), group2_timeouts); printf("\n"); break; case 0x2a : printf("CD/DVD capabilities and mechanical status page\n"); printf("\t\tNot dumped yet\n"); printf("\n"); break; default : /* dump bytes in hex:char notation */ printf("Reserved/vendor specific\n"); printf("\t\t "); for (j = 0; j < 16; j++) { printf("%02x ", j); } printf(" ASCII\n"); for (i = 2; i < page_length+2; i+= 16) { printf("\t\t%02x ", i-2); for (j = 0; j < 16; j++) { if (i+j < page_length+2) { printf("%02x ", pos[i+j]); } else { printf(" "); } } printf(": "); for (j = 0; j < 16; j++) { if (i+j < page_length+2) { c = pos[i+j]; if (c < 32 || c == 127) c = '.'; printf("%c", c); } else { printf(" "); } } printf("\n"); } printf("\n"); break; } } #define max_blk_len 60000 void dump_parameter_pages(void) { scsicmd cmd; int blk_len, val_length, changeable_length; uint8_t val[max_blk_len], changeable[max_blk_len], zeros[256]; int voff, choff, vpage_code, vpage_length, chpage_code, chpage_length; int error; bzero(val, max_blk_len); bzero(changeable, max_blk_len); bzero(zeros, 256); /* read the block size */ blk_len = 8; bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x5A; /* MODE SENSE (10) */ cmd[1] = 0; /* allow multiple blocks */ cmd[2] = 0x3F; /* return all current values */ cmd[7] = blk_len >> 8; /* MSB block length */ cmd[8] = blk_len & 0xff; /* LSB block length */ cmd[9] = 0; /* control */ error = uscsi_command(SCSI_READCMD, &dev, cmd, 10, val, blk_len, 10000, NULL); if (error) { fprintf(stderr, "While reading all parameter pages : %s\n", strerror(error)); return; } val_length = val[1] | (val[0] << 8); printf("\tSCSI mode sense for all pages returned %d bytes of data\n", val_length); /* read the mode sense block */ blk_len = val_length; cmd[7] = blk_len >> 8; /* MSB block length */ cmd[8] = blk_len & 0xff; /* LSB block length */ error = uscsi_command(SCSI_READCMD, &dev, cmd, 10, val, blk_len, 10000, NULL); if (error) { fprintf(stderr, "While reading all parameter pages : %s\n", strerror(error)); return; } cmd[2] = 64 | 0x3F; /* get all changeable values */ error = uscsi_command(SCSI_READCMD, &dev, cmd, 10, changeable, blk_len, 10000, NULL); if (error) { fprintf(stderr, "While reading all changeable parameter pages : %s\n", strerror(error)); } changeable_length = changeable[1] | (changeable[0] << 8); printf("\tSCSI mode sense changeable parameters list returned %d bytes of data\n", changeable_length); printf("\n"); /* read the mode sense block and process page by page */ voff = 8; while (voff < val_length) { vpage_code = val[voff ] & 63; vpage_length = val[voff + 1]; if (vpage_code) { choff = 8; chpage_code = -1; while (choff < changeable_length) { chpage_code = changeable[choff ] & 63; chpage_length = changeable[choff + 1]; if (chpage_code == vpage_code) break; choff += chpage_length + 2; } if (chpage_code == vpage_code) { dump_parameter_page(val + voff, changeable + choff); } else { printf("\tWarning: no matching changeable bits page was found\n"); dump_parameter_page(val + voff, zeros); } } voff += vpage_length + 2; } } #undef max_blk_len int main(int argc, char **argv) { scsicmd cmd; uint8_t buf[36]; struct uscsi_addr saddr; int drive_type; int error; bzero(&dev, sizeof(dev)); if (argc != 2) { printf("Usage : %s devicename\n", argv[0]); return 1; } /* Open the device */ dev.dev_name = strdup(argv[1]); printf("Opening device %s\n", dev.dev_name); if (uscsi_open(&dev) != 0) { exit(1); } error = uscsi_check_for_scsi(&dev); if (error) { fprintf(stderr, "sorry, not a SCSI device : %s\n", strerror(error)); exit(1); } error = uscsi_identify(&dev, &saddr); if (error) { fprintf(stderr, "SCSI identify returned : %s\n", strerror(error)); exit(1); } printf("\n\nDevice attachment identifies itself as : "); switch (saddr.type) { case USCSI_TYPE_SCSI : printf("SCSI busnum = %d, target = %d, lun = %d\n", saddr.addr.scsi.scbus, saddr.addr.scsi.target, saddr.addr.scsi.lun); break; case USCSI_TYPE_ATAPI : printf("ATAPI busnum = %d, drive = %d\n", saddr.addr.atapi.atbus, saddr.addr.atapi.drive); break; case USCSI_TYPE_UNKNOWN : printf("Unknown attachment\n"); } printf("\n\nTest unit ready\n"); bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0; /* test unit ready */ error = uscsi_command(SCSI_READCMD, &dev, cmd, 6, buf, 0, 10000, NULL); if (error) perror("SCSI test unit ready returned : "); printf("Device identifies itself as : "); dump_drive_identify(&drive_type); printf("\n\nCURRENT features\n"); dump_drive_configuration(1); printf("\n\nCAPAPLE features\n"); dump_drive_configuration(0); printf("\n\nRead recorded capacity\n"); dump_recorded_capacity(); if (drive_type == DEVICE_TYPE_MMC) { printf("\n\nDisc information\n"); dump_disc_information(); } printf("\n\nFormat capabilities\n"); dump_format_capabilities(); if (drive_type == DEVICE_TYPE_MMC) { printf("\n\nReading TOC/PMA/ATIP\n"); dump_toc_pma_atip_info(); } if (drive_type == DEVICE_TYPE_MMC) { /* normally support mode sense 10 */ printf("\n\nReading SCSI 'mode sense' parameter pages\n"); dump_parameter_pages(); } else { printf("\n\nnot an MMC class, `mode sense' 10 parameters might fail\n"); dump_parameter_pages(); } uscsi_close(&dev); return 0; } UDFclient.0.8.8/install-sh010075500001470000000000000127361307041400500146720ustar reinoudwheel#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 UDFclient.0.8.8/osta.c010064400001470000000000000341501307041400500137720ustar reinoudwheel/* $NetBSD$ */ /* * Various routines from the OSTA 2.01 specs. Copyrights are included with * each code segment. Slight whitespace modifications have been made for * formatting purposes. Typos/bugs have been fixed. * */ #include "osta.h" /*****************************************************************************/ /*********************************************************************** * OSTA compliant Unicode compression, uncompression routines. * Copyright 1995 Micro Design International, Inc. * Written by Jason M. Rinn. * Micro Design International gives permission for the free use of the * following source code. */ /*********************************************************************** * Takes an OSTA CS0 compressed unicode name, and converts * it to Unicode. * The Unicode output will be in the byte order * that the local compiler uses for 16-bit values. * NOTE: This routine only performs error checking on the compID. * It is up to the user to ensure that the unicode buffer is large * enough, and that the compressed unicode name is correct. * * RETURN VALUE * * The number of unicode characters which were uncompressed. * A -1 is returned if the compression ID is invalid. */ int udf_UncompressUnicode( int numberOfBytes, /* (Input) number of bytes read from media. */ byte *UDFCompressed, /* (Input) bytes read from media. */ unicode_t *unicode) /* (Output) uncompressed unicode characters. */ { unsigned int compID; int returnValue, unicodeIndex, byteIndex; /* Use UDFCompressed to store current byte being read. */ compID = UDFCompressed[0]; /* First check for valid compID. */ if (compID != 8 && compID != 16) { returnValue = -1; } else { unicodeIndex = 0; byteIndex = 1; /* Loop through all the bytes. */ while (byteIndex < numberOfBytes) { if (compID == 16) { /* Move the first byte to the high bits of the * unicode char. */ unicode[unicodeIndex] = UDFCompressed[byteIndex++] << 8; } else { unicode[unicodeIndex] = 0; } if (byteIndex < numberOfBytes) { /*Then the next byte to the low bits. */ unicode[unicodeIndex] |= UDFCompressed[byteIndex++]; } unicodeIndex++; } returnValue = unicodeIndex; } return(returnValue); } /*********************************************************************** * DESCRIPTION: * Takes a string of unicode wide characters and returns an OSTA CS0 * compressed unicode string. The unicode MUST be in the byte order of * the compiler in order to obtain correct results. Returns an error * if the compression ID is invalid. * * NOTE: This routine assumes the implementation already knows, by * the local environment, how many bits are appropriate and * therefore does no checking to test if the input characters fit * into that number of bits or not. * * RETURN VALUE * * The total number of bytes in the compressed OSTA CS0 string, * including the compression ID. * A -1 is returned if the compression ID is invalid. */ int udf_CompressUnicode( int numberOfChars, /* (Input) number of unicode characters. */ int compID, /* (Input) compression ID to be used. */ unicode_t *unicode, /* (Input) unicode characters to compress. */ byte *UDFCompressed) /* (Output) compressed string, as bytes. */ { int byteIndex, unicodeIndex; if (compID != 8 && compID != 16) { byteIndex = -1; /* Unsupported compression ID ! */ } else { /* Place compression code in first byte. */ UDFCompressed[0] = compID; byteIndex = 1; unicodeIndex = 0; while (unicodeIndex < numberOfChars) { if (compID == 16) { /* First, place the high bits of the char * into the byte stream. */ UDFCompressed[byteIndex++] = (unicode[unicodeIndex] & 0xFF00) >> 8; } /*Then place the low bits into the stream. */ UDFCompressed[byteIndex++] = unicode[unicodeIndex] & 0x00FF; unicodeIndex++; } } return(byteIndex); } /*****************************************************************************/ /* * CRC 010041 */ static unsigned short crc_table[256] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 }; uint16_t udf_cksum(uint8_t *s, int n) { uint16_t crc = 0; while (n-- > 0) crc = crc_table[(crc>>8 ^ *s++) & 0xff] ^ (crc<<8); return crc; } /* UNICODE Checksum */ uint16_t udf_unicode_cksum(uint16_t *s, int n) { uint16_t crc = 0; while (n-- > 0) { /* Take high order byte first--corresponds to a big endian * byte stream. */ crc = crc_table[(crc>>8 ^ (*s>>8)) & 0xff] ^ (crc<<8); crc = crc_table[(crc>>8 ^ (*s++ & 0xff)) & 0xff] ^ (crc<<8); } return crc; } /* * Calculates a 16-bit checksum of the Implementation Use * Extended Attribute header or Application Use Extended Attribute * header. The fields AttributeType through ImplementationIdentifier * (or ApplicationIdentifier) inclusively represent the * data covered by the checksum (48 bytes). * */ uint16_t udf_ea_cksum(uint8_t *data) { uint16_t checksum = 0; int count; for (count = 0; count < 48; count++) { checksum += *data++; } return checksum; } #ifdef MAIN unsigned char bytes[] = { 0x70, 0x6A, 0x77 }; main() { unsigned short x; x = cksum(bytes, sizeof bytes); printf("checksum: calculated=%4.4x, correct=%4.4x\en", x, 0x3299); exit(0); } #endif /*****************************************************************************/ #ifdef NEEDS_ISPRINT /*********************************************************************** * OSTA UDF compliant file name translation routine for OS/2, * Windows 95, Windows NT, Macintosh and UNIX. * Copyright 1995 Micro Design International, Inc. * Written by Jason M. Rinn. * Micro Design International gives permission for the free use of the * following source code. */ /*********************************************************************** * To use these routines with different operating systems. * * OS/2 * Define OS2 * Define MAXLEN = 254 * * Windows 95 * Define WIN_95 * Define MAXLEN = 255 * * Windows NT * Define WIN_NT * Define MAXLEN = 255 * * Macintosh: * Define MAC. * Define MAXLEN = 31. * * UNIX * Define UNIX. * Define MAXLEN as specified by unix version. */ #define ILLEGAL_CHAR_MARK 0x005F #define CRC_MARK 0x0023 #define EXT_SIZE 5 #define TRUE 1 #define FALSE 0 #define PERIOD 0x002E #define SPACE 0x0020 /*** PROTOTYPES ***/ int IsIllegal(unicode_t ch); /* Define a function or macro which determines if a Unicode character is * printable under your implementation. */ #include int UnicodeIsPrint(unicode_t ch) { return (ch >=' ') && (ch < 127); } int UnicodeLength(unicode_t *string) { int length; length = 0; while (*string++) length++; return length; } /*********************************************************************** * Translates a long file name to one using a MAXLEN and an illegal * char set in accord with the OSTA requirements. Assumes the name has * already been translated to Unicode. * * RETURN VALUE * * Number of unicode characters in translated name. */ int UDFTransName( unicode_t *newName, /* (Output)Translated name. Must be of length * MAXLEN */ unicode_t *udfName, /* (Input) Name from UDF volume.*/ int udfLen) /* (Input) Length of UDF Name. */ { int index, newIndex = 0, needsCRC = FALSE; int extIndex = 0, newExtIndex = 0, hasExt = FALSE; #if defined OS2 || defined WIN_95 || defined WIN_NT int trailIndex = 0; #endif unsigned short valueCRC; unicode_t current; const char hexChar[] = "0123456789ABCDEF"; for (index = 0; index < udfLen; index++) { current = udfName[index]; if (IsIllegal(current) || !UnicodeIsPrint(current)) { needsCRC = TRUE; /* Replace Illegal and non-displayable chars with * underscore. */ current = ILLEGAL_CHAR_MARK; /* Skip any other illegal or non-displayable * characters. */ while(index+1 < udfLen && (IsIllegal(udfName[index+1]) || !UnicodeIsPrint(udfName[index+1]))) { index++; } } /* Record position of extension, if one is found. */ if (current == PERIOD && (udfLen - index -1) <= EXT_SIZE) { if (udfLen == index + 1) { /* A trailing period is NOT an extension. */ hasExt = FALSE; } else { hasExt = TRUE; extIndex = index; newExtIndex = newIndex; } } #if defined OS2 || defined WIN_95 || defined WIN_NT /* Record position of last char which is NOT period or space. */ else if (current != PERIOD && current != SPACE) { trailIndex = newIndex; } #endif if (newIndex < MAXLEN) { newName[newIndex++] = current; } else { needsCRC = TRUE; } } #if defined OS2 || defined WIN_95 || defined WIN_NT /* For OS2, 95 & NT, truncate any trailing periods and\or spaces. */ if (trailIndex != newIndex - 1) { newIndex = trailIndex + 1; needsCRC = TRUE; hasExt = FALSE; /* Trailing period does not make an * extension. */ } #endif if (needsCRC) { unicode_t ext[EXT_SIZE]; int localExtIndex = 0; if (hasExt) { int maxFilenameLen; /* Translate extension, and store it in ext. */ for(index = 0; index maxFilenameLen) { newIndex = maxFilenameLen; } else { newIndex = newExtIndex; } } else if (newIndex > MAXLEN - 5) { /*If no extension, make sure to leave room for CRC. */ newIndex = MAXLEN - 5; } newName[newIndex++] = CRC_MARK; /* Add mark for CRC. */ /*Calculate CRC from original filename from FileIdentifier. */ valueCRC = udf_unicode_cksum(udfName, udfLen); /* Convert 16-bits of CRC to hex characters. */ newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12]; newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8]; newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4]; newName[newIndex++] = hexChar[(valueCRC & 0x000f)]; /* Place a translated extension at end, if found. */ if (hasExt) { newName[newIndex++] = PERIOD; for (index = 0;index < localExtIndex ;index++ ) { newName[newIndex++] = ext[index]; } } } return(newIndex); } #if defined OS2 || defined WIN_95 || defined WIN_NT /*********************************************************************** * Decides if a Unicode character matches one of a list * of ASCII characters. * Used by OS2 version of IsIllegal for readability, since all of the * illegal characters above 0x0020 are in the ASCII subset of Unicode. * Works very similarly to the standard C function strchr(). * * RETURN VALUE * * Non-zero if the Unicode character is in the given ASCII string. */ int UnicodeInString( unsigned char *string, /* (Input) String to search through. */ unicode_t ch) /* (Input) Unicode char to search for. */ { int found = FALSE; while (*string != '\0' && found == FALSE) { /* These types should compare, since both are unsigned * numbers. */ if (*string == ch) { found = TRUE; } string++; } return(found); } #endif /* OS2 */ /*********************************************************************** * Decides whether the given character is illegal for a given OS. * * RETURN VALUE * * Non-zero if char is illegal. */ int IsIllegal(unicode_t ch) { #ifdef MAC /* Only illegal character on the MAC is the colon. */ if (ch == 0x003A) { return(1); } else { return(0); } #elif defined UNIX /* Illegal UNIX characters are NULL and slash. */ if (ch == 0x0000 || ch == 0x002F) { return(1); } else { return(0); } #elif defined OS2 || defined WIN_95 || defined WIN_NT /* Illegal char's for OS/2 according to WARP toolkit. */ if (ch < 0x0020 || UnicodeInString("\\/:*?\"<>|", ch)) { return(1); } else { return(0); } #endif } #endif UDFclient.0.8.8/dirhash.h010064400001470000000000000062351307041400500144560ustar reinoudwheel/* $NetBSD: dirhash.h,v 1.4 2008/10/30 23:02:12 rmind Exp $ */ /* * Copyright (c) 2008, 2011 Reinoud Zandijk * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SYS_DIRHASH_H_ #define _SYS_DIRHASH_H_ #include #include "queue.h" #ifndef DIRHASH_SIZE #define DIRHASH_SIZE (1024*1024) #endif #define DIRHASH_HASHBITS 5 #define DIRHASH_HASHSIZE (1 << DIRHASH_HASHBITS) #define DIRHASH_HASHMASK (DIRHASH_HASHSIZE - 1) #ifdef NO_DIRENT_NAMLEN # define DIRENT_NAMLEN(d) strlen((d)->d_name) #else # define DIRENT_NAMLEN(d) (d)->d_namlen #endif #ifndef _DIRENT_SIZE /* guess */ # define _DIRENT_SIZE(d) (32 + DIRENT_NAMLEN(d)) #endif /* dirent's d_namlen is to avoid useless costly fid->dirent translations */ struct dirhash_entry { uint32_t hashvalue; uint64_t offset; uint32_t d_namlen; uint32_t entry_size; LIST_ENTRY(dirhash_entry) next; }; struct dirhash { uint32_t flags; uint32_t size; /* in bytes */ uint32_t refcnt; LIST_HEAD(, dirhash_entry) entries[DIRHASH_HASHSIZE]; LIST_HEAD(, dirhash_entry) free_entries; TAILQ_ENTRY(dirhash) next; }; #define DIRH_PURGED 0x0001 /* dirhash has been purged */ #define DIRH_COMPLETE 0x0002 /* dirhash is complete */ #define DIRH_BROKEN 0x0004 /* dirhash is broken on readin */ #define DIRH_FLAGBITS "\10\1DIRH_PURGED\2DIRH_COMPLETE\3DIRH_BROKEN" void dirhash_init(void); /* void dirhash_finish(void); */ void dirhash_purge(struct dirhash **); void dirhash_purge_entries(struct dirhash *); void dirhash_get(struct dirhash **); void dirhash_put(struct dirhash *); void dirhash_enter(struct dirhash *, struct dirent *, uint64_t, uint32_t, int); void dirhash_enter_freed(struct dirhash *, uint64_t, uint32_t); void dirhash_mark_freed(struct dirhash *, struct dirhash_entry *, struct dirent *); int dirhash_lookup(struct dirhash *, const char *, int, struct dirhash_entry **); int dirhash_lookup_freed(struct dirhash *, uint32_t, struct dirhash_entry **); #endif /* _SYS_DIRHASH_H_ */ UDFclient.0.8.8/osta.h010064400001470000000000000015651307041400500140030ustar reinoudwheel/* $NetBSD$ */ /* * Prototypes for the OSTA functions * */ #ifndef _OSTA_H_ #define _OSTA_H_ #include #include #include #ifndef UNIX #define UNIX #endif #ifndef MAXLEN #define MAXLEN 255 #endif /*********************************************************************** * The following two typedef's are to remove compiler dependancies. * byte needs to be unsigned 8-bit, and unicode_t needs to be * unsigned 16-bit. */ typedef uint16_t unicode_t; typedef uint8_t byte; int udf_UncompressUnicode(int, byte *, unicode_t *); int udf_CompressUnicode(int, int, unicode_t *, byte *); uint16_t udf_cksum(uint8_t *s, int n); uint16_t udf_unicode_cksum(uint16_t *s, int n); uint16_t udf_ea_cksum(uint8_t *); int UDFTransName(unicode_t *, unicode_t *, int); int UnicodeLength(unicode_t *string); #endif /* _OSTA_H_ */ UDFclient.0.8.8/queue.h010064400001470000000000000516261307041400500141640ustar reinoudwheel/* $NetBSD: queue.h,v 1.35 2004/02/26 01:20:47 wiz Exp $ */ /* * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)queue.h 8.5 (Berkeley) 8/20/94 */ #ifndef _SYS_QUEUE_H_ #define _SYS_QUEUE_H_ /* * This file defines five types of data structures: singly-linked lists, * lists, simple queues, tail queues, and circular queues. * * A singly-linked list is headed by a single forward pointer. The * elements are singly linked for minimum space and pointer manipulation * overhead at the expense of O(n) removal for arbitrary elements. New * elements can be added to the list after an existing element or at the * head of the list. Elements being removed from the head of the list * should use the explicit macro for this purpose for optimum * efficiency. A singly-linked list may only be traversed in the forward * direction. Singly-linked lists are ideal for applications with large * datasets and few or no removals or for implementing a LIFO queue. * * A list is headed by a single forward pointer (or an array of forward * pointers for a hash table header). The elements are doubly linked * so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before * or after an existing element or at the head of the list. A list * may only be traversed in the forward direction. * * A simple queue is headed by a pair of pointers, one the head of the * list and the other to the tail of the list. The elements are singly * linked to save space, so only elements can only be removed from the * head of the list. New elements can be added to the list after * an existing element, at the head of the list, or at the end of the * list. A simple queue may only be traversed in the forward direction. * * A tail queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or * after an existing element, at the head of the list, or at the end of * the list. A tail queue may be traversed in either direction. * * A circle queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or after * an existing element, at the head of the list, or at the end of the list. * A circle queue may be traversed in either direction, but has a more * complex end of list detection. * * For details on the use of these macros, see the queue(3) manual page. */ /* * List definitions. */ #define LIST_HEAD(name, type) \ struct name { \ struct type *lh_first; /* first element */ \ } #define LIST_HEAD_INITIALIZER(head) \ { NULL } #define LIST_ENTRY(type) \ struct { \ struct type *le_next; /* next element */ \ struct type **le_prev; /* address of previous next element */ \ } /* * List functions. */ #if defined(_KERNEL) && defined(QUEUEDEBUG) #define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) \ if ((head)->lh_first && \ (head)->lh_first->field.le_prev != &(head)->lh_first) \ panic("LIST_INSERT_HEAD %p %s:%d", (head), __FILE__, __LINE__); #define QUEUEDEBUG_LIST_OP(elm, field) \ if ((elm)->field.le_next && \ (elm)->field.le_next->field.le_prev != \ &(elm)->field.le_next) \ panic("LIST_* forw %p %s:%d", (elm), __FILE__, __LINE__);\ if (*(elm)->field.le_prev != (elm)) \ panic("LIST_* back %p %s:%d", (elm), __FILE__, __LINE__); #define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) \ (elm)->field.le_next = (void *)1L; \ (elm)->field.le_prev = (void *)1L; #else #define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) #define QUEUEDEBUG_LIST_OP(elm, field) #define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) #endif #define LIST_INIT(head) do { \ (head)->lh_first = NULL; \ } while (/*CONSTCOND*/0) #define LIST_INSERT_AFTER(listelm, elm, field) do { \ QUEUEDEBUG_LIST_OP((listelm), field) \ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ (listelm)->field.le_next->field.le_prev = \ &(elm)->field.le_next; \ (listelm)->field.le_next = (elm); \ (elm)->field.le_prev = &(listelm)->field.le_next; \ } while (/*CONSTCOND*/0) #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ QUEUEDEBUG_LIST_OP((listelm), field) \ (elm)->field.le_prev = (listelm)->field.le_prev; \ (elm)->field.le_next = (listelm); \ *(listelm)->field.le_prev = (elm); \ (listelm)->field.le_prev = &(elm)->field.le_next; \ } while (/*CONSTCOND*/0) #define LIST_INSERT_HEAD(head, elm, field) do { \ QUEUEDEBUG_LIST_INSERT_HEAD((head), (elm), field) \ if (((elm)->field.le_next = (head)->lh_first) != NULL) \ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ (head)->lh_first = (elm); \ (elm)->field.le_prev = &(head)->lh_first; \ } while (/*CONSTCOND*/0) #define LIST_REMOVE(elm, field) do { \ QUEUEDEBUG_LIST_OP((elm), field) \ if ((elm)->field.le_next != NULL) \ (elm)->field.le_next->field.le_prev = \ (elm)->field.le_prev; \ *(elm)->field.le_prev = (elm)->field.le_next; \ QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \ } while (/*CONSTCOND*/0) #define LIST_FOREACH(var, head, field) \ for ((var) = ((head)->lh_first); \ (var); \ (var) = ((var)->field.le_next)) /* * List access methods. */ #define LIST_EMPTY(head) ((head)->lh_first == NULL) #define LIST_FIRST(head) ((head)->lh_first) #define LIST_NEXT(elm, field) ((elm)->field.le_next) /* * Singly-linked List definitions. */ #define SLIST_HEAD(name, type) \ struct name { \ struct type *slh_first; /* first element */ \ } #define SLIST_HEAD_INITIALIZER(head) \ { NULL } #define SLIST_ENTRY(type) \ struct { \ struct type *sle_next; /* next element */ \ } /* * Singly-linked List functions. */ #define SLIST_EMPTY(head) ((head)->slh_first == NULL) #define SLIST_FIRST(head) ((head)->slh_first) #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) #define SLIST_FOREACH(var, head, field) \ for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next) #define SLIST_INIT(head) do { \ (head)->slh_first = NULL; \ } while (/*CONSTCOND*/0) #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ (elm)->field.sle_next = (slistelm)->field.sle_next; \ (slistelm)->field.sle_next = (elm); \ } while (/*CONSTCOND*/0) #define SLIST_INSERT_HEAD(head, elm, field) do { \ (elm)->field.sle_next = (head)->slh_first; \ (head)->slh_first = (elm); \ } while (/*CONSTCOND*/0) #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) #define SLIST_REMOVE_HEAD(head, field) do { \ (head)->slh_first = (head)->slh_first->field.sle_next; \ } while (/*CONSTCOND*/0) #define SLIST_REMOVE(head, elm, type, field) do { \ if ((head)->slh_first == (elm)) { \ SLIST_REMOVE_HEAD((head), field); \ } \ else { \ struct type *curelm = (head)->slh_first; \ while(curelm->field.sle_next != (elm)) \ curelm = curelm->field.sle_next; \ curelm->field.sle_next = \ curelm->field.sle_next->field.sle_next; \ } \ } while (/*CONSTCOND*/0) /* * Singly-linked Tail queue declarations. */ #define STAILQ_HEAD(name, type) \ struct name { \ struct type *stqh_first; /* first element */ \ struct type **stqh_last; /* addr of last next element */ \ } #define STAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).stqh_first } #define STAILQ_ENTRY(type) \ struct { \ struct type *stqe_next; /* next element */ \ } /* * Singly-linked Tail queue functions. */ #define STAILQ_INIT(head) do { \ (head)->stqh_first = NULL; \ (head)->stqh_last = &(head)->stqh_first; \ } while (/*CONSTCOND*/0) #define STAILQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \ (head)->stqh_last = &(elm)->field.stqe_next; \ (head)->stqh_first = (elm); \ } while (/*CONSTCOND*/0) #define STAILQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.stqe_next = NULL; \ *(head)->stqh_last = (elm); \ (head)->stqh_last = &(elm)->field.stqe_next; \ } while (/*CONSTCOND*/0) #define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\ (head)->stqh_last = &(elm)->field.stqe_next; \ (listelm)->field.stqe_next = (elm); \ } while (/*CONSTCOND*/0) #define STAILQ_REMOVE_HEAD(head, field) do { \ if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \ (head)->stqh_last = &(head)->stqh_first; \ } while (/*CONSTCOND*/0) #define STAILQ_REMOVE(head, elm, type, field) do { \ if ((head)->stqh_first == (elm)) { \ STAILQ_REMOVE_HEAD((head), field); \ } else { \ struct type *curelm = (head)->stqh_first; \ while (curelm->field.stqe_next != (elm)) \ curelm = curelm->field.stqe_next; \ if ((curelm->field.stqe_next = \ curelm->field.stqe_next->field.stqe_next) == NULL) \ (head)->stqh_last = &(curelm)->field.stqe_next; \ } \ } while (/*CONSTCOND*/0) #define STAILQ_FOREACH(var, head, field) \ for ((var) = ((head)->stqh_first); \ (var); \ (var) = ((var)->field.stqe_next)) #define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) #define STAILQ_FIRST(head) ((head)->stqh_first) #define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) /* * Simple queue definitions. */ #define SIMPLEQ_HEAD(name, type) \ struct name { \ struct type *sqh_first; /* first element */ \ struct type **sqh_last; /* addr of last next element */ \ } #define SIMPLEQ_HEAD_INITIALIZER(head) \ { NULL, &(head).sqh_first } #define SIMPLEQ_ENTRY(type) \ struct { \ struct type *sqe_next; /* next element */ \ } /* * Simple queue functions. */ #define SIMPLEQ_INIT(head) do { \ (head)->sqh_first = NULL; \ (head)->sqh_last = &(head)->sqh_first; \ } while (/*CONSTCOND*/0) #define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ (head)->sqh_last = &(elm)->field.sqe_next; \ (head)->sqh_first = (elm); \ } while (/*CONSTCOND*/0) #define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.sqe_next = NULL; \ *(head)->sqh_last = (elm); \ (head)->sqh_last = &(elm)->field.sqe_next; \ } while (/*CONSTCOND*/0) #define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ (head)->sqh_last = &(elm)->field.sqe_next; \ (listelm)->field.sqe_next = (elm); \ } while (/*CONSTCOND*/0) #define SIMPLEQ_REMOVE_HEAD(head, field) do { \ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ (head)->sqh_last = &(head)->sqh_first; \ } while (/*CONSTCOND*/0) #define SIMPLEQ_REMOVE(head, elm, type, field) do { \ if ((head)->sqh_first == (elm)) { \ SIMPLEQ_REMOVE_HEAD((head), field); \ } else { \ struct type *curelm = (head)->sqh_first; \ while (curelm->field.sqe_next != (elm)) \ curelm = curelm->field.sqe_next; \ if ((curelm->field.sqe_next = \ curelm->field.sqe_next->field.sqe_next) == NULL) \ (head)->sqh_last = &(curelm)->field.sqe_next; \ } \ } while (/*CONSTCOND*/0) #define SIMPLEQ_FOREACH(var, head, field) \ for ((var) = ((head)->sqh_first); \ (var); \ (var) = ((var)->field.sqe_next)) /* * Simple queue access methods. */ #define SIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL) #define SIMPLEQ_FIRST(head) ((head)->sqh_first) #define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) /* * Tail queue definitions. */ #define TAILQ_HEAD(name, type) \ struct name { \ struct type *tqh_first; /* first element */ \ struct type **tqh_last; /* addr of last next element */ \ } #define TAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).tqh_first } #define TAILQ_ENTRY(type) \ struct { \ struct type *tqe_next; /* next element */ \ struct type **tqe_prev; /* address of previous next element */ \ } /* * Tail queue functions. */ #if defined(_KERNEL) && defined(QUEUEDEBUG) #define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) \ if ((head)->tqh_first && \ (head)->tqh_first->field.tqe_prev != &(head)->tqh_first) \ panic("TAILQ_INSERT_HEAD %p %s:%d", (head), __FILE__, __LINE__); #define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) \ if (*(head)->tqh_last != NULL) \ panic("TAILQ_INSERT_TAIL %p %s:%d", (head), __FILE__, __LINE__); #define QUEUEDEBUG_TAILQ_OP(elm, field) \ if ((elm)->field.tqe_next && \ (elm)->field.tqe_next->field.tqe_prev != \ &(elm)->field.tqe_next) \ panic("TAILQ_* forw %p %s:%d", (elm), __FILE__, __LINE__);\ if (*(elm)->field.tqe_prev != (elm)) \ panic("TAILQ_* back %p %s:%d", (elm), __FILE__, __LINE__); #define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) \ if ((elm)->field.tqe_next == NULL && \ (head)->tqh_last != &(elm)->field.tqe_next) \ panic("TAILQ_PREREMOVE head %p elm %p %s:%d", \ (head), (elm), __FILE__, __LINE__); #define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) \ (elm)->field.tqe_next = (void *)1L; \ (elm)->field.tqe_prev = (void *)1L; #else #define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) #define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) #define QUEUEDEBUG_TAILQ_OP(elm, field) #define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) #define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) #endif #define TAILQ_INIT(head) do { \ (head)->tqh_first = NULL; \ (head)->tqh_last = &(head)->tqh_first; \ } while (/*CONSTCOND*/0) #define TAILQ_INSERT_HEAD(head, elm, field) do { \ QUEUEDEBUG_TAILQ_INSERT_HEAD((head), (elm), field) \ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ (head)->tqh_first->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (head)->tqh_first = (elm); \ (elm)->field.tqe_prev = &(head)->tqh_first; \ } while (/*CONSTCOND*/0) #define TAILQ_INSERT_TAIL(head, elm, field) do { \ QUEUEDEBUG_TAILQ_INSERT_TAIL((head), (elm), field) \ (elm)->field.tqe_next = NULL; \ (elm)->field.tqe_prev = (head)->tqh_last; \ *(head)->tqh_last = (elm); \ (head)->tqh_last = &(elm)->field.tqe_next; \ } while (/*CONSTCOND*/0) #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ QUEUEDEBUG_TAILQ_OP((listelm), field) \ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ (elm)->field.tqe_next->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (listelm)->field.tqe_next = (elm); \ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ } while (/*CONSTCOND*/0) #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ QUEUEDEBUG_TAILQ_OP((listelm), field) \ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ (elm)->field.tqe_next = (listelm); \ *(listelm)->field.tqe_prev = (elm); \ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ } while (/*CONSTCOND*/0) #define TAILQ_REMOVE(head, elm, field) do { \ QUEUEDEBUG_TAILQ_PREREMOVE((head), (elm), field) \ QUEUEDEBUG_TAILQ_OP((elm), field) \ if (((elm)->field.tqe_next) != NULL) \ (elm)->field.tqe_next->field.tqe_prev = \ (elm)->field.tqe_prev; \ else \ (head)->tqh_last = (elm)->field.tqe_prev; \ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \ } while (/*CONSTCOND*/0) /* * Tail queue access methods. */ #define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) #define TAILQ_FIRST(head) ((head)->tqh_first) #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) #define TAILQ_LAST(head, headname) \ (*(((struct headname *)((head)->tqh_last))->tqh_last)) #define TAILQ_PREV(elm, headname, field) \ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) #define TAILQ_FOREACH(var, head, field) \ for ((var) = ((head)->tqh_first); \ (var); \ (var) = ((var)->field.tqe_next)) #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \ (var); \ (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) /* * Circular queue definitions. */ #define CIRCLEQ_HEAD(name, type) \ struct name { \ struct type *cqh_first; /* first element */ \ struct type *cqh_last; /* last element */ \ } #define CIRCLEQ_HEAD_INITIALIZER(head) \ { (void *)&head, (void *)&head } #define CIRCLEQ_ENTRY(type) \ struct { \ struct type *cqe_next; /* next element */ \ struct type *cqe_prev; /* previous element */ \ } /* * Circular queue functions. */ #define CIRCLEQ_INIT(head) do { \ (head)->cqh_first = (void *)(head); \ (head)->cqh_last = (void *)(head); \ } while (/*CONSTCOND*/0) #define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm)->field.cqe_next; \ (elm)->field.cqe_prev = (listelm); \ if ((listelm)->field.cqe_next == (void *)(head)) \ (head)->cqh_last = (elm); \ else \ (listelm)->field.cqe_next->field.cqe_prev = (elm); \ (listelm)->field.cqe_next = (elm); \ } while (/*CONSTCOND*/0) #define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm); \ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ if ((listelm)->field.cqe_prev == (void *)(head)) \ (head)->cqh_first = (elm); \ else \ (listelm)->field.cqe_prev->field.cqe_next = (elm); \ (listelm)->field.cqe_prev = (elm); \ } while (/*CONSTCOND*/0) #define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ (elm)->field.cqe_next = (head)->cqh_first; \ (elm)->field.cqe_prev = (void *)(head); \ if ((head)->cqh_last == (void *)(head)) \ (head)->cqh_last = (elm); \ else \ (head)->cqh_first->field.cqe_prev = (elm); \ (head)->cqh_first = (elm); \ } while (/*CONSTCOND*/0) #define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.cqe_next = (void *)(head); \ (elm)->field.cqe_prev = (head)->cqh_last; \ if ((head)->cqh_first == (void *)(head)) \ (head)->cqh_first = (elm); \ else \ (head)->cqh_last->field.cqe_next = (elm); \ (head)->cqh_last = (elm); \ } while (/*CONSTCOND*/0) #define CIRCLEQ_REMOVE(head, elm, field) do { \ if ((elm)->field.cqe_next == (void *)(head)) \ (head)->cqh_last = (elm)->field.cqe_prev; \ else \ (elm)->field.cqe_next->field.cqe_prev = \ (elm)->field.cqe_prev; \ if ((elm)->field.cqe_prev == (void *)(head)) \ (head)->cqh_first = (elm)->field.cqe_next; \ else \ (elm)->field.cqe_prev->field.cqe_next = \ (elm)->field.cqe_next; \ } while (/*CONSTCOND*/0) #define CIRCLEQ_FOREACH(var, head, field) \ for ((var) = ((head)->cqh_first); \ (var) != (void *)(head); \ (var) = ((var)->field.cqe_next)) #define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ for ((var) = ((head)->cqh_last); \ (var) != (void *)(head); \ (var) = ((var)->field.cqe_prev)) /* * Circular queue access methods. */ #define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) #define CIRCLEQ_FIRST(head) ((head)->cqh_first) #define CIRCLEQ_LAST(head) ((head)->cqh_last) #define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) #define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) #endif /* !_SYS_QUEUE_H_ */ UDFclient.0.8.8/udfclient.c010066400001470000000000001401121307041400500147770ustar reinoudwheel/* $NetBSD$ */ /* * File "udfclient.c" is part of the UDFclient toolkit. * File $Id: udfclient.c,v 1.104 2016/04/25 21:28:00 reinoud Exp $ $Name: $ * * Copyright (c) 2003, 2004, 2005, 2006, 2011 * Reinoud Zandijk * All rights reserved. * * The UDFclient toolkit is distributed under the Clarified Artistic Licence. * A copy of the licence is included in the distribution as * `LICENCE.clearified.artistic' and a copy of the licence can also be * requested at the GNU foundantion's website. * * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include #include #include "udf.h" #include "udf_bswap.h" /* switches */ /* #define DEBUG(a) (a) */ #define DEBUG(a) if (0) { a; } #ifndef MAX #define MAX(a,b) ((a)>(b)?(a):(b)) #define MIN(a,b) ((a)<(b)?(a):(b)) #endif /* include timeval to timespec conversion macro's for systems that don't provide them */ #ifndef TIMEVAL_TO_TIMESPEC # define TIMEVAL_TO_TIMESPEC(tv, ts) do { \ (ts)->tv_sec = (tv)->tv_sec; \ (ts)->tv_nsec = (tv)->tv_usec * 1000; \ } while (/*CONSTCOND*/0) #endif #ifndef TIMESPEC_TO_TIMEVAL # define TIMESPEC_TO_TIMEVAL(tv, ts) do { \ (tv)->tv_sec = (ts)->tv_sec; \ (tv)->tv_usec = (ts)->tv_nsec / 1000; \ } while (/*CONSTCOND*/0) #endif /* include the dump parts ... in order to get a more sane splitting */ extern void udf_dump_alive_sets(void); /* globals */ extern int udf_verbose; extern int uscsilib_verbose; int read_only; #define MAX_ARGS 100 struct curdir { char *name; struct udf_mountpoint *mountpoint; /* foreign */ struct udf_node *udf_node; /* foreign */ struct hash_entry *udf_mountpoint_entry; /* `current' mountpoint entry */ } curdir; /* * XXX * FTP client; de volumes vooraan zetten in de VFS ; evt. in meerdere subdirs. * general file name format * * /volset:pri:log/udfpath * of * /volset/pri/log/udfpath/ * * XXX */ int udfclient_readdir(struct udf_node *udf_node, struct uio *result_uio, int *eof_res) { struct dirent entry; struct udf_mountpoint *mountable; assert(result_uio); if (!udf_node) { /* mountables */ /* XXX result_uio needs to be long enough to hold all mountables!!!! XXX */ SLIST_FOREACH(mountable, &udf_mountables, all_next) { strcpy(entry.d_name, mountable->mount_name); entry.d_type = DT_DIR; uiomove(&entry, sizeof(struct dirent), result_uio); } if (eof_res) *eof_res = 1; return 0; } /* intree nodes : pass on to udf_readdir */ return udf_readdir(udf_node, result_uio, eof_res); } /* VOP_LOOKUP a-like */ int udfclient_lookup(struct udf_node *dir_node, struct udf_node **resnode, char *name) { struct udf_mountpoint *mountable; struct fileid_desc *fid; struct long_ad udf_icbptr; int lb_size, found, error; assert(resnode); assert(name); *resnode = NULL; if (!dir_node) { /* mountables */ SLIST_FOREACH(mountable, &udf_mountables, all_next) { if (strcmp(mountable->mount_name, name) == 0) { /* found `root' of a mountable */ *resnode = mountable->rootdir_node; return 0; } } return ENOENT; } /* intree nodes : pass on to udf_lookup_name_in_dir */ lb_size = dir_node->udf_log_vol->lb_size; fid = malloc(lb_size); assert(fid); error = udf_lookup_name_in_dir(dir_node, name, strlen(name), &udf_icbptr, fid, &found); if (!error) { error = ENOENT; if (found) error = udf_readin_udf_node(dir_node, &udf_icbptr, fid, resnode); } free(fid); return error; } int udfclient_getattr(struct udf_node *udf_node, struct stat *stat) { int error; error = 0; if (udf_node) { error = udf_getattr(udf_node, stat); /* print? */ if (error) fprintf(stderr, "Can't stat file\n"); } else { /* dummy entry for `root' in VFS */ stat->st_mode = 0744 | S_IFDIR; stat->st_size = 0; stat->st_uid = 0; stat->st_gid = 0; } return error; } /* higher level of lookup; walk tree */ /* results in a `held'/locked node upto `root' */ int udfclient_lookup_pathname(struct udf_node *cur_node, struct udf_node **res_node, char *restpath_given) { struct udf_node *sub_node; char *restpath, *next_element, *slashpos, *pathpos; int error; assert(restpath_given); restpath = strdup(restpath_given); /* start at root */ *res_node = NULL; pathpos = restpath; assert(*pathpos == '/'); pathpos++; /* strip leading '/' */ next_element = pathpos; while (next_element && (strlen(next_element) > 0)) { /* determine next slash position */ slashpos = strchr(next_element, '/'); if (slashpos) *slashpos++ = 0; error = udfclient_lookup(cur_node, &sub_node, next_element); if (error) { free(restpath); return error; } /* advance */ cur_node = sub_node; next_element = slashpos; } /* we are at the end; return result */ *res_node = cur_node; free(restpath); return 0; } char *udfclient_realpath(char *cur_path, char *relpath, char **leaf) { char *resultpath, *here, *pos; resultpath = calloc(1, sizeof(cur_path) + sizeof(relpath) +1024); assert(resultpath); strcpy(resultpath, "/"); strcat(resultpath, cur_path); strcat(resultpath, "/"); /* check if we are going back to `root' */ if (relpath && *relpath == '/') { strcpy(resultpath, ""); } strcat(resultpath, relpath); /* now clean up the resulting string by removing double slashes */ here = resultpath; while (*here) { pos = here; while (strncmp(pos, "//", 2) == 0) pos++; if (pos != here) strcpy(here, pos); here++; } /* remove '.' and '..' sequences */ here = resultpath; while (*here) { /* printf("transformed to %s\n", resultpath); */ /* check for internal /./ and trailing /. */ if (strncmp(here, "/./", 3) == 0) { strcpy(here+1, here + 3); continue; } if (strcmp(here, "/.")==0) { strcpy(here+1, here + 2); continue; } if (strncmp(here, "/../", 4) == 0) { strcpy(here+1, here + 4); /* go for the parent */ pos = here-1; while (*pos && *pos != '/') pos--; pos++; strcpy(pos, here+1); here = pos; continue; } if (strcmp(here, "/..")==0) { strcpy(here+1, here + 3); /* go for the parent */ pos = here-1; while (*pos && *pos != '/') pos--; pos++; strcpy(pos, here+1); here = pos; continue; } here++; } if (leaf) { /* find the leaf name */ here = resultpath; while (*here) { if (strncmp(here, "/", 1) == 0) *leaf = here+1; here++; } } return resultpath; } static void print_dir_entry(struct udf_node *udf_node, char *name) { struct stat stat; uint64_t size; int mode, this_mode, uid, gid; int error; error = udfclient_getattr(udf_node, &stat); if (error) return; size = stat.st_size; mode = stat.st_mode; uid = stat.st_uid; gid = stat.st_gid; if (mode & S_IFDIR) printf("d"); else printf("-"); mode = mode & 511; this_mode = (mode >> 6) & 7; printf("%c%c%c", "----rrrr"[this_mode & 4], "--www"[this_mode & 2], "-x"[this_mode & 1]); this_mode = (mode >> 3) & 7; printf("%c%c%c", "----rrrr"[this_mode & 4], "--www"[this_mode & 2], "-x"[this_mode & 1]); this_mode = mode & 7; printf("%c%c%c", "----rrrr"[this_mode & 4], "--www"[this_mode & 2], "-x"[this_mode & 1]); printf(" %5d %5d %10"PRIu64" %s\n", gid, uid, size, name); } #define LS_SUBTREE_DIR_BUFFER_SIZE (16*1024) void udfclient_ls(int args, char *arg1) { struct udf_node *udf_node, *entry_node; uint8_t *buffer; struct uio dir_uio; struct iovec dir_uiovec; struct dirent *dirent; struct stat stat; uint32_t pos; int eof; char *node_name, *leaf_name; int error; if (args > 1) { printf("Syntax: ls [file | dir]\n"); return; } if (args == 0) arg1 = ""; node_name = udfclient_realpath(curdir.name, arg1, &leaf_name); error = udfclient_lookup_pathname(NULL, &udf_node, node_name); if (error) { fprintf(stderr, "%s : %s\n", arg1, strerror(error)); free(node_name); return; } error = udfclient_getattr(udf_node, &stat); if (stat.st_mode & S_IFDIR) { printf("Directory listing of %s\n", udf_node ? leaf_name : "/"); /* start at the start of the directory */ dir_uio.uio_offset = 0; dir_uio.uio_iov = &dir_uiovec; dir_uio.uio_iovcnt = 1; buffer = calloc(1, LS_SUBTREE_DIR_BUFFER_SIZE); if (!buffer) return; do { dir_uiovec.iov_base = buffer; dir_uiovec.iov_len = LS_SUBTREE_DIR_BUFFER_SIZE; dir_uio.uio_resid = LS_SUBTREE_DIR_BUFFER_SIZE; dir_uio.uio_rw = UIO_WRITE; error = udfclient_readdir(udf_node, &dir_uio, &eof); if (error) { fprintf(stderr, "error during readdir: %s\n", strerror(error)); break; } pos = 0; while (pos < LS_SUBTREE_DIR_BUFFER_SIZE - dir_uio.uio_resid) { dirent = (struct dirent *) (buffer + pos); error = udfclient_lookup(udf_node, &entry_node, dirent->d_name); print_dir_entry(entry_node, dirent->d_name); pos += sizeof(struct dirent); } } while (!eof); free(buffer); } else { print_dir_entry(udf_node, leaf_name); } free(node_name); } #undef LS_SUBTREE_DIR_BUFFER_SIZE void udfclient_pwd(int args) { char pwd[1024]; char *res; if (args) { printf("Syntax: pwd\n"); return; } res = getcwd(pwd, 1024); assert(res); printf("UDF working directory is %s\n", curdir.name); printf("Current FS working directory %s\n", pwd); } static void udfclient_print_free_amount(char *prefix, uint64_t value, uint64_t max_value) { printf("%s %10"PRIu64" Kb (%3"PRIu64" %%) (%8.2f Mb) (%5.2f Gb)\n", prefix, value/1024, (100*value)/max_value, (double) value/(1024*1024), (double) value/(1024*1024*1024)); } void udfclient_free(int args) { struct udf_part_mapping *part_mapping; struct udf_partition *udf_partition; struct udf_log_vol *udf_log_vol; struct logvol_desc *lvd; uint64_t part_size, unalloc_space, freed_space; uint64_t total_space, free_space, await_alloc_space; uint32_t lb_size; int part_num; if (args) { printf("Syntax: free\n"); return; } if (!curdir.udf_node || !(udf_log_vol = curdir.udf_node->udf_log_vol)) { printf("Can only report free space in UDF mountpoints\n"); return; } lb_size = udf_log_vol->lb_size; // sector_size = udf_log_vol->sector_size; lvd = udf_log_vol->log_vol; udf_dump_id("Logical volume ", 128, lvd->logvol_id, &lvd->desc_charset); total_space = udf_log_vol->total_space; free_space = udf_log_vol->free_space; await_alloc_space = udf_log_vol->await_alloc_space; SLIST_FOREACH(part_mapping, &udf_log_vol->part_mappings, next_mapping) { part_num = part_mapping->udf_virt_part_num; udf_logvol_vpart_to_partition(udf_log_vol, part_num, NULL, &udf_partition); assert(udf_partition); unalloc_space = udf_partition->free_unalloc_space; freed_space = udf_partition->free_freed_space; part_size = udf_partition->part_length; switch (part_mapping->udf_part_mapping_type) { case UDF_PART_MAPPING_PHYSICAL : printf("\tphysical partition %d\n", part_num); printf("\t\t%8"PRIu64" K (%"PRIu64" pages) size\n", part_size/1024, part_size / lb_size); printf("\t\t%8"PRIu64" K (%"PRIu64" pages) unallocated\n", unalloc_space/1024, unalloc_space / lb_size); printf("\t\t%8"PRIu64" K (%"PRIu64" pages) freed\n", freed_space/1024, freed_space / lb_size); break; case UDF_PART_MAPPING_VIRTUAL : printf("\tvirtual partition mapping %d\n", part_num); printf("\t\tnot applicable\n"); break; case UDF_PART_MAPPING_SPARABLE : printf("\tsparable partition %d\n", part_num); printf("\t\t%8"PRIu64" K (%"PRIu64" pages) size\n", part_size/1024, part_size / lb_size); printf("\t\t%8"PRIu64" K (%"PRIu64" pages) unallocated\n", unalloc_space/1024, unalloc_space / lb_size); printf("\t\t%8"PRIu64" K (%"PRIu64" pages) freed\n", freed_space/1024, freed_space / lb_size); break; case UDF_PART_MAPPING_META : printf("\tmetadata 'partition' %d\n", part_num); printf("\t\t%8"PRIu64" K (%"PRIu64" pages) unallocated\n", unalloc_space/1024, unalloc_space / lb_size); printf("\t\t%8"PRIu64" K (%"PRIu64" pages) freed\n", freed_space/1024, freed_space / lb_size); break; case UDF_PART_MAPPING_ERROR : printf("\terror partiton %d\n", part_num); break; default: break; } } printf("\n"); udfclient_print_free_amount("\tConfirmed free space ", free_space, total_space); udfclient_print_free_amount("\tAwaiting allocation ", await_alloc_space, total_space); udfclient_print_free_amount("\tEstimated free space ", free_space - await_alloc_space, total_space); udfclient_print_free_amount("\tEstimated total used ", total_space - free_space + await_alloc_space, total_space); printf("\n"); udfclient_print_free_amount("\tTotal size ", total_space, total_space); } void udfclient_cd(int args, char *arg1) { struct udf_node *udf_node; struct stat stat; char *node_name, *new_curdir_name; int error; if (args > 1) { printf("Syntax: cd [dir]\n"); return; } new_curdir_name = udfclient_realpath(curdir.name, arg1, NULL); node_name = strdup(new_curdir_name); /* working copy */ error = udfclient_lookup_pathname(NULL, &udf_node, node_name); if (error) { fprintf(stderr, "%s : %s\n", arg1, strerror(error)); free(new_curdir_name); free(node_name); return; } error = udfclient_getattr(udf_node, &stat); if (stat.st_mode & S_IFDIR) { free(curdir.name); curdir.name = new_curdir_name; curdir.udf_node = udf_node; free(node_name); udfclient_pwd(0); } else { fprintf(stderr, "%s is not a directory\n", arg1); free(new_curdir_name); free(node_name); } } void udfclient_lcd(int args, char *arg1) { char pwd[1024]; char *res; if (args > 1) { printf("Syntax: lcd [dir]\n"); return; } if (strcmp(arg1, "" )==0) arg1 = getenv("HOME"); if (strcmp(arg1, "~")==0) arg1 = getenv("HOME"); if (chdir(arg1)) { fprintf(stderr, "While trying to go to %s :", arg1); perror(""); } res = getcwd(pwd, 1024); assert(res); printf("Changing local directory to %s\n", pwd); } void udfclient_lls(int args) { if (args) { printf("Syntax: lls\n"); return; } if (system("/bin/ls")) { perror("While listing current directory\n"); } } uint64_t getmtime(void) { struct timeval tp; gettimeofday(&tp, NULL); return 1000000*tp.tv_sec + tp.tv_usec; } int udfclient_get_file(struct udf_node *udf_node, char *fullsrcname, char *fulldstname) { struct uio file_uio; struct iovec file_iov; struct stat stat; struct timeval times[2]; uint64_t file_length; uint64_t start, now, then, eta; uint64_t cur_speed, avg_speed, data_transfered; uint64_t file_block_size, file_transfer_size, written; uint8_t *file_block; char cur_txt[32], avg_txt[32], eta_txt[32]; int fileh, len; int notok, error; assert(udf_node); assert(fullsrcname); assert(strlen(fullsrcname) >= 1); error = 0; /* terminal directory node? */ error = udfclient_getattr(udf_node, &stat); if (stat.st_mode & S_IFDIR) { len = strlen(fulldstname); if (strcmp(fulldstname + len -2, "/.") == 0) fulldstname[len-2] = 0; if (strcmp(fulldstname + len -3, "/..") == 0) return 0; error = mkdir(fulldstname, (udf_node->stat.st_mode) & 07777); if (!error) { /* set owner attribute and times; access permissions allready set on creation.*/ notok = chown(fulldstname, stat.st_uid, stat.st_gid); if (notok && (udf_verbose > UDF_VERBLEV_ACTIONS)) fprintf(stderr, "failed to set owner of directory, ignoring\n"); TIMESPEC_TO_TIMEVAL(×[0], &stat.st_atimespec); /* access time */ TIMESPEC_TO_TIMEVAL(×[1], &stat.st_mtimespec); /* modification time */ notok = utimes(fulldstname, times); if (notok) fprintf(stderr, "failed to set times on directory, ignoring\n"); } if (error) fprintf(stderr, "While creating directory `%s' : %s\n", fulldstname, strerror(errno)); return 0; } /* terminal file node; setting mode correctly */ fileh = open(fulldstname, O_WRONLY | O_CREAT | O_TRUNC, udf_node->stat.st_mode); if (fileh >= 0) { file_length = udf_node->stat.st_size; file_block_size = 256*1024; /* block read in length */ file_block = malloc(file_block_size); if (!file_block) { printf("Out of memory claiming file buffer\n"); return ENOMEM; } /* move to uio_newuio(struct uio *uio) with fixed length uio_iovcnt? */ bzero(&file_uio, sizeof(struct uio)); file_uio.uio_rw = UIO_WRITE; /* WRITE into this space */ file_uio.uio_iovcnt = 1; file_uio.uio_iov = &file_iov; start = getmtime(); then = now = start; eta = data_transfered = 0; strcpy(avg_txt, "---"); strcpy(cur_txt, "---"); strcpy(eta_txt, "---"); file_uio.uio_offset = 0; /* begin at the start */ do { /* fill in IO vector space; reuse blob file_block over and over */ file_transfer_size = MIN(file_block_size, file_length - file_uio.uio_offset); file_uio.uio_resid = file_transfer_size; file_uio.uio_iov->iov_base = file_block; file_uio.uio_iov->iov_len = file_block_size; error = udf_read_file_part_uio(udf_node, fullsrcname, UDF_C_USERDATA, &file_uio); if (error) { fprintf(stderr, "While retrieving file block : %s\n", strerror(error)); printf("\n\n\n"); /* XXX */ break; } written = write(fileh, file_block, file_transfer_size); assert(written == file_transfer_size); if ((getmtime() - now > 1000000) || ((uint64_t) file_uio.uio_offset >= file_length)) { if (strlen(fulldstname) < 45) { printf("\r%-45s ", fulldstname); } else { printf("\r...%-42s ", fulldstname + strlen(fulldstname)-42); } printf("%10"PRIu64" / %10"PRIu64" bytes ", (uint64_t) file_uio.uio_offset, (uint64_t) file_length); if (file_length) printf("(%3d%%) ", (int) (100.0*(float) file_uio.uio_offset / file_length)); then = now; now = getmtime(); cur_speed = 0; avg_speed = 0; if (now-start > 0) avg_speed = (1000000 * file_uio.uio_offset) / (now-start); if (now-then > 0) cur_speed = (1000000 * (file_uio.uio_offset - data_transfered)) / (now-then); if (avg_speed > 0) eta = (file_length - file_uio.uio_offset) / avg_speed; data_transfered = file_uio.uio_offset; strcpy(avg_txt, "---"); strcpy(cur_txt, "---"); strcpy(eta_txt, "---"); if (avg_speed > 0) sprintf(avg_txt, "%d", (int32_t) avg_speed/1000); if (cur_speed > 0) sprintf(cur_txt, "%d", (int32_t) cur_speed/1000); if (eta > 0) sprintf(eta_txt, "%02d:%02d:%02d", (int) (eta/3600), (int) (eta/60) % 60, (int) eta % 60); printf("%6s KB/s (%6s KB/s) ETA %s", avg_txt, cur_txt, eta_txt); fflush(stdout); } } while ((uint64_t) file_uio.uio_offset < file_length); printf(" finished\n"); free(file_block); /* set owner attribute and times; access permissions allready set on creation.*/ notok = fchown(fileh, stat.st_uid, stat.st_gid); if (notok && (udf_verbose > UDF_VERBLEV_ACTIONS)) fprintf(stderr, "failed to set owner of file, ignoring\n"); TIMESPEC_TO_TIMEVAL(×[0], &stat.st_atimespec); /* access time */ TIMESPEC_TO_TIMEVAL(×[1], &stat.st_mtimespec); /* modification time */ notok = futimes(fileh, times); if (notok) fprintf(stderr, "failed to set times on directory, ignoring\n"); close(fileh); } else { printf("Help! can't open file %s for output\n", fulldstname); } return error; } #define GET_SUBTREE_DIR_BUFFER_SIZE (16*1024) void udfclient_get_subtree(struct udf_node *udf_node, char *srcprefix, char *dstprefix, int recurse, uint64_t *total_size) { struct uio dir_uio; struct iovec dir_iovec; uint8_t *buffer; uint32_t pos; char fullsrcpath[1024], fulldstpath[1024]; /* XXX arbitrary length XXX */ struct dirent *dirent; struct stat stat; struct udf_node *entry_node; struct fileid_desc *fid; struct long_ad udf_icbptr; int lb_size, eof; int found, isdot, isdotdot, error; if (!udf_node) return; udf_node->hold++; error = udfclient_getattr(udf_node, &stat); if ((stat.st_mode & S_IFDIR) && recurse) { buffer = malloc(GET_SUBTREE_DIR_BUFFER_SIZE); if (!buffer) { udf_node->hold--; return; } lb_size = udf_node->udf_log_vol->lb_size; fid = malloc(lb_size); assert(fid); /* recurse into this directory */ dir_uio.uio_offset = 0; /* begin at start */ do { dir_iovec.iov_base = buffer; dir_iovec.iov_len = GET_SUBTREE_DIR_BUFFER_SIZE; dir_uio.uio_resid = GET_SUBTREE_DIR_BUFFER_SIZE; dir_uio.uio_iovcnt = 1; dir_uio.uio_iov = &dir_iovec; dir_uio.uio_rw = UIO_WRITE; error = udf_readdir(udf_node, &dir_uio, &eof); pos = 0; while (pos < GET_SUBTREE_DIR_BUFFER_SIZE - dir_uio.uio_resid) { dirent = (struct dirent *) (buffer + pos); sprintf(fullsrcpath, "%s/%s", srcprefix, dirent->d_name); sprintf(fulldstpath, "%s/%s", dstprefix, dirent->d_name); /* looking for '.' or '..' ? */ isdot = (strcmp(dirent->d_name, "." ) == 0); isdotdot = (strcmp(dirent->d_name, "..") == 0); pos += sizeof(struct dirent); /* XXX variable size dirents possible XXX */ if (isdotdot) continue; if (isdot) { /* hack */ udfclient_get_subtree(udf_node, fullsrcpath, fulldstpath, 0, total_size); continue; } error = udf_lookup_name_in_dir(udf_node, dirent->d_name, DIRENT_NAMLEN(dirent), &udf_icbptr, fid, &found); if (!error) { error = ENOENT; if (found) error = udf_readin_udf_node(udf_node, &udf_icbptr, fid, &entry_node); } if (!error) udfclient_get_subtree(entry_node, fullsrcpath, fulldstpath, 1, total_size); } } while (!eof); udf_node->hold--; free(buffer); free(fid); return; } /* leaf node : prefix is complete name but with `/' prefix */ if (*srcprefix == '/') srcprefix++; error = udfclient_get_file(udf_node, srcprefix, dstprefix); udf_node->hold--; if (!error) *total_size += udf_node->stat.st_size; } #undef GET_SUBTREE_DIR_BUFFER_SIZE void udfclient_get(int args, char *arg1, char *arg2) { struct udf_node *udf_node; char *source_name, *target_name; uint64_t start, now, totalsize, avg_speed; int error; if (args > 2) { printf("Syntax: get remote [local]\n"); return; } source_name = arg1; target_name = arg1; if (args == 2) target_name = arg2; /* source name gets substituted */ source_name = udfclient_realpath(curdir.name, source_name, NULL); DEBUG(printf("Attempting to retrieve %s\n", source_name)); error = udfclient_lookup_pathname(NULL, &udf_node, source_name); if (error) { fprintf(stderr, "%s : %s\n", arg1, strerror(error)); free(source_name); return; } /* get the file/dir tree */ totalsize = 0; start = getmtime(); udfclient_get_subtree(udf_node, source_name, target_name, 1, &totalsize); now = getmtime(); if (now-start > 0) { avg_speed = (1000000 * totalsize) / (now-start); printf("A total of %d kb transfered at an overal average of %d kb/sec\n", (uint32_t) (totalsize/1024), (uint32_t) (avg_speed/1024)); } else { printf("Transfered %d kb\n", (uint32_t)(totalsize/1024)); } /* bugalert: not releasing target_name for its not substituted */ free(source_name); } void udfclient_mget(int args, char *argv[]) { struct udf_node *udf_node; uint64_t start, now, totalsize, avg_speed; char *node_name, *source_name, *target_name; int arg, error; if (args == 0) { printf("Syntax: mget (file | dir)*\n"); return; } /* retrieve the series of file/dir trees and measure time/seed */ totalsize = 0; start = getmtime(); /* process all args */ arg = 0; node_name = NULL; while (args) { source_name = target_name = argv[arg]; node_name = udfclient_realpath(curdir.name, source_name, NULL); DEBUG(printf("Attempting to retrieve %s\n", node_name)); error = udfclient_lookup_pathname(NULL, &udf_node, node_name); printf("%d: mget trying %s\n", error, node_name); if (!error) { udfclient_get_subtree(udf_node, source_name, target_name, 1, &totalsize); } if (node_name) { free(node_name); node_name = NULL; } if (error) break; /* TODO continuation flag? */ /* advance */ arg++; args--; } now = getmtime(); if (now-start > 0) { avg_speed = (1000000 * totalsize) / (now-start); printf("A total of %d kb transfered at an overal average of %d kb/sec\n", (uint32_t) (totalsize/1024), (uint32_t) (avg_speed/1024)); } else { printf("Transfered %d kb\n", (uint32_t) (totalsize/1024)); } if (node_name) free(node_name); } int udfclient_put_file(struct udf_node *udf_node, char *fullsrcname, char *fulldstname) { struct uio file_uio; struct iovec file_iov; uint64_t file_length; uint64_t start, now, then, eta; uint64_t cur_speed, avg_speed, data_transfered; uint64_t file_block_size, file_transfer_size; uint8_t *file_block; char cur_txt[32], avg_txt[32], eta_txt[32]; int fileh; int error, printed; assert(udf_node); assert(fullsrcname); DEBUG(printf("Attempting to write %s\n", fullsrcname)); fileh = open(fullsrcname, O_RDONLY, 0666); if (fileh == -1) { fprintf(stderr, "Can't open local file %s for reading: %s\n", fullsrcname, strerror(errno)); return ENOENT; } /* get file length */ file_length = lseek(fileh, 0, SEEK_END); lseek(fileh, 0, SEEK_SET); /* check if file will fit; give it a bit of slack space until the space issue is found and fixed */ if (udf_node->udf_log_vol->free_space < file_length + udf_node->udf_log_vol->await_alloc_space + UDF_MINFREE_LOGVOL) { return ENOSPC; } /* allocate file block to transfer file with */ file_block_size = 128*1024; file_block = malloc(file_block_size); if (!file_block) { fprintf(stderr, "Out of memory claiming file buffer\n"); return ENOMEM; } /* move to uio_newuio(struct uio *uio) with fixed length uio_iovcnt? */ bzero(&file_uio, sizeof(struct uio)); file_uio.uio_rw = UIO_READ; /* READ from this space */ file_uio.uio_iovcnt = 1; file_uio.uio_iov = &file_iov; /* ------------ */ start = getmtime(); then = now = start; eta = data_transfered = 0; printed = 0; strcpy(avg_txt, "---"); strcpy(cur_txt, "---"); strcpy(eta_txt, "---"); /* ------------ */ error = 0; error = udf_truncate_node(udf_node, 0); while (!error && ((uint64_t) file_uio.uio_offset < file_length)) { file_transfer_size = MIN(file_block_size, file_length - file_uio.uio_offset); error = read(fileh, file_block, file_transfer_size); if (error<0) { fprintf(stderr, "While reading in file block for writing : %s\n", strerror(errno)); error = errno; break; } file_uio.uio_resid = file_transfer_size; file_uio.uio_iov->iov_base = file_block; file_uio.uio_iov->iov_len = file_block_size; error = udf_write_file_part_uio(udf_node, fullsrcname, UDF_C_USERDATA, &file_uio); if (error) { fprintf(stderr, "\nError while writing file : %s\n", strerror(error)); break; } /* ------------ */ if ((getmtime() - now > 1000000) || ((uint64_t) file_uio.uio_offset >= file_length)) { printed = 1; if (strlen(fulldstname) < 45) { printf("\r%-45s ", fulldstname); } else { printf("\r...%-42s ", fulldstname+strlen(fulldstname)-42); } printf("%10"PRIu64" / %10"PRIu64" bytes ", (uint64_t) file_uio.uio_offset, (uint64_t) file_length); if (file_length) printf("(%3d%%) ", (int) (100.0*(float) file_uio.uio_offset / file_length)); then = now; now = getmtime(); cur_speed = 0; avg_speed = 0; if (now-start > 0) avg_speed = (1000000 * file_uio.uio_offset) / (now-start); if (now-then > 0) cur_speed = (1000000 * (file_uio.uio_offset - data_transfered)) / (now-then); if (avg_speed > 0) eta = (file_length - file_uio.uio_offset) / avg_speed; data_transfered = file_uio.uio_offset; strcpy(avg_txt, "---"); strcpy(cur_txt, "---"); strcpy(eta_txt, "---"); if (avg_speed > 0) sprintf(avg_txt, "%d", (int32_t) avg_speed/1024); if (cur_speed > 0) sprintf(cur_txt, "%d", (int32_t) cur_speed/1024); if (eta > 0) sprintf(eta_txt, "%02d:%02d:%02d", (int) (eta/3600), (int) (eta/60) % 60, (int) eta % 60); printf("%6s KB/s (%6s KB/s) ETA %s", avg_txt, cur_txt, eta_txt); fflush(stdout); } /* ------------ */ } if (!error && printed) printf(" finished\n"); close(fileh); free(file_block); return error; } int udfclient_put_subtree(struct udf_node *parent_node, char *srcprefix, char *srcname, char *dstprefix, char *dstname, uint64_t *totalsize) { struct udf_node *file_node, *dir_node; struct dirent *dirent; struct stat stat; DIR *dir; char fullsrcpath[1024], fulldstpath[1024]; int error; sprintf(fullsrcpath, "%s/%s", srcprefix, srcname); sprintf(fulldstpath, "%s/%s", dstprefix, dstname); /* stat source file */ bzero(&stat, sizeof(struct stat)); error = lstat(fullsrcpath, &stat); if (error) { error = errno; /* lstat symantics; returns -1 on error */ fprintf(stderr, "Can't stat file/dir \"%s\"! : %s\n", fullsrcpath, strerror(error)); return error; } /* test if `srcname' refers to a directory */ dir = opendir(fullsrcpath); if (dir) { error = udfclient_lookup(parent_node, &dir_node, dstname); if (error) { DEBUG(printf("Create dir %s on UDF\n", fulldstpath)); error = udf_create_directory(parent_node, dstname, &stat, &dir_node); if (error) { closedir(dir); fprintf(stderr, "UDF: couldn't create new directory %s : %s\n", dstname, strerror(error)); return error; } } dir_node->hold++; dirent = readdir(dir); while (dirent) { if (strcmp(dirent->d_name, ".") && strcmp(dirent->d_name, "..")) { /* skip `.' and ',,' */ error = udfclient_put_subtree(dir_node, fullsrcpath, dirent->d_name, fulldstpath, dirent->d_name, totalsize); if (error) break; } dirent = readdir(dir); } closedir(dir); dir_node->hold--; return error; } /* leaf node : prefix is complete name but with `/' prefix */ DEBUG(printf("Put leaf: %s\n", fulldstpath)); error = udfclient_lookup(parent_node, &file_node, dstname); if (!file_node) { error = udf_create_file(parent_node, dstname, &stat, &file_node); if (error) { fprintf(stderr, "UDF: couldn't add new file entry in directory %s for %s : %s\n", dstprefix, dstname, strerror(error)); return error; } } file_node->hold++; error = udfclient_put_file(file_node, fullsrcpath, fulldstpath); file_node->hold--; if (error) fprintf(stderr, "UDF: Couldn't write file %s : %s\n", fulldstpath, strerror(error)); if (error) udf_remove_file(parent_node, file_node, dstname); if (!error) *totalsize += file_node->stat.st_size; return error; } void udfclient_put(int args, char *arg1, char *arg2) { struct udf_node *curdir_node; uint64_t start, now, totalsize, avg_speed; char *source_name, *target_name; int error; if (args > 2) { printf("Syntax: put source [destination]\n"); return; } if (read_only) { printf("Modifying this filingsystem is prevented; use -W flag to enable writing on your own risk!\n"); return; } error = udfclient_lookup_pathname(NULL, &curdir_node, curdir.name); if (error) { printf("Current directory not found?\n"); return; } DEBUG(printf("Attempting to copy %s\n", arg1)); /* determine source and destination entities */ source_name = arg1; target_name = arg1; if (args == 2) target_name = arg2; /* writeout file/dir tree and measure the time/speed */ totalsize = 0; start = getmtime(); error = udfclient_put_subtree(curdir_node, ".", source_name, ".", target_name, &totalsize); now = getmtime(); if (now-start > 0) { avg_speed = (1000000 * totalsize) / (now-start); printf("A total of %d kb transfered at an overal average of %d kb/sec\n", (uint32_t) (totalsize/1024), (uint32_t) (avg_speed/1024)); } else { printf("Transfered %d kb\n", (uint32_t) (totalsize/1024)); } } /* args start at position 0 of argv */ void udfclient_mput(int args, char **argv) { struct udf_node *curdir_node; uint64_t start, now, totalsize, avg_speed; char *source_name, *target_name; int arg, error; if (args == 0) { printf("Syntax: mput (file | dir)*\n"); return; } if (read_only) { printf("Modifying this filingsystem is prevented; use -W flag to enable writing on your own risk!\n"); return; } error = udfclient_lookup_pathname(NULL, &curdir_node, curdir.name); if (error) { printf("Current directory not found?\n"); return; } /* writeout file/dir trees and measure the time/speed */ totalsize = 0; start = getmtime(); /* process all args */ arg = 0; while (args) { source_name = target_name = argv[arg]; error = udfclient_put_subtree(curdir_node, ".", source_name, ".", target_name, &totalsize); if (error) { fprintf(stderr, "While writing file %s : %s\n", source_name, strerror(error)); break; /* TODO continuation flag? */ } /* advance */ arg++; args--; } now = getmtime(); if (now-start > 0) { avg_speed = (1000000 * totalsize) / (now-start); printf("A total of %d kb transfered at an overal average of %d kb/sec\n", (uint32_t)(totalsize/1024), (uint32_t)(avg_speed/1024)); } else { printf("Transfered %d kb\n", (uint32_t)(totalsize/1024)); } } void udfclient_trunc(int args, char *arg1, char *arg2) { struct udf_node *udf_node; char *node_name; uint64_t length; int error; if (args != 2) { printf("Syntax: trunc file length\n"); return; } length = strtoll(arg2, NULL, 10); node_name = udfclient_realpath(curdir.name, arg1, NULL); error = udfclient_lookup_pathname(NULL, &udf_node, node_name); if (error || !udf_node) { printf("Can only truncate existing file!\n"); free(node_name); return; } udf_truncate_node(udf_node, length); free(node_name); } void udfclient_sync(void) { struct udf_discinfo *udf_disc; SLIST_FOREACH(udf_disc, &udf_discs_list, next_disc) { udf_sync_disc(udf_disc); } } #define RM_SUBTREE_DIR_BUFFER_SIZE (32*1024) int udfclient_rm_subtree(struct udf_node *parent_node, struct udf_node *dir_node, char *name, char *full_parent_name) { struct uio dir_uio; struct iovec dir_iovec; uint8_t *buffer; uint32_t pos; char *fullpath; struct dirent *dirent; struct stat stat; struct udf_node *entry_node; struct fileid_desc *fid; struct long_ad udf_icbptr; int lb_size, eof, found, isdot, isdotdot; int error; if (!dir_node) return ENOENT; error = udfclient_getattr(dir_node, &stat); if (stat.st_mode & S_IFDIR) { buffer = malloc(RM_SUBTREE_DIR_BUFFER_SIZE); if (!buffer) return ENOSPC; lb_size = dir_node->udf_log_vol->lb_size; fid = malloc(lb_size); if (!fid) { free(buffer); return ENOSPC; } /* recurse into this directory */ dir_uio.uio_offset = 0; /* begin at start */ do { dir_iovec.iov_base = buffer; dir_iovec.iov_len = RM_SUBTREE_DIR_BUFFER_SIZE; dir_uio.uio_resid = RM_SUBTREE_DIR_BUFFER_SIZE; dir_uio.uio_iovcnt = 1; dir_uio.uio_iov = &dir_iovec; dir_uio.uio_rw = UIO_WRITE; error = udf_readdir(dir_node, &dir_uio, &eof); pos = 0; while (pos < RM_SUBTREE_DIR_BUFFER_SIZE - dir_uio.uio_resid) { dirent = (struct dirent *) (buffer + pos); pos += sizeof(struct dirent); /* XXX variable size dirents possible XXX */ /* looking for '.' or '..' ? */ isdot = (strcmp(dirent->d_name, "." ) == 0); isdotdot = (strcmp(dirent->d_name, "..") == 0); if (isdot || isdotdot) continue; error = udf_lookup_name_in_dir(dir_node, dirent->d_name, DIRENT_NAMLEN(dirent), &udf_icbptr, fid, &found); if (!error) { error = ENOENT; if (found) error = udf_readin_udf_node(dir_node, &udf_icbptr, fid, &entry_node); } if (error) break; error = udfclient_getattr(entry_node, &stat); if (error) break; /* check if the direntry is a directory or a file */ if (stat.st_mode & S_IFDIR) { fullpath = malloc(strlen(full_parent_name) + strlen(dirent->d_name)+2); if (fullpath) { sprintf(fullpath, "%s/%s", full_parent_name, dirent->d_name); error = udfclient_rm_subtree(dir_node, entry_node, dirent->d_name, fullpath); } else { error = ENOMEM; } free(fullpath); } else { error = udf_remove_file(dir_node, entry_node, dirent->d_name); if (!error) printf("rm %s/%s\n", full_parent_name, dirent->d_name); } if (error) break; } } while (!eof); free(buffer); free(fid); /* leaving directory -> delete directory itself */ if (!error) { error = udf_remove_directory(parent_node, dir_node, name); if (!error) printf("rmdir %s/%s\n", full_parent_name, name); } return error; } return ENOTDIR; } #undef RM_SUBTREE_DIR_BUFFER_SIZE void udfclient_rm(int args, char *argv[]) { struct udf_node *remove_node, *parent_node; struct stat stat; char *target_name, *leaf_name, *full_parent_name; int error, len, arg; if (args == 0) { printf("Syntax: rm (file | dir)*\n"); return; } /* process all args; effectively multiplying an `rm' command */ arg = 0; while (args) { leaf_name = argv[arg]; /* lookup node; target_name gets substituted */ target_name = udfclient_realpath(curdir.name, leaf_name, &leaf_name); error = udfclient_lookup_pathname(NULL, &remove_node, target_name); if (error || !remove_node) { printf("rm %s : %s\n", target_name, strerror(error)); free(target_name); return; /* TODO continuation flag */ /* continue; */ } full_parent_name = udfclient_realpath(target_name, "..", NULL); error = udfclient_lookup_pathname(NULL, &parent_node, full_parent_name); if (error || !parent_node) { printf("rm %s : parent lookup failed : %s\n", target_name, strerror(error)); free(target_name); free(full_parent_name); return; /* TODO continuation flag */ /* continue; */ } error = udfclient_getattr(remove_node, &stat); if (!error) { if (stat.st_mode & S_IFDIR) { len = strlen(target_name); if (target_name[len-1] == '/') target_name[len-1] = '\0'; error = udfclient_rm_subtree(parent_node, remove_node, leaf_name, target_name); } else { error = udf_remove_file(parent_node, remove_node, leaf_name); if (!error) printf("rm %s/%s\n", full_parent_name, leaf_name); } } if (error) fprintf(stderr, "While removing file/dir : %s\n", strerror(error)); free(target_name); free(full_parent_name); if (error) break; /* TODO continuation flag */ /* advance */ arg++; args--; } } void udfclient_mv(int args, char *from, char *to) { struct udf_node *rename_me, *present, *old_parent, *new_parent; char *rename_from_name, *rename_to_name, *old_parent_name, *new_parent_name; int error; if (args != 2) { printf("Syntax: mv source destination\n"); return; } /* `from' gets substituted by its leaf name */ rename_from_name = udfclient_realpath(curdir.name, from, &from); error = udfclient_lookup_pathname(NULL, &rename_me, rename_from_name); if (error || !rename_me) { printf("Can't find file/dir to be renamed\n"); free(rename_from_name); return; } old_parent_name = udfclient_realpath(rename_from_name, "..", NULL); error = udfclient_lookup_pathname(NULL, &old_parent, old_parent_name); if (error || !old_parent) { printf("Can't determine rootdir of renamed file?\n"); free(rename_from_name); free(old_parent_name); return; } /* `to' gets substituted by its leaf name */ rename_to_name = udfclient_realpath(curdir.name, to, &to); udfclient_lookup_pathname(NULL, &present, rename_to_name); new_parent_name = udfclient_realpath(rename_to_name, "..", NULL); error = udfclient_lookup_pathname(NULL, &new_parent, new_parent_name); if (error || !new_parent) { printf("Can't determine rootdir of destination\n"); free(rename_from_name); free(rename_to_name); free(old_parent_name); free(new_parent_name); return; } error = udf_rename(old_parent, rename_me, from, new_parent, present, to); if (error) { printf("Can't move file or directory: %s\n", strerror(error)); return; } free(rename_from_name); free(rename_to_name); free(old_parent_name); free(new_parent_name); } void udfclient_mkdir(int args, char *arg1) { struct stat stat; struct udf_node *udf_node, *parent_node; char *full_create_name, *dirname, *parent_name; int error; if (args != 1) { printf("Syntax: mkdir dir\n"); return; } /* get full name of dir to be created */ full_create_name = udfclient_realpath(curdir.name, arg1, &dirname); parent_name = udfclient_realpath(full_create_name, "..", NULL); error = udfclient_lookup_pathname(NULL, &parent_node, parent_name); if (error || !parent_node) { printf("Can't determine directory the new directory needs to be created in %d <%s> <%s> <%s>\n", error, parent_name, full_create_name, curdir.name); free(full_create_name); free(parent_name); return; } bzero(&stat, sizeof(struct stat)); stat.st_uid = UINT_MAX; stat.st_gid = UINT_MAX; stat.st_mode = 0755 | S_IFDIR; /* don't forget this! */ error = udf_create_directory(parent_node, dirname, &stat, &udf_node); if (error) { printf("Can't create directory %s : %s\n", arg1, strerror(error)); } free(full_create_name); free(parent_name); } /* `line' gets more and more messed up in the proces */ char *udfclient_get_one_arg(char *line, char **result) { unsigned char chr, limiter; char *end_arg; *result = NULL; /* get prepending whitespace */ while (*line && (*line <= ' ')) line++; chr= '\0'; limiter = ' '; if (*line == '"') { line++; limiter = '"'; } *result = line; while (*line) { chr = *line; if (chr && (chr < ' ')) chr = ' '; if (chr == 0 || chr == limiter) { break; } else { *line = chr; } line++; } end_arg = line; if (chr == limiter) line++; /* get appended whitespace */ while (*line && (*line <= ' ')) line++; *end_arg = 0; return line; } int udfclient_get_args(char *line, char *argv[]) { int arg, args; for (arg = 0; arg < MAX_ARGS+1; arg++) { argv[arg] = ""; } /* get all arguments */ args = 0; while (args < MAX_ARGS+1) { line = udfclient_get_one_arg(line, &argv[args]); args++; if (!*line) { return args; } } printf("UDFclient implementation limit: too many arguments\n"); return 0; } void udfclient_interact(void) { int args, params; char *cmd; char *argv[MAX_ARGS+1]; char line[4096]; udfclient_pwd(0); while (1) { printf("UDF> "); clearerr(stdin); *line = 0; (void) fgets(line, 4096, stdin); if ((*line == 0) && feof(stdin)) { printf("quit\n"); return; } args = udfclient_get_args(line, argv); cmd = argv[0]; params = args -1; if (args) { if (strcmp(cmd, "")==0) continue; if (strcmp(cmd, "ls")==0) { udfclient_ls(params, argv[1]); continue; } if (strcmp(cmd, "cd")==0) { udfclient_cd(params, argv[1]); continue; } if (strcmp(cmd, "lcd")==0) { udfclient_lcd(params, argv[1]); continue; } if (strcmp(cmd, "lls")==0) { udfclient_lls(params); continue; } if (strcmp(cmd, "pwd")==0) { udfclient_pwd(params); continue; } if (strcmp(cmd, "free")==0) { udfclient_free(params); continue; } if (strcmp(cmd, "get")==0) { udfclient_get(params, argv[1], argv[2]); continue; } if (strcmp(cmd, "mget")==0) { udfclient_mget(params, argv + 1); continue; } if (strcmp(cmd, "put")==0) { /* can get destination file/dir (one day) */ udfclient_put(params, argv[1], argv[2]); continue; } if (strcmp(cmd, "mput")==0) { udfclient_mput(params, argv + 1); continue; } if (strcmp(cmd, "trunc")==0) { udfclient_trunc(params, argv[1], argv[2]); continue; } if (strcmp(cmd, "mkdir")==0) { udfclient_mkdir(params, argv[1]); continue; } if (strcmp(cmd, "rm")==0) { udfclient_rm(params, argv + 1); continue; } if (strcmp(cmd, "mv")==0) { udfclient_mv(params, argv[1], argv[2]); continue; } if (strcmp(cmd, "sync")==0) { udfclient_sync(); continue; } if (strcmp(cmd, "help")==0) { printf("Selected commands available (use \" pair for filenames with spaces) :\n" "ls [file | dir]\tlists the UDF directory\n" "cd [dir]\t\tchange current UDF directory\n" "lcd [dir]\t\tchange current directory\n" "lls\t\t\tlists current directory\n" "pwd\t\t\tdisplay current directories\n" "free\t\t\tdisplay free space on disc\n" "get source [dest]\tretrieve a file / directory from disc\n" "mget (file | dir)*\tretrieve set of files / directories\n" "put source [dest]\twrite a file / directory to disc\n" "mput (file | dir)*\twrite a set of files / directories\n" "trunc file length\ttrunc file to length\n" "mkdir dir\t\tcreate directory\n" "rm (file | dir)*\tdelete set of files / directories\n" "mv source dest\t\trename a file (limited)\n" "sync\t\t\tsync filingsystem\n" "quit\t\t\texits program\n" "exit\t\t\talias for quit\n" ); continue; } if (strcmp(cmd, "quit")==0 || strcmp(cmd, "exit")==0) { return; } printf("\nUnknown command %s\n", cmd); } } } int usage(char *program) { fprintf(stderr, "Usage: %s [options] devicename [devicename]*)\n", program); fprintf(stderr, "-u level UDF system verbose level\n" "-r range use only selected sessions like -3,5,7 or 6-\n" "-W allow writing (temporary flag)\n" "-F force mount writable when marked dirty (use with cause)\n" "-b blocksize use alternative sectorsize; use only on files/discs\n" "-D debug/verbose SCSI command errors\n" "-s byteswap read sectors (for PVRs)\n" ); return 1; } extern char *optarg; extern int optind; extern int optreset; int main(int argc, char *argv[]) { struct udf_discinfo *disc, *next_disc; uint32_t alt_sector_size; char *progname, *range; int flag, mnt_flags; int error; progname = argv[0]; if (argc == 1) { return usage(progname); } /* be a bit more verbose */ udf_verbose = UDF_VERBLEV_ACTIONS; uscsilib_verbose= 0; mnt_flags = UDF_MNT_RDONLY; range = NULL; alt_sector_size = 0; while ((flag = getopt(argc, argv, "u:Dr:WFb:s")) != -1) { switch (flag) { case 'u' : udf_verbose = atoi(optarg); break; case 'D' : uscsilib_verbose = 1; break; case 'r' : range = strdup(optarg); if (udf_check_session_range(range)) { fprintf(stderr, "Invalid range %s\n", range); return usage(progname); } break; case 'W' : mnt_flags &= ~UDF_MNT_RDONLY; break; case 'F' : mnt_flags |= UDF_MNT_FORCE; break; case 'b' : alt_sector_size = atoi(optarg); break; case 's' : mnt_flags |= UDF_MNT_BSWAP; break; default : return usage(progname); } } argv += optind; argc -= optind; if (argc == 0) return usage(progname); if (!(mnt_flags & UDF_MNT_RDONLY)) { printf("--------------------------------\n"); printf("WARNING: writing enabled, use on own risc\n"); printf("\t* DONT cancel program or data-loss might occure\n"); printf("\t* set dataspace userlimits very high when writing thousands of files\n"); printf("\nEnjoy your writing!\n"); printf("--------------------------------\n\n\n"); printf("%c", 7); fflush(stdout); sleep(1); printf("%c", 7); fflush(stdout); sleep(1); printf("%c", 7); fflush(stdout); } /* all other arguments are devices */ udf_init(); while (argc) { printf("Opening device %s\n", *argv); error = udf_mount_disc(*argv, range, alt_sector_size, mnt_flags, &disc); if (error) { fprintf(stderr, "Can't open my device; bailing out : %s\n", strerror(error)); exit(1); } if (read_only) disc->recordable = 0; if (read_only) disc->rewritable = 0; argv++; argc--; if (udf_verbose) printf("\n\n"); } printf("\n"); printf("Resulting list of alive sets :\n\n"); udf_dump_alive_sets(); /* interactive part */ bzero(&curdir, sizeof(struct curdir)); curdir.mountpoint = NULL; curdir.name = strdup("/"); udfclient_ls(0, ""); udfclient_interact(); /* close part */ printf("Closing discs\n"); disc = SLIST_FIRST(&udf_discs_list); while (disc) { next_disc = SLIST_NEXT(disc, next_disc); udf_dismount_disc(disc); disc = next_disc; } return 0; } UDFclient.0.8.8/defs.h010066400001470000000000000056011307041400500137530ustar reinoudwheel/* $NetBSD$ */ /* * File "udf.h" is part of the UDFclient toolkit. * File $Id: defs.h,v 1.8 2016/04/26 19:35:20 reinoud Exp $ $Name: $ * * Copyright (c) 2003, 2004, 2005, 2006, 2011 * Reinoud Zandijk * All rights reserved. * * The UDFclient toolkit is distributed under the Clarified Artistic Licence. * A copy of the licence is included in the distribution as * `LICENCE.clearified.artistic' and a copy of the licence can also be * requested at the GNU foundantion's website. * * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef _DEFS_H_ #define _DEFS_H_ #include #include #include #include #include #include #ifdef NO_INT_FMTIO /* assume 32 bits :-/ */ #ifndef PRIu32 # define PRIu32 "u" # define PRIx32 "x" # define PRIu64 "lld" # define PRIx64 "llx" #endif #endif /* exported flags */ extern int udf_verbose; #define UDF_MNT_RDONLY 1 #define UDF_MNT_FORCE 2 #define UDF_VERBLEV_NONE 0 #define UDF_VERBLEV_ACTIONS 1 #define UDF_VERBLEV_TABLES 2 #define UDF_VERBLEV_MAX 3 /* constants to identify what kind of identifier we are dealing with */ #define UDF_REGID_DOMAIN 1 #define UDF_REGID_UDF 2 #define UDF_REGID_IMPLEMENTATION 3 #define UDF_REGID_APPLICATION 4 #define UDF_REGID_NAME 99 /* 99? */ /* DON'T change these: they identify 13thmonkey's UDF toolkit */ #define APP_NAME "*UDFtoolkit" #define APP_VERSION_MAIN 0 #define APP_VERSION_SUB 8 #define IMPL_NAME "*13thMonkey UDFtoolkit" /* RW content hint for allocation and other purposes */ #define UDF_C_DSCR 0 #define UDF_C_USERDATA 1 #define UDF_C_FIDS 2 #define UDF_C_NODE 3 /* end of Configuration */ #if 1 # define UDF_VERBOSE(op) if (udf_verbose) { op; } # define UDF_VERBOSE_LEVEL(level, op) if (udf_verbose >= (level)) { op; } # define UDF_VERBOSE_TABLES(op) UDF_VERBOSE_LEVEL(UDF_VERBLEV_TABLES, op) # define UDF_VERBOSE_MAX(op) UDF_VERBOSE_LEVEL(UDF_VERBLEV_MAX, op) #else # define UDF_VERBOSE(op) # define UDF_VERBOSE_LEVEL(level, op) # define UDF_VERBOSE_TABLES(op) # define UDF_VERBOSE_MAX(op) #endif #endif /* _DEFS_H_ */ UDFclient.0.8.8/udf_readwrite.c010066400001470000000000000700731307041400500156560ustar reinoudwheel/* $NetBSD$ */ /* * File "udf_readwrite.c" is part of the UDFclient toolkit. * File $Id: udf_readwrite.c,v 1.50 2016/04/25 21:01:40 reinoud Exp $ $Name: $ * * Copyright (c) 2003, 2004, 2005, 2006, 2011 * Reinoud Zandijk * All rights reserved. * * The UDFclient toolkit is distributed under the Clarified Artistic Licence. * A copy of the licence is included in the distribution as * `LICENCE.clearified.artistic' and a copy of the licence can also be * requested at the GNU foundantion's website. * * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* XXX strip list to bare minimum XXX */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "uscsilib.h" /* for locals */ #include "udf.h" #include "udf_bswap.h" #include "udf_discop.h" #include "uio.h" #include #ifndef MAX # define MAX(a,b) ((a)>(b)?(a):(b)) # define MIN(a,b) ((a)<(b)?(a):(b)) #endif /* #define DEBUG(a) { a; } */ #define DEBUG(a) if (0) { a; } /* predefines */ #if 1 extern void udf_dump_descriptor(union dscrptr *dscrpt); #else void udf_dump_descriptor(union dscrptr *dscrptr) {} #endif int udf_writeout_session_cache(struct udf_session *udf_session); /****************************************************************************************** * * Session-cache init and syncing * ******************************************************************************************/ int udf_init_session_caches(struct udf_session *udf_session) { uint32_t sector_size; sector_size = udf_session->disc->sector_size; UDF_MUTEX_INIT(&udf_session->session_cache_lock); udf_session->cache_line_read = malloc(UDF_READWRITE_LINE_LENGTH * sector_size); udf_session->cache_line_write = malloc(UDF_READWRITE_LINE_LENGTH * sector_size); assert(udf_session->cache_line_read); assert(udf_session->cache_line_write); bzero(udf_session->cache_write_callbacks, UDF_READWRITE_LINE_LENGTH * sizeof(struct udf_wrcallback)); return 0; } void udf_sync_session_cache(struct udf_session *udf_session) { UDF_MUTEX_LOCK(&udf_session->session_cache_lock); /* hmm... have to write out current write-cache */ udf_writeout_session_cache(udf_session); UDF_MUTEX_UNLOCK(&udf_session->session_cache_lock); } int udf_sync_caches(struct udf_log_vol *udf_log_vol) { struct udf_volumeset *udf_volumeset; struct udf_partition *udf_partition; struct udf_part_mapping *udf_part_mapping; uint32_t part_num; /* XXX need to force writeout of session caches... XXX */ /* process all `partions->sessions' */ DEBUG( printf("SYNC statistics\n"); printf("\tbufcache lru_len_data %d\n", udf_bufcache->lru_len_data); printf("\tbufcache lru_len_metadata %d\n", udf_bufcache->lru_len_metadata); printf("\tbufcache claimed/released %d\n", udf_bufcache->bcnt); ); udf_volumeset = udf_log_vol->primary->volumeset; SLIST_FOREACH(udf_part_mapping, &udf_log_vol->part_mappings, next_mapping) { part_num = udf_part_mapping->udf_virt_part_num; SLIST_FOREACH(udf_partition, &udf_volumeset->parts, next_partition) { if (udf_rw16(udf_partition->partition->part_num) == part_num) { /* sync session */ DEBUG(printf("Syncing session cache for vpart %d, part %d\n", part_num, udf_partition->udf_session->session_num)); udf_sync_session_cache(udf_partition->udf_session); } } } return 0; } /****************************************************************************************** * * Session and logvol sector reading/writing (simple caching) * ******************************************************************************************/ int udf_read_session_sector(struct udf_session *udf_session, uint32_t sector, char *what, uint8_t *buffer, int prefetch_sectors, int rwflags) { uint32_t eff_sector, bit, sector_size; int32_t cache_diff; int error; rwflags = rwflags; /* unused here */ /* maximise 'prefetch_sectors' to cache line length */ prefetch_sectors = MIN(UDF_READWRITE_LINE_LENGTH, prefetch_sectors); sector_size = udf_session->disc->sector_size; /* XXX cache coherency ???? XXX */ UDF_MUTEX_LOCK(&udf_session->session_cache_lock); eff_sector = udf_session->session_offset + sector; /* snoop write cache */ cache_diff = eff_sector - udf_session->cache_line_w_start; if ((cache_diff >= 0) && (cache_diff < UDF_READWRITE_LINE_LENGTH)) { bit = (1 << cache_diff); if (udf_session->cache_line_w_present & bit) { /* return cached value */ memcpy(buffer, udf_session->cache_line_write + cache_diff * sector_size, sector_size); UDF_MUTEX_UNLOCK(&udf_session->session_cache_lock); return 0; } /* not present */ } /* check read cache */ cache_diff = eff_sector - udf_session->cache_line_r_start; if ((cache_diff >= 0) && (cache_diff < UDF_READWRITE_LINE_LENGTH)) { bit = (1 << cache_diff); if (udf_session->cache_line_r_present & bit) { /* return cached value */ memcpy(buffer, udf_session->cache_line_read + cache_diff * sector_size, sector_size); UDF_MUTEX_UNLOCK(&udf_session->session_cache_lock); return 0; } /* not present */ } /* read in from this sector on for the prefetch length */ /* XXX use `pending' and `unalloc'/`freed' allocentry queue to minimise read/write misses in streams ? XXX */ /* XXX use 3 write streams ? XXX */ error = udf_read_physical_sectors(udf_session->disc, eff_sector, prefetch_sectors, what, udf_session->cache_line_read); if (!error) { udf_session->cache_line_r_start = eff_sector; memcpy(buffer, udf_session->cache_line_read, sector_size); udf_session->cache_line_r_present = 0; for (cache_diff=0; cache_diff < prefetch_sectors; cache_diff++) { bit = (1 << cache_diff); udf_session->cache_line_r_present |= bit; } UDF_MUTEX_UNLOCK(&udf_session->session_cache_lock); return 0; } /* what now? */ DEBUG( printf("ERROR! reading chunk\n"); ); udf_session->cache_line_r_present = 0; error = udf_read_physical_sectors(udf_session->disc, eff_sector, 1, what, buffer); if (!error) { udf_session->cache_line_r_start = eff_sector; udf_session->cache_line_r_present = 1; } DEBUG( if (error) printf("ERROR reading sector %d\n", eff_sector) ); UDF_MUTEX_UNLOCK(&udf_session->session_cache_lock); return error; } int udf_writeout_session_cache(struct udf_session *udf_session) { struct udf_wrcallback *callback; uint32_t bit, error_bits, sector_size; uint32_t num_sectors; int32_t cache_diff; uint32_t start_sector; uint8_t *from, *to; int error, report_error; if (udf_session->cache_line_w_dirty == 0) return 0; error_bits = 0; sector_size = udf_session->disc->sector_size; num_sectors = UDF_READWRITE_LINE_LENGTH; start_sector = 0; error = 0; report_error = 0; if (udf_session->disc->strict_overwrite) { /* Have to do our own Read-Modify-Write :( */ assert((udf_session->cache_line_w_start % UDF_READWRITE_LINE_LENGTH) == 0); /* all present ? */ if (udf_session->cache_line_w_dirty && (udf_session->cache_line_w_present != UDF_READWRITE_ALL_PRESENT)) { /* could snoop read buffer for missed sectors */ } /* double check all present */ if (udf_session->cache_line_w_dirty && (udf_session->cache_line_w_present != UDF_READWRITE_ALL_PRESENT)) { /* read in from media :-S */ udf_session->cache_line_r_present = 0; error = udf_read_physical_sectors(udf_session->disc, udf_session->cache_line_w_start, UDF_READWRITE_LINE_LENGTH, "cache line", udf_session->cache_line_read); if (error) { /* TODO try to fix-up please */ printf("Error reading physical sectors for cache for line_w_start %d ? : %s\n", udf_session->cache_line_w_start, strerror(error)); } assert(!error); udf_session->cache_line_r_start = udf_session->cache_line_w_start; udf_session->cache_line_r_present = UDF_READWRITE_ALL_PRESENT; for (cache_diff = 0; cache_diff < UDF_READWRITE_LINE_LENGTH; cache_diff++) { bit = (1 << cache_diff); if ((udf_session->cache_line_w_present & bit) == 0) { from = udf_session->cache_line_read + cache_diff * sector_size; to = udf_session->cache_line_write + cache_diff * sector_size; memcpy(to, from, sector_size); } udf_session->cache_line_w_present |= bit; } } assert(udf_session->cache_line_w_present == UDF_READWRITE_ALL_PRESENT); } assert(udf_session->cache_line_w_dirty); if (udf_session->cache_line_w_present != UDF_READWRITE_ALL_PRESENT) { /* count number of sectors present * (SEQUENTIAL?) */ start_sector = 0; cache_diff = 0; DEBUG(printf("Writing out non complete line\n")); DEBUG(printf("present %032o\n", udf_session->cache_line_w_present)); /* write out individual sectors */ while (cache_diff < UDF_READWRITE_LINE_LENGTH) { bit = (1 << cache_diff); if (udf_session->cache_line_w_present & bit) { start_sector = cache_diff; num_sectors = 1; /* calculate memory address and disc address */ from = udf_session->cache_line_write + start_sector * sector_size; start_sector += udf_session->session_offset + udf_session->cache_line_w_start; /* write! */ error = udf_write_physical_sectors(udf_session->disc, start_sector, num_sectors, "cache line (bits)", from); if (error) { error_bits |= bit; report_error = error; } else { udf_session->cache_line_w_dirty &= ~bit; } } cache_diff++; } } else { /* All present : calculate memory address and disc address */ from = udf_session->cache_line_write + start_sector * sector_size; start_sector += udf_session->session_offset + udf_session->cache_line_w_start; /* write! */ assert(num_sectors == UDF_READWRITE_LINE_LENGTH); error = udf_write_physical_sectors(udf_session->disc, start_sector, num_sectors, "cache line", from); if (error) { error_bits = UDF_READWRITE_ALL_PRESENT; } else { udf_session->cache_line_w_dirty = 0; } report_error = error; } if (error_bits) { /* ABORT/ROLLBACK */ for (cache_diff = 0; cache_diff < UDF_READWRITE_LINE_LENGTH; cache_diff++) { bit = (1 << cache_diff); if (error_bits & bit) { from = udf_session->cache_line_write + cache_diff * sector_size; callback = &udf_session->cache_write_callbacks[cache_diff]; udf_session->cache_line_w_present &= ~bit; if (callback->function) { callback->function(UDF_WRCALLBACK_REASON_ANULATE, callback, report_error, from); } else { fprintf(stderr, "WARNING: error encountered with NULL callback function\n"); } } } } return error; } /* XXX called directly OR called by purging dirty buffers out trough VOP_STRATEGY or trough VOP_INACTIVE XXX */ int udf_write_session_sector(struct udf_session *udf_session, uint32_t sector, char *what, uint8_t *source, int rwflags, struct udf_wrcallback *wrcallback) { uint32_t eff_sector, bit, sector_size; int32_t cache_diff; int error; rwflags = rwflags; /* unused here */ what = what; /* unused for now */ assert(udf_session); assert(udf_session->cache_line_read); assert(udf_session->cache_line_write); sector_size = udf_session->disc->sector_size; /* XXX cache coherency ???? XXX */ error = 0; UDF_MUTEX_LOCK(&udf_session->session_cache_lock); eff_sector = udf_session->session_offset + sector; cache_diff = eff_sector - udf_session->cache_line_w_start; if (udf_session->cache_line_w_dirty && ((cache_diff < 0) || (cache_diff >= UDF_READWRITE_LINE_LENGTH))) { /* hmm... have to write out current write-cache */ udf_writeout_session_cache(udf_session); } if (udf_session->cache_line_w_dirty == 0) { if (udf_session->disc->strict_overwrite) { udf_session->cache_line_w_start = eff_sector & ~(UDF_READWRITE_LINE_LENGTH-1); } else { udf_session->cache_line_w_start = eff_sector; } cache_diff = eff_sector - udf_session->cache_line_w_start; udf_session->cache_line_w_present = 0; } if ((cache_diff >= 0) && (cache_diff < UDF_READWRITE_LINE_LENGTH)) { /* its in the cache range: overwrite current value */ bit = (1 << cache_diff); udf_session->cache_line_w_present |= bit; udf_session->cache_line_w_dirty |= bit; memcpy(udf_session->cache_line_write + cache_diff * sector_size, source, sector_size); if (wrcallback) memcpy(&udf_session->cache_write_callbacks[cache_diff], wrcallback, sizeof(struct udf_wrcallback)); else bzero(&udf_session->cache_write_callbacks[cache_diff], sizeof(struct udf_wrcallback)); ; UDF_MUTEX_UNLOCK(&udf_session->session_cache_lock); return 0; } UDF_MUTEX_UNLOCK(&udf_session->session_cache_lock); return error; } /* reads in 'logvol->lb_size' logical sector size bytes */ int udf_read_logvol_sector(struct udf_log_vol *udf_log_vol, uint32_t vpart_num, uint32_t lb_num, char *what, uint8_t *buffer, uint32_t prefetch_sectors, int rwflags) { struct udf_partition *udf_partition; struct udf_part_mapping *udf_part_mapping; struct udf_session *udf_session; uint64_t ses_off, trans_valid_len; uint64_t offset; uint32_t length, trans_length, trans_sectors, readahead; uint32_t lb_size, sector_size; uint32_t ses_sector, ses_offset; int error; lb_size = udf_log_vol->lb_size; sector_size = udf_log_vol->sector_size; DEBUG( printf("Read logvol space for %s, from vpart %d, lb_num %d for logical sector size %d\n", what, vpart_num, (int)lb_num, (int) lb_size); ); error = udf_logvol_vpart_to_partition(udf_log_vol, vpart_num, &udf_part_mapping, &udf_partition); if (error) return error; /* get the offset (in bytes) in the partition for translational purposes */ offset = (uint64_t) lb_num * lb_size; length = lb_size; udf_session = udf_partition->udf_session; do { trans_length = length; ses_sector = 0; /* TODO optimalisation: could use `trans_valid_len' and `prefetch_sectors' */ /* determine the translated address and its translation validity length */ error = udf_vpartoff_to_sessionoff(udf_log_vol, udf_part_mapping, udf_partition, offset, &ses_off, &trans_valid_len); if (error) break; ses_sector = ses_off / sector_size; ses_offset = ses_off % sector_size; assert(ses_offset == 0); trans_length = sector_size; trans_sectors = 1; /* estimate how much we could read-ahead given prefetch sectors and translation validation */ readahead = MIN(trans_valid_len, prefetch_sectors * lb_size); readahead = (readahead + sector_size -1) / sector_size; /* XXX could use partition_sector defs XXX */ error = udf_read_session_sector(udf_session, ses_sector, what, buffer + ses_offset, readahead, rwflags); if (error) break; /* advance to next block */ offset += trans_length; length -= trans_length; buffer += trans_length; prefetch_sectors -= trans_sectors; if (length == 0) return error; } while (length && !error); return EFAULT; } /* internal function; sector is allready a partition sector */ void udf_fillin_fids_sector(uint8_t *buffer, uint32_t *fid_pos, uint32_t max_fidpos, uint32_t sector, uint32_t sector_size) { struct fileid_desc *fid; uint32_t rfid_pos; uint32_t fid_len; assert(fid_pos); assert(buffer); rfid_pos = (*fid_pos) % sector_size; while (rfid_pos + sizeof(struct desc_tag) <= sector_size) { if ((*fid_pos) + sizeof(struct desc_tag) > max_fidpos) { return; } fid = (struct fileid_desc *) (buffer + (*fid_pos)); fid_len = udf_calc_tag_malloc_size((union dscrptr *) fid, sector_size); /* update sector number and recalculate checkum */ fid->tag.tag_loc = udf_rw32(sector); udf_validate_tag_sum((union dscrptr *) fid); *fid_pos += fid_len; rfid_pos += fid_len; } } /* writes out 'logvol->lb_size' logical sector size bytes */ /* XXX it ASSUMES that the translation is allready known/filled in (!) (offcource) XXX */ int udf_write_logvol_sector(struct udf_log_vol *udf_log_vol, uint32_t vpart_num, uint32_t lb_num, char *what, uint8_t *buffer, int rwflags, struct udf_wrcallback *wrcallback) { struct udf_partition *udf_partition; struct udf_part_mapping *udf_part_mapping; struct udf_session *udf_session; union dscrptr *dscrptr; uint64_t ses_off, trans_valid_len; uint64_t offset; uint64_t length, trans_length; uint32_t lb_size, sector_size; uint32_t ses_sector, ses_offset; uint32_t fid_pos, max_fid_pos; int error, has_fids, recalc_crc, file_type; lb_size = udf_log_vol->lb_size; sector_size = udf_log_vol->sector_size; DEBUG( printf("Write logvol space for %s, rwflags = %d, from vpart %d, lb_num %d for logical sector size %d\n", what, rwflags, vpart_num, (int)lb_num, (int) lb_size); ); error = udf_logvol_vpart_to_partition(udf_log_vol, vpart_num, &udf_part_mapping, &udf_partition); if (error) return error; /* get the offset (in bytes) in the partition for translational purposes */ offset = (uint64_t) lb_num * lb_size; length = lb_size; fid_pos = max_fid_pos = 0; has_fids = recalc_crc = 0; dscrptr = (union dscrptr *) buffer; /* doesn't have to be valid */ if (rwflags == UDF_C_FIDS) { /* FIDs in this sector need to be updated, so search the first FID by using the resync function */ DEBUG(printf("C_FIDS\n")); max_fid_pos = lb_size; udf_resync_fid_stream(buffer, &fid_pos, max_fid_pos, &has_fids); recalc_crc = 0; } if (rwflags == UDF_C_NODE) { DEBUG(printf("C_NODE\n")); /* if NODE with possibly an embedded FID stream -> have to patch up the FIDs (max one lbnum though) */ file_type = 0; if (udf_rw16(dscrptr->tag.id) == TAGID_FENTRY) { if ((udf_rw16(dscrptr->fe.icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK) == UDF_ICB_INTERN_ALLOC) { DEBUG(printf("\tINTERN FE\n")); fid_pos = (dscrptr->fe.data - buffer) + udf_rw32(dscrptr->fe.l_ea); max_fid_pos = fid_pos + udf_rw64(dscrptr->fe.inf_len); has_fids = 1; recalc_crc = 1; file_type = dscrptr->fe.icbtag.file_type; /* 8 bit */ } } else { if ((udf_rw16(dscrptr->fe.icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK) == UDF_ICB_INTERN_ALLOC) { DEBUG(printf("\tINTERN EFE\n")); fid_pos = (dscrptr->efe.data - buffer) + udf_rw32(dscrptr->efe.l_ea); max_fid_pos = fid_pos + udf_rw64(dscrptr->efe.inf_len); has_fids = 1; recalc_crc = 1; file_type = dscrptr->efe.icbtag.file_type; /* 8 bit */ } } if (!((file_type == UDF_ICB_FILETYPE_DIRECTORY) || (file_type == UDF_ICB_FILETYPE_STREAMDIR))) { has_fids = 0; } } DEBUG( if (rwflags == UDF_C_USERDATA) { printf("C_USERDATA\n"); } printf("has_fids = %d, fid_pos = %d, max_fid_pos = %d\n", has_fids, fid_pos, max_fid_pos); ); udf_session = udf_partition->udf_session; do { trans_length = length; ses_sector = 0; /* determine the translated address and its translation validity length */ error = udf_vpartoff_to_sessionoff(udf_log_vol, udf_part_mapping, udf_partition, offset, &ses_off, &trans_valid_len); if (error) break; ses_sector = ses_off / sector_size; ses_offset = ses_off % sector_size; assert(ses_offset == 0); /* FIDs need to be updated to include the correct physical sector */ if (has_fids) { udf_fillin_fids_sector(buffer, &fid_pos, max_fid_pos, lb_num, sector_size); if (recalc_crc) { udf_validate_tag_and_crc_sums(dscrptr); recalc_crc = 0; } } /* XXX optimalisation: could use more of `trans_valid_len' XXX */ trans_length = sector_size; /* XXX could use partition_sector defs XXX */ error = udf_write_session_sector(udf_session, ses_sector, what, buffer, rwflags, wrcallback); if (error) break; /* advance to next physical sector */ offset += trans_length; length -= trans_length; buffer += trans_length; /* really? */ DEBUG( printf("write logvol sector loop: recalc_crc = %d, offset = %d, length = %d, buffer = %p\n", recalc_crc, (uint32_t) offset, (uint32_t) length, buffer); ); if (length == 0) { return error; } } while (length && !error); return EFAULT; } /****************************************************************************************** * * Descriptor readers and writers * ******************************************************************************************/ /* * Read in an descriptor in either logvol space or in session space determined * by the specification of log_vol. * * In logvol space, lb_num specifies the logical block number in the logical * volume wich can be bigger than a sector. * * In session space, lb_num specifies a distinct sector. * * The function returns the read in descriptor blob and its length; it deals * with both short and long descriptors. */ int udf_read_descriptor(struct udf_log_vol *udf_log_vol, uint32_t vpart_num, struct udf_session *udf_session, uint32_t lb_num, char *what, uint32_t cache_flags, union dscrptr **dscr, uint32_t *length) { union dscrptr *cur_dscr, *new_dscr; void *sector0; uint32_t sector_size, num_sectors, sector; uint32_t cur_length, new_length; uint8_t *pos; int error; assert(dscr); if (length) *length = 0; *dscr = NULL; assert((udf_log_vol && !udf_session) || (!udf_log_vol && udf_session)); sector_size = udf_log_vol ? udf_log_vol->lb_size : (uint32_t) udf_session->disc->sector_size; /* All discriptors have a mimimum size of one sector be it logical or physical */ cur_length = sector_size; num_sectors = 1; sector0 = malloc(cur_length); cur_dscr = sector0; if (!sector0) { printf("\t\t\tOut of memory claiming memory for %s\n", what); return ENOMEM; } /* start reading in sector; read at offset 0 into the logic block */ if (udf_log_vol) { /* could read more in advance? */ error = udf_read_logvol_sector(udf_log_vol, vpart_num, lb_num, what, (uint8_t *) cur_dscr, num_sectors, cache_flags); } else { error = udf_read_session_sector(udf_session, lb_num, what, (uint8_t *) cur_dscr, num_sectors, cache_flags); } if (!error) error = udf_check_tag(cur_dscr); if (!error) { new_length = udf_calc_tag_malloc_size(cur_dscr, sector_size); DEBUG( if (new_length < (uint32_t) udf_rw16(cur_dscr->tag.desc_crc_len) + UDF_DESC_TAG_LENGTH) { printf("UDF warning: reading in %s for %d bytes but descriptor crc len is %d bytes\n", what, new_length, udf_rw16(cur_dscr->tag.desc_crc_len) + UDF_DESC_TAG_LENGTH); udf_dump_descriptor(cur_dscr); } ); if (new_length > cur_length) { /* extent the current descriptor; length is multiple of (logical or session) sector size */ num_sectors = (new_length + sector_size -1) / sector_size; new_length = num_sectors * sector_size; new_dscr = malloc(new_length); if (new_dscr) { /* copy read-in stuff into the new allocated space */ memcpy(new_dscr, sector0, cur_length); free(sector0); /* read in the additional sectors */ cur_dscr = new_dscr; cur_length = new_length; for (sector = 1; sector < num_sectors; sector++) { pos = ((uint8_t *) cur_dscr) + sector * sector_size; if (udf_log_vol) { /* could read more in advance? */ error = udf_read_logvol_sector(udf_log_vol, vpart_num, lb_num + sector, what, pos, num_sectors - sector, cache_flags); } else { error = udf_read_session_sector(udf_session, lb_num + sector, what, pos, num_sectors - sector, cache_flags); } } } else { free(sector0); } } } if (!error) { *dscr = cur_dscr; if (length) *length = cur_length; /* if requested return length */ error = udf_check_tag(*dscr); if (!error) error = udf_check_tag_payload(*dscr); } return error; } /* Reads descriptor as in currenly recorded on disc or as is in the cache */ int udf_read_session_descriptor(struct udf_session *udf_session, uint32_t lb_num, char *what, union dscrptr **dscr, uint32_t *length) { uint32_t cache_flags; cache_flags = UDF_C_DSCR; return udf_read_descriptor(NULL, 0, udf_session, lb_num, what, cache_flags, dscr, length); } /* Reads descriptor as in currenly recorded on disc or as is in the cache */ int udf_read_logvol_descriptor(struct udf_log_vol *udf_log_vol, uint32_t vpart_num, uint32_t lb_num, char *what, union dscrptr **dscr, uint32_t *length) { uint32_t cache_flags; cache_flags = UDF_C_DSCR; return udf_read_descriptor(udf_log_vol, vpart_num, NULL, lb_num, what, cache_flags, dscr, length); } static int udf_write_descriptor(struct udf_log_vol *udf_log_vol, uint32_t vpart_num, struct udf_session *udf_session, uint32_t lb_num, uint32_t dscr_lb_num, char *what, union dscrptr *dscr, struct udf_wrcallback *wrcallback) { uint32_t dscr_length; uint32_t sector_size; uint32_t sector, num_sectors; uint8_t *pos; int error, rwflags; assert(dscr); assert((udf_log_vol && !udf_session) || (!udf_log_vol && udf_session)); sector_size = udf_log_vol ? udf_log_vol->lb_size : (uint32_t) udf_session->disc->sector_size; /* All discriptors have a mimimum size of one sector be it logical or physical */ num_sectors = 1; dscr_length = udf_calc_tag_malloc_size(dscr, sector_size); /* extent the current descriptor; length is multiple of (logical or session) sector size */ num_sectors = (dscr_length + sector_size -1) / sector_size; /* set the rwflags according to what kind of descriptor we are writing */ wrcallback->flags |= UDF_WRCALLBACK_FLAG_DESCRIPTOR; /* not needed? */ rwflags = UDF_C_DSCR; if (udf_rw16(dscr->tag.id) == TAGID_FENTRY) rwflags = UDF_C_NODE; if (udf_rw16(dscr->tag.id) == TAGID_EXTFENTRY) rwflags = UDF_C_NODE; /* write out descriptor */ error = 0; if (udf_log_vol) { /* prepare descriptor for writing */ dscr->tag.tag_loc = udf_rw32(dscr_lb_num); udf_validate_tag_and_crc_sums(dscr); /* write sectors */ for (sector = 0; sector < num_sectors; sector++) { pos = ((uint8_t *) dscr) + sector * sector_size; /* wrcallback->function is given */ #if 0 wrcallback->udf_node = wrcallback->lb_num = lb_num + sector; wrcallback->length = sector_size; wrcallback->vpart_num = vpart_num; #endif DEBUG(printf("writing logical sector %8d for %s (sector offset %d)\n", lb_num + sector, what, sector)); error = udf_write_logvol_sector(udf_log_vol, vpart_num, lb_num + sector, what, pos, rwflags, wrcallback); if (error) break; } } else { /* prepare descriptor for writing */ dscr->tag.tag_loc = udf_rw32(dscr_lb_num); udf_validate_tag_and_crc_sums(dscr); /* write sectors */ for (sector = 0; sector < num_sectors; sector++) { pos = ((uint8_t *) dscr) + sector * sector_size; /* wrcallback->function is given */ #if 0 wrcallback->lb_num = lb_num; wrcallback->length = sector_size; #endif DEBUG(printf("writing sector %8d for %s (sector offset %d)\n", lb_num + sector, what, sector)); error = udf_write_session_sector(udf_session, lb_num + sector, what, pos, rwflags, wrcallback); if (error) break; } } return error; } /* Write descriptor trough cache if present */ int udf_write_session_descriptor(struct udf_session *udf_session, uint32_t lb_num, char *what, union dscrptr *dscr, struct udf_wrcallback *wrcallback) { return udf_write_descriptor(NULL, 0, udf_session, lb_num, lb_num, what, dscr, wrcallback); } int udf_write_partition_descriptor(struct udf_partition *udf_partition, uint32_t lb_num, char *what, union dscrptr *dscr, struct udf_wrcallback *wrcallback) { uint32_t dscr_lb_num; dscr_lb_num = udf_rw32(lb_num + udf_partition->partition->start_loc); return udf_write_descriptor(NULL, 0, udf_partition->udf_session, dscr_lb_num, lb_num, what, dscr, wrcallback); } /* Write descriptor trough cache if present */ int udf_write_logvol_descriptor(struct udf_log_vol *udf_log_vol, uint32_t vpart_num, uint32_t lb_num, char *what, union dscrptr *dscr, struct udf_wrcallback *wrcallback) { return udf_write_descriptor(udf_log_vol, vpart_num, NULL, lb_num, lb_num, what, dscr, wrcallback); } /* end of udf_readwrite.c */ UDFclient.0.8.8/udf_bswap.h010064400001470000000000000077001307041400500150040ustar reinoudwheel/* $NetBSD: udf_bswap.h,v 1.12 2003/04/16 14:27:03 yamt Exp $ */ /* * Copyright (c) 1998 Manuel Bouyer. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * `ported' for UDF by Reinoud Zandijk * */ #ifndef _UDF_BSWAP_H_ #define _UDF_BSWAP_H_ #if HAVE_ENDIAN_H #include #else #if HAVE_SYS_ENDIAN_H #include #else #if HAVE_MACHINE_ENDIAN_H #include #endif #endif #endif /* rest only relevant for big endian machines */ #if (BYTE_ORDER == BIG_ENDIAN) //#warning BIG ENDIAN //#if (BYTE_ORDER == LITTLE_ENDIAN) /* ENDIAN SWAP... only for testing!!!!! */ /* inlines for access to swapped data */ static __inline uint16_t udf_rw16 __P((uint16_t)); static __inline uint32_t udf_rw32 __P((uint32_t)); static __inline uint64_t udf_rw64 __P((uint64_t)); #ifdef HAVE_SYS_BSWAP_H #include #endif #ifdef HAVE_MACHINE_BSWAP_H #include #endif #if (defined(HAVE_SYS_BSWAP_H) || defined(HAVE_MACHINE_BSWAP_H)) /* bswap macro's defined */ // #warning BSWAP's defined static __inline uint16_t udf_rw16(a) uint16_t a; { return bswap16(a); } static __inline uint32_t udf_rw32(a) uint32_t a; { return bswap32(a); } static __inline uint64_t udf_rw64(a) uint64_t a; { return bswap64(a); } #else /* no bswap macro's */ // #warning _NO_ BSWAP's defined union _bswap_data { uint16_t u16; uint32_t u32; uint64_t u64; uint8_t b[8]; }; static __inline uint16_t udf_rw16(uint16_t a) { union _bswap_data b; b.u16 = a; return b.b[0] | (b.b[1] << 8); } static __inline uint32_t udf_rw32(uint32_t a) { union _bswap_data b; b.u32 = a; return b.b[0] | (b.b[1] << 8) | (b.b[2] << 16) | (b.b[3] << 24); } static __inline uint64_t udf_rw64(uint64_t a) { union _bswap_data b; uint32_t low, high; b.u64 = a; high = b.b[4] | (b.b[5] << 8) | (b.b[6] << 16) | (b.b[7] << 24); low = b.b[0] | (b.b[1] << 8) | (b.b[2] << 16) | (b.b[3] << 24); return ((uint64_t) low) | ((uint64_t) high) << 32; } #endif /* bswap macro's */ #else /* little endian */ #define udf_rw16(a) ((uint16_t)(a)) #define udf_rw32(a) ((uint32_t)(a)) #define udf_rw64(a) ((uint64_t)(a)) #endif #define udf_add16(a, b) \ (a) = udf_rw16(udf_rw16((a)) + (b)) #define udf_add32(a, b) \ (a) = udf_rw32(udf_rw32((a)) + (b)) #define udf_add64(a, b) \ (a) = udf_rw64(udf_rw64((a)) + (b)) #endif /* !_UDF_BSWAP_H_ */ UDFclient.0.8.8/udf_unix.c010066400001470000000000000465431307041400500146600ustar reinoudwheel/* $NetBSD$ */ /* * File "udf_unix.c" is part of the UDFclient toolkit. * File $Id: udf_unix.c,v 1.17 2016/04/25 21:01:40 reinoud Exp $ * * Copyright (c) 2003, 2004, 2005, 2006, 2011 * Reinoud Zandijk * All rights reserved. * * The UDFclient toolkit is distributed under the Clarified Artistic Licence. * A copy of the licence is included in the distribution as * `LICENCE.clearified.artistic' and a copy of the licence can also be * requested at the GNU foundantion's website. * * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* XXX strip list to bare minimum XXX */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "uscsilib.h" /* for locals */ #include "udf.h" #include "udf_bswap.h" #include "udf_discop.h" #include "udf_unix.h" #include "uio.h" #include #ifndef MAX # define MAX(a,b) ((a)>(b)?(a):(b)) # define MIN(a,b) ((a)<(b)?(a):(b)) #endif /* #define DEBUG(a) { a; } */ #define DEBUG(a) if (0) { a; } /****************************************************************************************** * * Bufcache emulation * ******************************************************************************************/ /* shared bufcache structure */ struct udf_bufcache *udf_bufcache = NULL; int udf_unix_init(void) { if (udf_bufcache) { fprintf(stderr, "reinit unix_init?\n"); return 0; } udf_bufcache = calloc(1, sizeof(struct udf_bufcache)); assert(udf_bufcache); UDF_MUTEX_INIT(&udf_bufcache->bufcache_lock); TAILQ_INIT(&udf_bufcache->lru_bufs_data); TAILQ_INIT(&udf_bufcache->lru_bufs_metadata); pthread_cond_init(&udf_bufcache->purgethread_signal, NULL); pthread_mutex_init(&udf_bufcache->purgethread_lock, NULL); pthread_cond_init(&udf_bufcache->processed_signal, NULL); pthread_mutex_init(&udf_bufcache->processed_lock, NULL); return 0; } /* delete the buf entry */ void udf_free_buf_entry(struct udf_buf *buf_entry) { assert(udf_bufcache); buf_entry->b_vp = NULL; /* detach, i.e. recycle */ buf_entry->b_flags = 0; /* just in case */ udf_bufcache->bcnt--; free(buf_entry->b_data); free(buf_entry); } /* XXX knowledge of LBSIZE, FILETYPE, INTERNAL NODE (?) ! XXX */ /* must be called with bufcache lock ! */ int udf_get_buf_entry(struct udf_node *udf_node, struct udf_buf **buf_entry_p) { struct udf_log_vol *log_vol; struct udf_buf *buf_entry; uint32_t lb_size; assert(udf_node); assert(udf_bufcache); assert(buf_entry_p); log_vol = udf_node->udf_log_vol; lb_size = log_vol->lb_size; *buf_entry_p = NULL; buf_entry = NULL; if (udf_node->udf_filetype != UDF_ICB_FILETYPE_RANDOMACCESS) { if (udf_bufcache->lru_len_metadata >= UDF_LRU_METADATA_MIN) { /* kick writeout of data; if past max wait for space to continue */ UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock); udf_purgethread_kick("Data buffer surplus"); while (udf_bufcache->lru_len_metadata >= UDF_LRU_METADATA_MAX) { udf_purgethread_kick("Metadata buffer surplus"); /* wait for processed signal */ pthread_mutex_lock(&udf_bufcache->processed_lock); pthread_cond_wait(&udf_bufcache->processed_signal, &udf_bufcache->processed_lock); pthread_mutex_unlock(&udf_bufcache->processed_lock); } UDF_MUTEX_LOCK(&udf_bufcache->bufcache_lock); } } else { if (udf_bufcache->lru_len_data >= UDF_LRU_DATA_MIN) { /* kick writeout of data; if past max wait for space to continue */ UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock); udf_purgethread_kick("Data buffer surplus"); while (udf_bufcache->lru_len_data >= UDF_LRU_DATA_MAX) { udf_purgethread_kick("Data buffer surplus"); /* wait for processed signal */ pthread_mutex_lock(&udf_bufcache->processed_lock); pthread_cond_wait(&udf_bufcache->processed_signal, &udf_bufcache->processed_lock); pthread_mutex_unlock(&udf_bufcache->processed_lock); } UDF_MUTEX_LOCK(&udf_bufcache->bufcache_lock); } } /* create new buf_entry */ buf_entry = calloc(1, sizeof(struct udf_buf)); if (!buf_entry) return ENOMEM; buf_entry->b_data = calloc(1, lb_size); if (!buf_entry->b_data) { *buf_entry_p = NULL; free(buf_entry); return ENOMEM; } *buf_entry_p = buf_entry; /* fill in details */ buf_entry->b_bufsize = lb_size; buf_entry->b_bcount = 0; buf_entry->b_resid = lb_size; buf_entry->b_lblk = 0; buf_entry->b_flags = B_INVAL; buf_entry->b_vp = udf_node; /* not just NULL ? */ udf_bufcache->bcnt++; return 0; } /* really `out of the sky' hash formula */ uint32_t udf_calc_bufhash(struct udf_node *udf_node, uint32_t b_lblk) { return (udf_node->hashkey * 5 + b_lblk); } /* !!! needs to be called with bufcache and udf_node->buf_mutex lock !!! */ void udf_mark_buf_needing_allocate(struct udf_node *udf_node, struct udf_buf *buf_entry) { uint32_t lb_size; assert(udf_node); /* assert(udf_node->buf_mutex.locked && udf_bufcache->bufcache_lock.locked); */ lb_size = udf_node->udf_log_vol->lb_size; /* if it isnt allready marked to eb allocated, allocate it and claim space */ if (!(buf_entry->b_flags & B_NEEDALLOC)) { udf_node->udf_log_vol->await_alloc_space += lb_size; buf_entry->b_flags |= B_NEEDALLOC; } } /* !!! needs to be called with bufcache and udf_node->buf_mutex lock !!! */ void udf_mark_buf_allocated(struct udf_node *udf_node, struct udf_buf *buf_entry) { uint32_t lb_size; assert(udf_node); /* assert(udf_node->buf_mutex.locked && udf_bufcache->bufcache_lock.locked); */ lb_size = udf_node->udf_log_vol->lb_size; /* if it needed allocation, clear the flag and release the space */ if (buf_entry->b_flags & B_NEEDALLOC) { udf_node->udf_log_vol->await_alloc_space -= lb_size; buf_entry->b_flags &= ~B_NEEDALLOC; } } /* !!! needs to be called with bufcache and udf_node->buf_mutex lock !!! */ void udf_mark_buf_dirty(struct udf_node *udf_node, struct udf_buf *buf_entry) { assert(udf_node); assert(buf_entry); assert(udf_node->buf_mutex.locked); assert(udf_bufcache->bufcache_lock.locked); if (buf_entry->b_flags & B_DIRTY) return; if (udf_node->addr_type == UDF_ICB_INTERN_ALLOC) { udf_mark_buf_needing_allocate(udf_node, buf_entry); /* signal it needs allocation */ } if (udf_node->udf_filetype != UDF_ICB_FILETYPE_RANDOMACCESS) { udf_bufcache->lru_len_dirty_metadata++; } else { udf_bufcache->lru_len_dirty_data++; } buf_entry->b_flags |= B_DIRTY; udf_node->v_numoutput++; } /* !!! needs to be called with bufcache and udf_node->buf_mutex lock !!! */ void udf_mark_buf_clean(struct udf_node *udf_node, struct udf_buf *buf_entry) { assert(udf_node); assert(buf_entry); assert(udf_node->buf_mutex.locked); assert(udf_bufcache->bufcache_lock.locked); if ((buf_entry->b_flags & B_DIRTY) == 0) return; if (udf_node->udf_filetype != UDF_ICB_FILETYPE_RANDOMACCESS) { udf_bufcache->lru_len_dirty_metadata--; } else { udf_bufcache->lru_len_dirty_data--; } buf_entry->b_flags &= ~B_DIRTY; assert(udf_node->v_numoutput >= 1); udf_node->v_numoutput--; } /* !!! needs to be called with bufcache and udf_node->buf_mutex lock !!! */ int udf_attach_buf_to_node(struct udf_node *udf_node, struct udf_buf *buf_entry) { struct udf_buf_queue *lru_chain; struct udf_buf *buf, *lbuf; uint32_t hashkey, bucket; assert(udf_node); assert(buf_entry); assert(udf_node->buf_mutex.locked && udf_bufcache->bufcache_lock.locked); buf_entry->b_vp = udf_node; if (0) { /* * Insert ordered in list. In KERNEL: vnode->v_dirtyblkhd is a list * that can be reverse-sorted. Ordering not used yet thus commented * out. */ lbuf = TAILQ_LAST(&udf_node->vn_bufs, udf_buf_queue); if (lbuf) { if (buf_entry->b_lblk > lbuf->b_lblk) { TAILQ_INSERT_TAIL(&udf_node->vn_bufs, buf_entry, b_vnbufs); } else { buf = TAILQ_FIRST(&udf_node->vn_bufs); while (buf->b_lblk < buf->b_lblk) { buf = TAILQ_NEXT(buf, b_vnbufs); } assert((buf->b_lblk != buf_entry->b_lblk) && (buf->b_vp == udf_node)); TAILQ_INSERT_BEFORE(buf, buf_entry, b_vnbufs); } } else { TAILQ_INSERT_HEAD(&udf_node->vn_bufs, buf_entry, b_vnbufs); } } else { TAILQ_INSERT_TAIL(&udf_node->vn_bufs, buf_entry, b_vnbufs); } /* fill buf into the bufcache */ hashkey = udf_calc_bufhash(udf_node, buf_entry->b_lblk); bucket = hashkey & UDF_BUFCACHE_HASHMASK; DEBUG( struct udf_buf *buf; /* checking for doubles */ LIST_FOREACH(buf, &udf_bufcache->udf_bufs[bucket], b_hash) { if ((buf->b_vp == udf_node) && (buf->b_lblk == buf_entry->b_lblk)) { printf("DOUBLE hashnode in UDF_BUFS!?\n"); exit(1); } } ); LIST_INSERT_HEAD(&udf_bufcache->udf_bufs[bucket], buf_entry, b_hash); /* queue it in the lru chain */ if (udf_node->udf_filetype != UDF_ICB_FILETYPE_RANDOMACCESS) { lru_chain = &udf_bufcache->lru_bufs_metadata; udf_bufcache->lru_len_metadata++; } else { lru_chain = &udf_bufcache->lru_bufs_data; udf_bufcache->lru_len_data++; } TAILQ_INSERT_TAIL(lru_chain, buf_entry, b_lru); return 0; } /* kind of brelse() ? */ /* !!! needs to be called with bufcache and udf_node->buf_mutex lock !!! */ int udf_detach_buf_from_node(struct udf_node *udf_node, struct udf_buf *buf_entry) { struct udf_buf_queue *lru_chain; assert(udf_node); assert(buf_entry); assert(udf_node->buf_mutex.locked && udf_bufcache->bufcache_lock.locked); /* remove from vnode admin */ TAILQ_REMOVE(&udf_node->vn_bufs, buf_entry, b_vnbufs); /* please don't forget this one */ if (buf_entry->b_flags & B_DIRTY) udf_node->v_numoutput--; /* remove from buffer cache */ LIST_REMOVE(buf_entry, b_hash); /* remove from lru lists */ if (udf_node->udf_filetype != UDF_ICB_FILETYPE_RANDOMACCESS) { lru_chain = &udf_bufcache->lru_bufs_metadata; TAILQ_REMOVE(lru_chain, buf_entry, b_lru); udf_bufcache->lru_len_metadata--; } else { lru_chain = &udf_bufcache->lru_bufs_data; TAILQ_REMOVE(lru_chain, buf_entry, b_lru); udf_bufcache->lru_len_data--; } return 0; } /* bufcache lock has to be held! */ int udf_lookup_node_buf(struct udf_node *udf_node, uint32_t lblk, struct udf_buf **buf_p) { #ifdef UDF_METADATA_LRU struct udf_buf_queue *lru_chain; #endif struct udf_buf *buf; uint32_t hashkey, bucket; assert(udf_node); assert(udf_bufcache->bufcache_lock.locked); *buf_p = NULL; hashkey = udf_calc_bufhash(udf_node, lblk); bucket = hashkey & UDF_BUFCACHE_HASHMASK; LIST_FOREACH(buf, &udf_bufcache->udf_bufs[bucket], b_hash) { if ((buf->b_vp == udf_node) && (buf->b_lblk == lblk)) { *buf_p = buf; #ifdef UDF_METADATA_LRU lru_chain = &udf_bufcache->lru_bufs_data; if (udf_node->udf_filetype != UDF_ICB_FILETYPE_RANDOMACCESS) lru_chain = &udf_bufcache->lru_bufs_metadata; TAILQ_REMOVE(lru_chain, buf, b_lru); TAILQ_INSERT_TAIL(lru_chain, buf, b_lru); #endif break; /* for each */ } } return 0; } void *udf_purger(void *arg) { struct timespec wakeup; struct udf_buf *buf_entry, *marker; struct udf_node *udf_node; arg = arg; /* paramter not used */ marker = calloc(1, sizeof(struct udf_buf)); assert(marker); UDF_VERBOSE(printf("\tbufcache thread initialising\n")); while (1) { DEBUG(printf("UDF bufcache sync thread: waiting for lock\n")); /* * If we are not asked to finish up our writing, block to * wait for more data. Signal the reader to continue just in * case it is still stuck. */ if (!udf_bufcache->finish_purgethread) { do { /* determine the time we want to wake up again * */ clock_gettime(CLOCK_REALTIME, &wakeup); wakeup.tv_sec += UDF_BUFCACHE_IDLE_SECS; /* ask for more requests */ pthread_cond_signal(&udf_bufcache->processed_signal); pthread_mutex_lock(&udf_bufcache->purgethread_lock); pthread_cond_timedwait(&udf_bufcache->purgethread_signal, &udf_bufcache->purgethread_lock, &wakeup); pthread_mutex_unlock(&udf_bufcache->purgethread_lock); if (!udf_bufcache->purgethread_kicked) { /* UDF_VERBOSE_MAX(printf("\nUDF purger woke up due to timeout\n")); */ /* see if we would want to do something */ if (udf_bufcache->flushall) /* shouldn't happen */ break; if (udf_bufcache->lru_len_data >= UDF_LRU_DATA_MIN) break; /* we have something to do */ if (udf_bufcache->lru_len_metadata >= UDF_LRU_METADATA_MIN) break; /* we have something to do */ } /* else : we have been explicitly asked to do something */ } while (!udf_bufcache->purgethread_kicked && !udf_bufcache->finish_purgethread); } udf_bufcache->purgethread_kicked = 0; DEBUG(printf("UDF read/write thread: got activate\n")); UDF_MUTEX_LOCK(&udf_bufcache->bufcache_lock); /* writeout surplus of dirty buffers */ /* PURGE surplus bufs if possible */ if ((udf_bufcache->lru_len_data >= UDF_LRU_DATA_MIN) || udf_bufcache->flushall) { /* getting too many dirty data buffers */ TAILQ_INSERT_HEAD(&udf_bufcache->lru_bufs_data, marker, b_lru); while ((buf_entry = TAILQ_NEXT(marker, b_lru))) { /* advance marker */ TAILQ_REMOVE(&udf_bufcache->lru_bufs_data, marker, b_lru); TAILQ_INSERT_AFTER(&udf_bufcache->lru_bufs_data, buf_entry, marker, b_lru); /* process buf_entry */ if ((buf_entry->b_flags & B_DIRTY) != 0) { if ((udf_bufcache->lru_len_dirty_data >= UDF_READWRITE_LINE_LENGTH*2) || udf_bufcache->flushall) { UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock); /* signal there is time/space ahead and write out buffer */ pthread_cond_signal(&udf_bufcache->processed_signal); udf_writeout_file_buffer(buf_entry->b_vp, "dirty data buf", UDF_C_USERDATA, buf_entry); DEBUG(printf("."); fflush(stdout)); UDF_MUTEX_LOCK(&udf_bufcache->bufcache_lock); } } /* if there are too many, drop least used */ if (udf_bufcache->lru_len_data > UDF_LRU_DATA_MIN) { TAILQ_FOREACH(buf_entry, &udf_bufcache->lru_bufs_data, b_lru) { /* process buf_entry */ if ((buf_entry != marker) && ((buf_entry->b_flags & B_DIRTY) == 0)) { /* lock node bufs (locking protocol) */ udf_node = buf_entry->b_vp; if (udf_node) { UDF_MUTEX_LOCK(&udf_node->buf_mutex); udf_detach_buf_from_node(udf_node, buf_entry); UDF_MUTEX_UNLOCK(&udf_node->buf_mutex); } else { printf("\n\nWARNING: got a NULL udf_node freeing dataspace\n\n"); } udf_free_buf_entry(buf_entry); /* signal there is time/space ahead */ UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock); pthread_cond_signal(&udf_bufcache->processed_signal); UDF_MUTEX_LOCK(&udf_bufcache->bufcache_lock); break; /* mandatory leaving FOREACH */ } if (udf_bufcache->lru_len_data < UDF_LRU_DATA_MIN) break; /* foreach */ } } } TAILQ_REMOVE(&udf_bufcache->lru_bufs_data, marker, b_lru); } if ((udf_bufcache->lru_len_metadata >= UDF_LRU_METADATA_MIN) || udf_bufcache->flushall) { /* getting too many dirty metadata buffers */ TAILQ_INSERT_HEAD(&udf_bufcache->lru_bufs_metadata, marker, b_lru); while ((buf_entry = TAILQ_NEXT(marker, b_lru))) { /* advance marker */ TAILQ_REMOVE(&udf_bufcache->lru_bufs_metadata, marker, b_lru); TAILQ_INSERT_AFTER(&udf_bufcache->lru_bufs_metadata, buf_entry, marker, b_lru); /* process buf_entry */ if ((buf_entry->b_flags & B_DIRTY) != 0) { if ((udf_bufcache->lru_len_dirty_metadata >= UDF_READWRITE_LINE_LENGTH*2) || udf_bufcache->flushall) { UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock); /* signal there is time/space ahead and writeout buffer */ pthread_cond_signal(&udf_bufcache->processed_signal); udf_writeout_file_buffer(buf_entry->b_vp, "dirty metadata buf", UDF_C_FIDS, buf_entry); DEBUG(printf("+"); fflush(stdout)); UDF_MUTEX_LOCK(&udf_bufcache->bufcache_lock); } } /* if there are too many, drop least used */ if (udf_bufcache->lru_len_metadata > UDF_LRU_METADATA_MIN) { TAILQ_FOREACH(buf_entry, &udf_bufcache->lru_bufs_metadata, b_lru) { /* process buf_entry */ if ((buf_entry != marker) && ((buf_entry->b_flags & B_DIRTY)) == 0) { /* lock node bufs (locking protocol); don't drop metadata from `held' nodes */ udf_node = buf_entry->b_vp; if (udf_node && ((!udf_node->hold) || udf_bufcache->flushall)) { UDF_MUTEX_LOCK(&udf_node->buf_mutex); udf_detach_buf_from_node(udf_node, buf_entry); UDF_MUTEX_UNLOCK(&udf_node->buf_mutex); udf_free_buf_entry(buf_entry); /* signal there is time/space ahead */ UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock); pthread_cond_signal(&udf_bufcache->processed_signal); UDF_MUTEX_LOCK(&udf_bufcache->bufcache_lock); break; /* mandatory leaving FOREACH */ } else { if (!udf_node) { printf("\n\nWARNING: got a NULL udf_node freeing METAspace\n\n"); } #ifdef UDF_METADATA_LRU TAILQ_REMOVE(&udf_bufcache->lru_bufs_metadata, buf_entry, b_lru); TAILQ_INSERT_TAIL(&udf_bufcache->lru_bufs_metadata, buf_entry, b_lru); #endif } } } } } TAILQ_REMOVE(&udf_bufcache->lru_bufs_metadata, marker, b_lru); } /* can only be used once */ udf_bufcache->flushall = 0; UDF_MUTEX_UNLOCK(&udf_bufcache->bufcache_lock); /* PURGE nodes? (or only on request?) */ /* if asked to quit break out of the loop */ if (udf_bufcache->finish_purgethread) break; } UDF_VERBOSE(printf("\tbufcache thread joining\n")); pthread_exit(0); /* join */ /* not reached */ return NULL; } int udf_start_unix_thread(void) { /* * start up bufcache purger thread and crudely kick it into * existence. */ if (udf_bufcache->thread_active) { fprintf(stderr,"\tlogvol bufcache thread asked to start again; ignoring\n"); return 0; } DEBUG(printf("\tstarting logvol bufcache thread\n")); udf_bufcache->thread_active = 1; pthread_create(&udf_bufcache->purgethread_id, NULL, udf_purger, NULL); sleep(1); DEBUG(printf("\n\n")); return 0; } int udf_stop_unix_thread(void) { /* stop all associated threads */ UDF_VERBOSE(printf("\tstopping bufcache thread\n")); if (udf_bufcache->thread_active) { udf_bufcache->purgethread_kicked = 1; udf_bufcache->finish_purgethread = 1; pthread_cond_signal(&udf_bufcache->purgethread_signal); pthread_join(udf_bufcache->purgethread_id, NULL); /* wait for join */ } udf_bufcache->thread_active = 0; return 0; } int udf_purgethread_kick(char *why) { /* * Kick the cache purger into existence in case its not active and wait * for it to signal there is space left. */ DEBUG(printf("\npurgethread kick! because of %s\n", why)); udf_bufcache->purgethread_kicked = 1; pthread_cond_signal(&udf_bufcache->purgethread_signal); return 0; } /* end of udf_unix.c */ UDFclient.0.8.8/udfdump.c010066400001470000000000000153261307041400500144760ustar reinoudwheel/* $NetBSD$ */ /* * File "udfdump.c" is part of the UDFclient toolkit. * File $Id: udfdump.c,v 1.75 2016/04/25 21:01:41 reinoud Exp $ $Name: $ * * Copyright (c) 2003, 2004, 2005, 2006, 2011 * Reinoud Zandijk * All rights reserved. * * The UDFclient toolkit is distributed under the Clarified Artistic Licence. * A copy of the licence is included in the distribution as * `LICENCE.clearified.artistic' and a copy of the licence can also be * requested at the GNU foundantion's website. * * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include "udf.h" #include "udf_bswap.h" /* switches */ /* #define DEBUG(a) (a) */ #define DEBUG(a) if (0) { a; } int dump_sequential = 0; int dump_directory_trees = 0; #ifndef MAX # define MAX(a,b) ((a)>(b)?(a):(b)) # define MIN(a,b) ((a)<(b)?(a):(b)) #endif /* include the dump parts ... in order to get a more sane splitting */ extern void udf_dump_descriptor(union dscrptr *dscrpt); extern void udf_dump_alive_sets(void); extern void udf_dump_root_dir(struct udf_mountpoint *mountpoint); /* globals */ extern int udf_verbose; extern int uscsilib_verbose; /* main discdump routine */ void udf_dump_sequential(int alt_sector_size, int flags, char *dev_name) { struct udf_discinfo *disc; union dscrptr *dscr; uint64_t sec_num, rsec_num; uint32_t sector_size, size, chunk, dscr_len; uint8_t *new_sector, *sector, *pos; int error; udf_verbose = UDF_VERBLEV_ACTIONS; printf("Opening disc:\n"); error = udf_open_disc(dev_name, flags, &disc); if (error) return; if (alt_sector_size) disc->sector_size = alt_sector_size; sector = calloc(1, 65*1024); assert(sector); printf("Sequential dump of device/file (sector size %d)\n", disc->sector_size); sec_num = 0; sector_size = disc->sector_size; do { size = 1; error = udf_read_physical_sectors(disc, sec_num, size, "sector", sector); if (!error) { dscr = (union dscrptr *) sector; if (!udf_check_tag(dscr)) { if (udf_rw16(dscr->tag.id) <= TAGID_MAX) { dscr_len = udf_calc_tag_malloc_size(dscr, sector_size); dscr_len = MAX(sector_size, dscr_len); if (dscr_len > sector_size) { size = (dscr_len + sector_size -1) / sector_size; new_sector = realloc(sector, size * sector_size); if (!new_sector) goto next_sector; if (new_sector) sector = new_sector; dscr = (union dscrptr *) sector; chunk = MIN(size, 0xffff); pos = sector; rsec_num = sec_num; while (size) { error = udf_read_physical_sectors( disc, rsec_num, chunk, "sector", pos); if (error) break; pos += chunk * sector_size; rsec_num += chunk; size -= chunk; chunk = MIN(size, 0xffff); } if (error) break; } size = (dscr_len + sector_size -1) / sector_size; if (!udf_check_tag_payload(dscr)) { printf("%8d ", (int) sec_num); udf_dump_descriptor(dscr); } } } } else { if (error == ENOENT) break; printf("\nRead error : %s\n", strerror(error)); } next_sector: sec_num++; printf("\r%08d ", (int) sec_num); fflush(stdout); } while (1); printf("\n"); } void udf_dump_mountable_dirtrees(void) { struct udf_mountpoint *mountpoint; printf("Dumping directory tree for each non obsolete logical volume's fileset\n"); SLIST_FOREACH(mountpoint, &udf_mountables, all_next) { printf("\n"); printf("Directory tree of mount point %s\n", mountpoint->mount_name); udf_dump_root_dir(mountpoint); } } int usage(char *program) { fprintf(stderr, "Usage %s [options] devicename [devicename]*)\n", program); fprintf(stderr, "-S dump device sequential\n" "-s byteswap read sectors (for PVRs)\n" "-t dump complete directory contents\n" "-b blocksize use alternative sectorsize; use only on files/discs\n" "-u level UDF system verbose level\n" "-D verbose SCSI command errors\n" "-r range only use UDF sessions range like -3,4-5 or 6-\n" ); return 1; } int main(int argc, char *argv[]) { struct udf_discinfo *disc; char *progname, *range; uint32_t alt_sector_size; int flag, mntflags, bswap, error; progname = argv[0]; if (argc == 1) return usage(progname); dump_sequential = 0; dump_directory_trees = 0; range = NULL; alt_sector_size = 0; bswap = 0; while ((flag = getopt(argc, argv, "u:r:b:DSst")) != -1) { switch (flag) { case 'u' : udf_verbose = atoi(optarg); break; case 'r' : range = strdup(optarg); if (udf_check_session_range(range)) { fprintf(stderr, "Invalid range %s\n", range); return usage(progname); } break; case 'b' : alt_sector_size = atoi(optarg); break; case 'D' : uscsilib_verbose = 1; break; case 'S' : dump_sequential = 1; break; case 's' : bswap = 1; break; case 't' : dump_directory_trees = 1; break; default : return usage(progname); } } argv += optind; argc -= optind; if (dump_sequential) { if (argc != 1) return usage(progname); udf_dump_sequential(alt_sector_size, bswap, *argv); return 0; } if (argc == 0) return usage(progname); /* all other arguments are devices */ udf_init(); while (argc) { printf("Opening device %s\n\n", *argv); mntflags = UDF_MNT_RDONLY; mntflags |= bswap ? UDF_MNT_BSWAP : 0; error = udf_mount_disc(*argv, range, alt_sector_size, mntflags, &disc); if (error) { fprintf(stderr, "Can't open my device; bailing out : %s\n", strerror(error)); exit(1); } argv++; argc--; if (udf_verbose) printf("\n\n"); } printf("Resulting list of alive sets :\n\n"); udf_dump_alive_sets(); if (dump_directory_trees) { printf("Dump tree of all mountables\n"); udf_dump_mountable_dirtrees(); printf("\n"); } printf("Closing discs\n"); SLIST_FOREACH(disc, &udf_discs_list, next_disc) { udf_close_disc(disc); } return 0; } UDFclient.0.8.8/uio.c010066400001470000000000000045321307041400500136230ustar reinoudwheel/* $NetBSD$ */ /* * File "uio.c" is part of the UDFclient toolkit. * File $Id: uio.c,v 1.7 2011/02/01 20:43:41 reinoud Exp $ $Name: $ * * Copyright (c) 2004, 2005, 2006, 2011 * Reinoud Zandijk * All rights reserved. * * The UDFclient toolkit is distributed under the Clarified Artistic Licence. * A copy of the licence is included in the distribution as * `LICENCE.clearified.artistic' and a copy of the licence can also be * requested at the GNU foundantion's website. * * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include "uio.h" /* modelled after NetBSD's uiomove */ int uiomove(void *buf, size_t amount, struct uio *uio) { struct iovec *iov; char *cp = buf; size_t cnt; assert(buf); assert(uio); assert(uio->uio_iov); while (amount > 0 && uio->uio_resid > 0) { iov = uio->uio_iov; cnt = iov->iov_len; if (cnt == 0) { assert(uio->uio_iovcnt > 0); uio->uio_iov++; uio->uio_iovcnt--; if (uio->uio_iovcnt == 0) return 0; /* end of buffers */ continue; } /* not more than requested please */ if (cnt > amount) cnt = amount; /* move the information */ if (uio->uio_rw == UIO_READ) { /* read into the uio */ memcpy(cp, iov->iov_base, cnt); } else { /* write from the uio */ memcpy(iov->iov_base, cp, cnt); } /* update the uio structure to reflect move */ iov->iov_base = (caddr_t) iov->iov_base + cnt; iov->iov_len -= cnt; uio->uio_resid -= cnt; uio->uio_offset += cnt; cp += cnt; assert(cnt <= amount); amount -= cnt; } return 0; } /* end of uio.c */ UDFclient.0.8.8/uio.h010066400001470000000000000042401307041400500136240ustar reinoudwheel/* $NetBSD$ */ /* * File "uio.h" is part of the UDFclient toolkit. * File $Id: uio.h,v 1.6 2011/02/01 20:43:41 reinoud Exp $ $Name: $ * * Copyright (c) 2004, 2005, 2006, 2011 * Reinoud Zandijk * All rights reserved. * * The UDFclient toolkit is distributed under the Clarified Artistic Licence. * A copy of the licence is included in the distribution as * `LICENCE.clearified.artistic' and a copy of the licence can also be * requested at the GNU foundantion's website. * * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef _SYS_UIO_H_ #define _SYS_UIO_H_ #include #include /* define an uio structure for fragmenting reading in and writing data out */ /* modelled after BSD's kernel structures */ enum uio_rw { UIO_READ, UIO_WRITE }; struct iovec { void *iov_base; /* base if this chunk */ size_t iov_len; /* length */ }; /* this is consumed !! i.e. keep a copy */ struct uio { struct iovec *uio_iov; /* pointer to array of iovecs */ int uio_iovcnt; /* number of iovecs in array */ off_t uio_offset; /* current offset */ size_t uio_resid; /* residual i/o count */ enum uio_rw uio_rw; /* read/write direction */ /* ... rest obmitted ... */ }; #endif /* _SYS_UIO_H_ */ /* allways declare the functions */ /* move data from/to a uio structure to a blob */ extern int uiomove(void *buf, size_t amount, struct uio *uio); /* end of uio.h */ UDFclient.0.8.8/udf_unix.h010066400001470000000000000146471307041400500146650ustar reinoudwheel/* $NetBSD$ */ /* * File "udf.h" is part of the UDFclient toolkit. * File $Id: udf_unix.h,v 1.5 2011/02/01 20:43:41 reinoud Exp $ $Name: $ * * Copyright (c) 2003, 2004, 2005, 2006, 2011 * Reinoud Zandijk * All rights reserved. * * The UDFclient toolkit is distributed under the Clarified Artistic Licence. * A copy of the licence is included in the distribution as * `LICENCE.clearified.artistic' and a copy of the licence can also be * requested at the GNU foundantion's website. * * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef _UDF_UNIX_H_ #define _UDF_UNIX_H_ #include "udf.h" /* Predefines */ struct udf_pri_vol; struct udf_node; /* * Provides :: system buffer structure for file/metadata caching * * ... free after struct buf ... */ struct udf_buf { UDF_MUTEX(b_interlock); uint32_t b_lblk; /* logical block number for vnode */ struct udf_node *b_vp; /* points to its parent udf_node */ uint32_t b_flags; /* B_* flags */ uint8_t *b_data; /* buffer itself */ uint8_t *b_private; /* private pointer for FS */ uint32_t b_bufsize; /* allocated size */ uint32_t b_bcount; /* size used */ uint32_t b_resid; /* size remaining */ LIST_ENTRY(udf_buf) b_hash; TAILQ_ENTRY(udf_buf) b_vnbufs; /* used for vnode bufs */ TAILQ_ENTRY(udf_buf) b_lru; /* lru queue (reuse) */ }; TAILQ_HEAD(udf_buf_queue, udf_buf); /* * These flags are kept in b_flags. Copied from NetBSD's */ #define B_AGE 0x00000001 /* Move to age queue when I/O done. */ #define B_ASYNC 0x00000004 /* Start I/O, do not wait. */ #define B_BAD 0x00000008 /* Bad block revectoring in progress. */ #define B_BUSY 0x00000010 /* I/O in progress. */ #define B_SCANNED 0x00000020 /* Block already pushed during sync */ #define B_CALL 0x00000040 /* Call b_iodone from biodone. */ #define B_DELWRI 0x00000080 /* Delay I/O until buffer reused. */ #define B_DIRTY 0x00000100 /* Dirty page to be pushed out async. */ #define B_DONE 0x00000200 /* I/O completed. */ #define B_EINTR 0x00000400 /* I/O was interrupted */ #define B_ERROR 0x00000800 /* I/O error occurred. */ #define B_GATHERED 0x00001000 /* LFS: already in a segment. */ #define B_INVAL 0x00002000 /* Does not contain valid info. */ #define B_LOCKED 0x00004000 /* Locked in core (not reusable). */ #define B_NOCACHE 0x00008000 /* Do not cache block after use. */ #define B_CACHE 0x00020000 /* Bread found us in the cache. */ #define B_PHYS 0x00040000 /* I/O to user memory. */ #define B_RAW 0x00080000 /* Set by physio for raw transfers. */ #define B_READ 0x00100000 /* Read buffer. */ #define B_TAPE 0x00200000 /* Magnetic tape I/O. */ #define B_WANTED 0x00800000 /* Process wants this buffer. */ #define B_WRITE 0x00000000 /* Write buffer (pseudo flag). */ #define B_XXX 0x02000000 /* Debugging flag. */ #define B_VFLUSH 0x04000000 /* Buffer is being synced. */ #define B_NEEDALLOC 0x08000000 /* TEMP */ #define BUF_FLAGBITS \ "\20\1AGE\3ASYNC\4BAD\5BUSY\6SCANNED\7CALL\10DELWRI" \ "\11DIRTY\12DONE\13EINTR\14ERROR\15GATHERED\16INVAL\17LOCKED\20NOCACHE" \ "\22CACHE\23PHYS\24RAW\25READ\26TAPE\30WANTED\32XXX\33VFLUSH" struct udf_bufcache { /* udf_node buf's multiplexed in one hashtable on (inode, b_lblk) */ LIST_HEAD(bufcache, udf_buf) udf_bufs[UDF_BUFCACHE_HASHSIZE]; UDF_MUTEX(bufcache_lock); int32_t bcnt; /* temp var counting alloc/free */ uint32_t lru_len_data, lru_len_metadata; uint32_t lru_len_dirty_data, lru_len_dirty_metadata; struct udf_buf_queue lru_bufs_data; struct udf_buf_queue lru_bufs_metadata; /* thread support for bufs & nodes purge (bufcache emulation) */ pthread_t purgethread_id; pthread_mutex_t purgethread_lock; /* lock the thread code out */ pthread_cond_t purgethread_signal; /* signal there is work to be done */ int purgethread_kicked; /* sanity for spurious wakeups */ pthread_mutex_t processed_lock; /* lock for main threads to wait on */ pthread_cond_t processed_signal; /* signals an action has been done */ int thread_active; int finish_purgethread; /* ask thread to stop what its doing and exit */ int flushall; /* flusha all dirty buffers */ }; extern struct udf_bufcache *udf_bufcache; /* bufcache emulation */ extern int udf_get_buf_entry(struct udf_node *udf_node, struct udf_buf **buf_entry_p); extern void udf_free_buf_entry(struct udf_buf *buf_entry); extern int udf_attach_buf_to_node(struct udf_node *udf_node, struct udf_buf *buf_entry); extern int udf_detach_buf_from_node(struct udf_node *udf_node, struct udf_buf *buf_entry); extern int udf_build_udf_node(struct udf_node *dir_node, struct fileid_desc *fid, struct udf_node **res_sub_node); extern int udf_lookup_node_buf(struct udf_node *udf_node, uint32_t lblk, struct udf_buf **buf_p); extern void udf_mark_buf_clean(struct udf_node *udf_node, struct udf_buf *buf_entry); extern void udf_mark_buf_dirty(struct udf_node *udf_node, struct udf_buf *buf_entry); /* maybe not strictly udf_unix */ extern void udf_mark_buf_needing_allocate(struct udf_node *udf_node, struct udf_buf *buf_entry); extern void udf_mark_buf_allocated(struct udf_node *udf_node, struct udf_buf *buf_entry); extern int udf_unix_init(void); extern int udf_start_unix_thread(void); extern int udf_stop_unix_thread(void); /* HELP ! need good clear closedown */ /* TEMP */ extern int udf_purgethread_kick(char *why); #endif /* _UDF_UNIX_H_ */ UDFclient.0.8.8/mmc_format.c010066400001470000000000000641111307041400500151520ustar reinoudwheel/* $NetBSD$ */ /* * File "mmc_format.c" is part of the UDFclient toolkit. * File $Id: mmc_format.c,v 1.15 2016/04/25 21:01:39 reinoud Exp $ $Name: $ * * Copyright (c) 2003, 2004, 2005, 2006, 2011 * Reinoud Zandijk * All rights reserved. * * The UDFclient toolkit is distributed under the Clarified Artistic Licence. * A copy of the licence is included in the distribution as * `LICENCE.clearified.artistic' and a copy of the licence can also be * requested at the GNU foundantion's website. * * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "uscsilib.h" /* globals */ struct uscsi_dev dev; extern int scsilib_verbose; /* #define DEBUG(a) {a;} */ #define DEBUG(a) ; uint64_t getmtime(void) { struct timeval tp; gettimeofday(&tp, NULL); return (uint64_t) 1000000 * tp.tv_sec + tp.tv_usec; } void print_eta(uint32_t progress, uint64_t now, uint64_t start_time) { int hours, minutes, seconds; float fract; uint32_t eta, ubusy; if (progress == 0) { printf(" ETA --:--:--"); return; } ubusy = (now - start_time); fract = ((uint64_t) (0x10000) - progress) / progress; eta = (fract * ubusy) / 1000000; hours = (int) (eta/3600); minutes = (int) (eta/60) % 60; seconds = (int) eta % 60; printf(" ETA %02d:%02d:%02d", hours, minutes, seconds); } void uscsi_waitop(struct uscsi_dev *dev) { scsicmd cmd; struct uscsi_sense sense; uint64_t start_time; uint32_t progress; uint8_t buffer[256]; int asc, ascq; int cnt = 0; bzero(cmd, SCSI_CMD_LEN); bzero(buffer, sizeof(buffer)); /* * not be to unpatient... give the drive some time to start or it * might break off */ start_time = getmtime(); sleep(10); progress = 0; while (progress < 0x10000) { /* we need a command that is NOT going to stop the formatting */ bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0; /* test unit ready */ uscsi_command(SCSI_READCMD, dev, cmd, 6, buffer, 0, 10000, &sense); /* * asc may be `not-ready' or `no-sense'. ascq for format in * progress is 4 too */ asc = sense.asc; ascq = sense.ascq; if (((asc == 0) && (ascq == 4)) || (asc == 4)) { /* drive not ready : operation/format in progress */ if (sense.skey_valid) { progress = sense.sense_key; } else { /* finished (? XXX) */ progress = 0x10000; } } /* check if drive is ready again, ifso break out loop */ if ((asc == 0) && (ascq == 0)) { progress = 0x10000; } printf("%3d %% ", (100 * progress / 0x10000)); printf("%c", "|/-\\" [cnt++ %4]); /* twirl */ /* print ETA */ print_eta(progress, getmtime(), start_time); fflush(stdout); sleep(1); printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); fflush(stdout); } printf("\n"); return; } static char *print_mmc_profile(int profile) { static char scrap[100]; switch (profile) { case 0x00 : return "Unknown[0] profile"; case 0x01 : return "Non removable disc"; case 0x02 : return "Removable disc"; case 0x03 : return "Magneto Optical with sector erase"; case 0x04 : return "Magneto Optical write once"; case 0x05 : return "Advance Storage Magneto Optical"; case 0x08 : return "CD-ROM"; case 0x09 : return "CD-R recordable"; case 0x0a : return "CD-RW rewritable"; case 0x10 : return "DVD-ROM"; case 0x11 : return "DVD-R sequential"; case 0x12 : return "DVD-RAM rewritable"; case 0x13 : return "DVD-RW restricted overwrite"; case 0x14 : return "DVD-RW sequential"; case 0x1a : return "DVD+RW rewritable"; case 0x1b : return "DVD+R recordable"; case 0x20 : return "DDCD readonly"; case 0x21 : return "DDCD-R recordable"; case 0x22 : return "DDCD-RW rewritable"; case 0x2b : return "DVD+R double layer"; case 0x40 : return "BD-ROM"; case 0x41 : return "BD-R Sequential Recording (SRM)"; case 0x42 : return "BD-R Random Recording (RRM)"; case 0x43 : return "BD-RE rewritable"; } sprintf(scrap, "Reserved profile 0x%02x", profile); return scrap; } int uscsi_get_mmc_profile(struct uscsi_dev *dev, int *mmc_profile) { scsicmd cmd; uint8_t buf[32]; int error; *mmc_profile = 0; bzero(cmd, SCSI_CMD_LEN); cmd[ 0] = 0x46; /* Get configuration */ cmd[ 8] = 32; /* just a small buffer size */ cmd[ 9] = 0; /* control */ error = uscsi_command(SCSI_READCMD, dev, cmd, 10, buf, 32, 30000, NULL); if (!error) { *mmc_profile = buf[7] | (buf[6] << 8); } return error; } #define max_blk_len 10000 int uscsi_set_packet_parameters(struct uscsi_dev *dev, int blockingnr) { scsicmd cmd; int val_len; uint8_t res[max_blk_len], *pos; int error; /* Set up CD/DVD recording parameters */ DEBUG(printf("Setting device's recording parameters\n")); val_len = 0x32+2+8; bzero(res, val_len); pos = res + 8; bzero(cmd, SCSI_CMD_LEN); pos[ 0] = 0x05; /* page code 5 : cd writing */ pos[ 1] = 0x32; /* length in bytes */ pos[ 2] = 0; /* write type 0 : packet/incremental */ /* next session OK, data packet, rec. incr. fixed packets */ pos[ 3] = (3<<6) | 32 | 5; pos[ 4] = 10; /* ISO mode 2; XA form 1 */ pos[ 8] = 0x20; /* CD-ROM XA disc or DDCD disc */ pos[10] = (blockingnr >> 24) & 0xff; /* MSB packet size */ pos[11] = (blockingnr >> 16) & 0xff; pos[12] = (blockingnr >> 8) & 0xff; pos[13] = (blockingnr ) & 0xff; /* LSB packet size */ bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x55; /* MODE SELECT (10) */ cmd[1] = 16; /* PF format */ cmd[7] = val_len >> 8; /* length of blob */ cmd[8] = val_len & 0xff; cmd[9] = 0; /* control */ error = uscsi_command(SCSI_WRITECMD, dev, cmd, 10, res, val_len, 30000, NULL); if (error) { perror("While WRTITING parameter page 5"); return error; } /* flag OK */ return 0; } #undef max_blk_len int get_format_capabilities(struct uscsi_dev *dev, uint8_t *buf, uint32_t *len) { scsicmd cmd; int list_length; uint32_t buf_len = 512, trans_len; int error; assert(*len >= buf_len); bzero(buf, buf_len); trans_len = 12; /* only fixed header first */ bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x23; /* Read format capabilities */ cmd[7] = trans_len >> 8; /* MSB allocation length */ cmd[8] = trans_len & 0xff; /* LSB allocation length */ cmd[9] = 0; /* control */ error = uscsi_command(SCSI_READCMD, dev, cmd, 10, buf, trans_len, 30000, NULL); if (error) { fprintf(stderr, "While reading format capabilities : %s\n", strerror(error)); return error; } list_length = buf[ 3]; if (list_length % 8) { printf( "\t\tWarning: violating SCSI spec," "capacity list length ought to be multiple of 8\n"); printf("\t\tInterpreting as including header of 4 bytes\n"); assert(list_length % 8 == 4); list_length -= 4; } /* read in full capacity list */ trans_len = 12 + list_length; /* complete structure */ bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x23; /* Read format capabilities */ cmd[7] = trans_len >> 8; /* MSB allocation length */ cmd[8] = trans_len & 0xff; /* LSB allocation length */ cmd[9] = 0; /* control */ error = uscsi_command(SCSI_READCMD, dev, cmd, 10, buf, trans_len, 30000, NULL); if (error) { fprintf(stderr, "While reading format capabilities : %s\n", strerror(error)); return error; } *len = list_length; return 0; } void print_format(int format_tp, uint32_t num_blks, uint32_t param, int dscr_type, int verbose, int *supported) { char *format_str, *nblks_str, *param_str, *user_spec; format_str = nblks_str = param_str = "reserved"; user_spec = ""; *supported = 1; switch (format_tp) { case 0x00 : format_str = "full format capacity"; nblks_str = "sectors"; param_str = "block length in bytes"; user_spec = "'-F [-b blockingnr]'"; break; case 0x01 : format_str = "spare area expansion"; nblks_str = "extension in blocks"; param_str = "block length in bytes"; user_spec = "'-S'"; break; /* 0x02 - 0x03 reserved */ case 0x04 : format_str = "variable length zone'd format"; nblks_str = "zone length"; param_str = "zone number"; *supported = 0; break; case 0x05 : format_str = "fixed length zone'd format"; nblks_str = "zone length"; param_str = "last zone number"; *supported = 0; break; /* 0x06 - 0x0f reserved */ case 0x10 : format_str = "CD-RW/DVD-RW full packet format"; nblks_str = "adressable blocks"; param_str = "fixed packet size/ECC blocksize in sectors"; user_spec = "'-F -p [-b blockingnr]'"; break; case 0x11 : format_str = "CD-RW/DVD-RW grow session"; nblks_str = "adressable blocks"; param_str = "fixed packet size/ECC blocksize in sectors"; user_spec = "'-G'"; break; case 0x12 : format_str = "CD-RW/DVD-RW add session"; nblks_str = "adressable blocks"; param_str = "maximum fixed packet size/ECC blocksize " "in sectors"; *supported = 0; break; case 0x13 : format_str = "DVD-RW max growth of last complete session"; nblks_str = "adressable blocks"; param_str = "ECC blocksize in sectors"; user_spec = "'-G'"; break; case 0x14 : format_str = "DVD-RW quick grow last session"; nblks_str = "adressable blocks"; param_str = "ECC blocksize in sectors"; *supported = 0; break; case 0x15 : format_str = "DVD-RW quick full format"; nblks_str = "adressable blocks"; param_str = "ECC blocksize in sectors"; *supported = 0; break; /* 0x16 - 0x23 reserved */ case 0x24 : format_str = "background MRW format"; nblks_str = "Defect Management Area blocks"; param_str = "not used"; user_spec = "'[-R] [-s] [-w] -F -M [-b blockingnr]'"; break; /* 0x25 reserved */ case 0x26 : format_str = "background DVD+RW full format"; nblks_str = "sectors"; param_str = "not used"; user_spec = "'[-R] [-w] -F'"; break; /* 0x27 - 0x2f reserved */ case 0x30 : format_str = "BD-RE full format with spare area"; nblks_str = "blocks"; param_str = "total spare area size in clusters"; user_spec = "'[-s] -F'"; break; case 0x31 : format_str = "BD-RE full format without spare area"; nblks_str = "blocks"; param_str = "block length in bytes"; user_spec = "'-F'"; break; /* 0x32 - 0x3f reserved */ default : break; } if (verbose) { printf("\n\tFormat type 0x%02x : %s\n", format_tp, format_str); switch (dscr_type) { case 1 : printf( "\t\tUnformatted media," "maximum formatted capacity\n"); break; case 2 : printf( "\t\tFormatted media," "current formatted capacity\n"); break; case 3 : printf( "\t\tNo media present or incomplete session, " "maximum formatted capacity\n"); break; default : printf("\t\tUnspecified descriptor type\n"); break; } printf("\t\tNumber of blocks : %12d\t(%s)\n", num_blks, nblks_str); printf("\t\tParameter : %12d\t(%s)\n", param, param_str); if (format_tp == 0x24) { printf( "\t\tExpert select : " "'-X 0x%02x:0xffffff:0' or " "'-X 0x%02x:0xffff0000:0'\n", format_tp, format_tp); } else { printf( "\t\tExpert select : " "'-X 0x%02x:%d:%d'\n", format_tp, num_blks, param); } if (*supported) { printf("\t\tmmc_format arg : %s\n", user_spec); } else { printf("\t\t** not supported **\n"); } } } void process_format_caps(uint8_t *buf, int list_length, int verbose, uint8_t *allow, uint32_t *blks, uint32_t *params) { uint32_t num_blks, param; uint8_t *fcd; int dscr_type, format_tp; int supported; bzero(allow, 255); bzero(blks, 255*4); bzero(params, 255*4); fcd = buf + 4; list_length -= 4; /* strip header */ if (verbose) printf("\tCurrent/max capacity followed by additional capacity," "reported length of %d bytes (8/entry)\n", list_length); while (list_length > 0) { num_blks = fcd[ 3] | (fcd[ 2] << 8) | (fcd[ 1] << 16) | (fcd[ 0] << 24); dscr_type = fcd[ 4] & 3; format_tp = fcd[ 4] >> 2; param = fcd[ 7] | (fcd[ 6] << 8) | (fcd[ 5] << 16); print_format(format_tp, num_blks, param, dscr_type, verbose, &supported); allow[format_tp] = 1; /* TODO = supported? */ blks[format_tp] = num_blks; params[format_tp] = param; fcd += 8; list_length-=8; } } /* format a CD-RW disc */ /* old style format 7 */ int uscsi_format_cdrw_mode7(struct uscsi_dev *dev, uint32_t blocks) { scsicmd cmd; struct uscsi_sense sense; uint8_t buffer[16]; int error; if (blocks % 32) { blocks -= blocks % 32; } bzero(cmd, SCSI_CMD_LEN); bzero(buffer, sizeof(buffer)); cmd[0] = 0x04; /* format unit */ cmd[1] = 0x17; /* parameter list format 7 follows */ cmd[5] = 0; /* control */ /* format list header */ buffer[ 0] = 0; /* reserved */ buffer[ 1] = 0x80 | 0x02; /* Valid info, immediate return */ buffer[ 2] = 0; /* MSB format descriptor length */ buffer[ 3] = 8; /* LSB ... */ /* * for CD-RW the initialisation pattern bit is reserved, but there IS * one */ buffer[ 4] = 0; /* no header */ buffer[ 5] = 0; /* default pattern */ buffer[ 6] = 0; /* pattern length MSB */ buffer[ 7] = 0; /* pattern length LSB */ /* 8 bytes of format descriptor */ /* (s)ession bit 1<<7, (g)row bit 1<<6 */ /* SG action */ /* 00 format disc with number of user data blocks */ /* 10 create new session with number of data blocks */ /* x1 grow session to be number of data blocks */ buffer[ 8] = 0x00; /* session and grow bits (7 and 6) */ buffer[ 9] = 0; /* reserved */ buffer[10] = 0; /* reserved */ buffer[11] = 0; /* reserved */ buffer[12] = (blocks >> 24) & 0xff; /* blocks MSB */ buffer[13] = (blocks >> 16) & 0xff; buffer[14] = (blocks >> 8) & 0xff; buffer[15] = (blocks ) & 0xff; /* blocks LSB */ /* this will take a while .... */ error = uscsi_command(SCSI_WRITECMD, dev, cmd, 6, buffer, sizeof(buffer), UINT_MAX, &sense); if (error) return error; uscsi_waitop(dev); return 0; } int uscsi_format_disc(struct uscsi_dev *dev, int immed, int format_type, uint32_t blocks, uint32_t param, int certification, int cmplist) { scsicmd cmd; struct uscsi_sense sense; uint8_t buffer[16], fmt_flags; int error; fmt_flags = 0x80; /* valid info flag */ if (immed) fmt_flags |= 2; if (certification == 0) fmt_flags |= 32; if (cmplist) cmplist = 8; #if 0 if (mmc_profile != 0x43) { /* certification specifier only valid for BD-RE */ certification = 0; } #endif bzero(cmd, SCSI_CMD_LEN); bzero(buffer, sizeof(buffer)); cmd[0] = 0x04; /* format unit */ cmd[1] = 0x11 | cmplist; /* parameter list format 1 follows */ cmd[5] = 0; /* control */ /* format list header */ buffer[ 0] = 0; /* reserved */ buffer[ 1] = 0x80 | fmt_flags; /* Valid info, flags follow */ buffer[ 2] = 0; /* MSB format descriptor length */ buffer[ 3] = 8; /* LSB ... */ /* 8 bytes of format descriptor */ buffer[ 4] = (blocks >> 24) & 0xff; /* blocks MSB */ buffer[ 5] = (blocks >> 16) & 0xff; buffer[ 6] = (blocks >> 8) & 0xff; buffer[ 7] = (blocks ) & 0xff; /* blocks LSB */ buffer[ 8] = (format_type << 2) | certification; buffer[ 9] = (param >> 16) & 0xff; /* parameter MSB */ buffer[10] = (param >> 8) & 0xff; /* packet size */ buffer[11] = (param ) & 0xff; /* parameter LSB */ /* this will take a while .... */ error = uscsi_command(SCSI_WRITECMD, dev, cmd, 6, buffer, 12, UINT_MAX, &sense); if (error) return error; if (immed) uscsi_waitop(dev); return 0; } int uscsi_blank_disc(struct uscsi_dev *dev) { scsicmd cmd; int error; /* XXX check if the device can blank! */ /* blank disc */ bzero(cmd, SCSI_CMD_LEN); cmd[ 0] = 0xA1; /* blank */ cmd[ 1] = 16; /* Immediate, blank complete */ cmd[11] = 0; /* control */ /* this will take a while .... */ error = uscsi_command(SCSI_WRITECMD, dev, cmd, 12, NULL, 0, UINT_MAX, NULL); if (error) return error; uscsi_waitop(dev); return 0; } int usage(char *program) { fprintf(stderr, "\n"); fprintf(stderr, "Usage: %s [options] devicename\n", program); fprintf(stderr, "-B blank cd-rw disc before formatting\n" "-F format cd-rw disc\n" "-O CD-RW formatting 'old-style' for old CD-RW drives\n" "-M select MRW format\n" "-R restart MRW & DVD+RW format\n" "-G grow last CD-RW/DVD-RW session\n" "-S grow spare space DVD-RAM/BD-RE\n" "-s format DVD+MRW/BD-RE with extra spare space\n" "-w wait until completion of background format\n" "-p explicitly set packet format\n" "-c num media certification for DVD-RAM/BD-RE : " "0 no, 1 full, 2 quick\n" "-r recompile defect list for DVD-RAM (cmplist)\n" "-h -H -I help/inquiry formats\n" "-X format expert format selector form 'fmt:blks:param' with -c\n" "-b blockingnr in sectors (for CD-RW)\n" "-D verbose SCSI command errors\n" ); return 1; } extern char *optarg; extern int optind; extern int optreset; #define max_caps_len 512 int main(int argc, char *argv[]) { struct uscsi_addr saddr; uint32_t caps_len = max_caps_len; uint32_t blks[256], params[256]; uint32_t format_type, format_blks, format_param, blockingnr; uint8_t allow[256]; uint8_t caps[max_caps_len]; char *progname; int blank, format, mrw, background; int inquiry, spare, oldtimer; int expert; int restart_format, grow_session, grow_spare, packet_wr; int mmc_profile, flag, error, display_usage; int certification, cmplist; int wait_until_finished; progname = strdup(argv[0]); if (argc == 1) { return usage(progname); } blank = 0; format = 0; mrw = 0; restart_format = 0; grow_session = 0; grow_spare = 0; wait_until_finished = 0; packet_wr = 0; certification = 1; cmplist = 0; inquiry = 0; spare = 0; inquiry = 0; oldtimer = 0; expert = 0; display_usage = 0; blockingnr = 32; uscsilib_verbose = 0; while ((flag = getopt(argc, argv, "BFMRGSwpsc:rhHIX:Ob:D")) != -1) { switch (flag) { case 'B' : blank = 1; break; case 'F' : format = 1; break; case 'M' : mrw = 1; break; case 'R' : restart_format = 1; break; case 'G' : grow_session = 1; break; case 'S' : grow_spare = 1; break; case 'w' : wait_until_finished = 1; break; case 'p' : packet_wr = 1; break; case 's' : spare = 1; break; case 'c' : certification = atoi(optarg); break; case 'r' : cmplist = 1; break; case 'h' : case 'H' : display_usage = 1; case 'I' : inquiry = 1; break; case 'X' : /* TODO parse expert mode string */ printf("-X not implemented yet\n"); expert = 1; exit(1); break; case 'O' : /* oldtimer CD-RW format */ oldtimer = 1; format = 1; break; case 'b' : blockingnr = atoi(optarg); break; case 'D' : uscsilib_verbose = 1; break; default : return usage(progname); } } argv += optind; argc -= optind; if ((!blank && !format && !grow_session && !grow_spare) && (!expert && !inquiry)) { fprintf(stderr, "%s : at least one of -B, -F, -G, -S, -X or -I " "needs to be specified\n\n", progname); return usage(progname); } if (format + grow_session + grow_spare + expert > 1) { fprintf(stderr, "%s : at most one of -F, -G, -S or -X " "needs to be specified\n\n", progname); return usage(progname); } if (argc != 1) return usage(progname); /* Open the device */ dev.dev_name = strdup(*argv); printf("Opening device %s\n", dev.dev_name); error = uscsi_open(&dev); if (error) { fprintf(stderr, "Device failed to open : %s\n", strerror(error)); exit(1); } error = uscsi_check_for_scsi(&dev); if (error) { fprintf(stderr, "sorry, not a SCSI/ATAPI device : %s\n", strerror(error)); exit(1); } error = uscsi_identify(&dev, &saddr); if (error) { fprintf(stderr, "SCSI/ATAPI identify returned : %s\n", strerror(error)); exit(1); } printf("\nDevice identifies itself as : "); if (saddr.type == USCSI_TYPE_SCSI) { printf("SCSI busnum = %d, target = %d, lun = %d\n", saddr.addr.scsi.scbus, saddr.addr.scsi.target, saddr.addr.scsi.lun); } else { printf("ATAPI busnum = %d, drive = %d\n", saddr.addr.atapi.atbus, saddr.addr.atapi.drive); } printf("\n"); /* get MMC profile */ error = uscsi_get_mmc_profile(&dev, &mmc_profile); if (error) { fprintf(stderr, "Can't get the disc's MMC profile because of :" " %s\n", strerror(error)); fprintf(stderr, "aborting\n"); uscsi_close(&dev); return 1; } /* blank disc section */ if (blank) { printf("\nBlanking disc.... "); fflush(stdout); error = uscsi_blank_disc(&dev); if (error) { printf("fail\n"); fflush(stdout); fprintf(stderr, "Blanking failed because of : %s\n", strerror(error)); uscsi_close(&dev); return 1; } else { printf("success!\n\n"); } } /* re-get MMC profile */ error = uscsi_get_mmc_profile(&dev, &mmc_profile); if (error) { fprintf(stderr, "Can't get the disc's MMC profile because of : %s\n", strerror(error)); fprintf(stderr, "aborting\n"); uscsi_close(&dev); return 1; } error = get_format_capabilities(&dev, caps, &caps_len); if (error) exit(1); process_format_caps(caps, caps_len, inquiry, allow, blks, params); if (!format && !expert && inquiry) { /* we're done */ if (display_usage) usage(progname); uscsi_close(&dev); exit(0); } format_type = 0; /* expert format section */ if (expert) { } /* normal format section */ if (format) { /* get current mmc profile of disc */ if (oldtimer && mmc_profile != 0x0a) { printf("Oldtimer flag only defined for CD-RW; " "ignored\n"); } switch (mmc_profile) { case 0x12 : /* DVD-RAM */ format_type = 0x00; break; case 0x0a : /* CD-RW */ format_type = mrw ? 0x24 : 0x10; packet_wr = 1; break; case 0x13 : /* DVD-RW restricted overwrite */ case 0x14 : /* DVD-RW sequential */ format_type = 0x10; /* * Some drives suddenly stop supporting this format * type when packet_wr = 1 */ packet_wr = 0; break; case 0x1a : /* DVD+RW */ format_type = mrw ? 0x24 : 0x26; break; case 0x43 : /* BD-RE */ format_type = spare ? 0x30 : 0x31; break; default : fprintf(stderr, "Can't format discs of type %s\n", print_mmc_profile(mmc_profile)); uscsi_close(&dev); exit(1); } } if (grow_spare) { switch (mmc_profile) { case 0x12 : /* DVD-RAM */ case 0x43 : /* BD-RE */ format_type = 0x01; break; default : fprintf(stderr, "Can't grow spare area for discs of type %s\n", print_mmc_profile(mmc_profile)); uscsi_close(&dev); exit(1); } } if (grow_session) { switch (mmc_profile) { case 0x0a : /* CD-RW */ format_type = 0x11; break; case 0x13 : /* DVD-RW restricted overwrite */ case 0x14 : /* DVD-RW sequential ? */ format_type = 0x13; break; default : uscsi_close(&dev); fprintf(stderr, "Can't grow session for discs of type %s\n", print_mmc_profile(mmc_profile)); exit(1); } } /* check if format type is allowed */ format_blks = blks[format_type]; format_param = params[format_type]; if (!allow[format_type]) { if (!inquiry) process_format_caps(caps, caps_len, 1, allow, blks, params); printf("\n"); fflush(stdout); fprintf(stderr, "Drive indicates it can't format with deduced format " "type 0x%02x\n", format_type); uscsi_close(&dev); exit(1); } if (restart_format && !((mmc_profile == 0x1a) || (format_type == 0x24))) { fprintf(stderr, "Format restarting only for MRW formats or DVD+RW " "formats\n"); uscsi_close(&dev); exit(1); } if (restart_format && !wait_until_finished) { printf( "Warning : format restarting without waiting for it be " "finished is prolly not handy\n"); } /* explicitly select packet write just in case */ if (packet_wr) { printf("Explicitly setting packet type and blocking number\n"); error = uscsi_set_packet_parameters(&dev, blockingnr); if (error) { fprintf(stderr, "Can't set packet writing and blocking number: " "%s\n", strerror(error)); uscsi_close(&dev); exit(1); } } /* determine if formatting is done in the background */ background = 0; if (format_type == 0x24) background = 1; if (format_type == 0x26) background = 1; /* special case format type 0x24 : MRW */ if (format_type == 0x24) { format_blks = spare ? 0xffff0000 : 0xffffffff; format_param = restart_format; } /* special case format type 0x26 : DVD+RW */ if (format_type == 0x26) { format_param = restart_format; } /* verbose to the user */ DEBUG( printf("Actual format selected: " "format_type 0x%02x, blks %d, param %d, " "certification %d, cmplist %d\n", format_type, format_blks, format_param, certification, cmplist); ); printf("\nFormatting.... "); fflush(stdout); /* formatting time! */ if (oldtimer) { error = uscsi_format_cdrw_mode7(&dev, format_blks); background = 0; } else { error = uscsi_format_disc(&dev, !background, format_type, format_blks, format_param, certification, cmplist); } /* what now? */ if (error) { printf("fail\n"); fflush(stdout); fprintf(stderr, "Formatting failed because of : %s\n", strerror(error)); } else { if (background) { printf("background formatting in progress\n"); if (wait_until_finished) { printf("Waiting for completion ... "); uscsi_waitop(&dev); } /* explicitly do NOT close disc ... (for now) */ return 0; } else { printf("success!\n\n"); } } /* finish up */ uscsi_close(&dev); return error; } #undef max_caps_len UDFclient.0.8.8/udf_bmap.c010066400001470000000000000326421307041400500146070ustar reinoudwheel/* $NetBSD$ */ /* * File "udf_bmap.c" is part of the UDFclient toolkit. * File $Id: udf_bmap.c,v 1.28 2016/04/25 21:01:40 reinoud Exp $ $Name: $ * * Copyright (c) 2003, 2004, 2005, 2006, 2011 * Reinoud Zandijk * All rights reserved. * * The UDFclient toolkit is distributed under the Clarified Artistic Licence. * A copy of the licence is included in the distribution as * `LICENCE.clearified.artistic' and a copy of the licence can also be * requested at the GNU foundantion's website. * * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* XXX strip list to bare minimum XXX */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "uscsilib.h" /* for locals */ #include "udf.h" #include "udf_bswap.h" #include "udf_discop.h" #include "uio.h" #include #ifndef MAX # define MAX(a,b) ((a)>(b)?(a):(b)) # define MIN(a,b) ((a)<(b)?(a):(b)) #endif //#define DEBUG(a) { a; } #define DEBUG(a) if (0) { a; } void udf_dump_allocentry_queue(char *msg, struct udf_alloc_entries *queue, uint32_t lb_size); /****************************************************************************************** * * Get and release free logical blocks from the free space tables * ******************************************************************************************/ /* * simple metadata distribution algorithm; first part of each block is * metadata followed by data; the offset this blocking can be tweaked by * part_offset. */ static int udf_allocate_lbs_on_rewritables(struct udf_partition *udf_partition, uint64_t part_offset, uint64_t metadata_granularity, uint32_t lb_size, uint64_t req_size, int content, uint32_t *res_start_lb, uint32_t *res_num_lbs) { struct udf_allocentry *alloc_entry, *chosen; struct udf_alloc_entries *queue; uint64_t start; uint64_t chosen_offset; uint64_t size; int error, is_meta; /* allways unalloc_space_queue ? */ queue = &udf_partition->unalloc_space_queue; /* TODO this is a simplification; no multiple queues yet XXX */ is_meta = (content != UDF_C_USERDATA); /* start from the beginning of the unallocated space queue */ alloc_entry = TAILQ_FIRST(queue); start = alloc_entry->lb_num; assert(start == 0); chosen = NULL; chosen_offset = 0; size = 0; TAILQ_FOREACH(alloc_entry, queue, next_alloc) { /* we can only start on lb_size (extra sanity check) */ assert(start % lb_size == 0); /* piecewise if nessisary */ size = MIN(alloc_entry->len, req_size); size = (uint64_t) lb_size * (size / lb_size); if (size == 0) continue; /* we can only give out on lb_size boundaries */ assert(size % lb_size == 0); if (alloc_entry->flags == UDF_SPACE_FREE) { DEBUG(printf("got free entry from %"PRIu64" + %"PRIu64"\n", start / lb_size, (start + alloc_entry->len)/lb_size)); if (is_meta) { if (start + req_size + part_offset <= metadata_granularity) { chosen = alloc_entry; chosen_offset = 0; } } else { chosen_offset = 0; if (start + part_offset < metadata_granularity) { chosen_offset = metadata_granularity - (start + part_offset); } if (chosen_offset + size <= alloc_entry->len) { chosen = alloc_entry; } } DEBUG(if (chosen && (size > 0)) printf("chosen\n")); } if (size <= 0) chosen = NULL; if (chosen) break; /* foreach */ start = start + alloc_entry->len; } /* FOREACH */ if (!chosen) return ENOSPC; assert(size > 0); assert(size % lb_size == 0); assert(chosen->len % lb_size == 0); assert(start + chosen_offset + size <= start + chosen->len); start += chosen_offset; *res_start_lb = start / lb_size; *res_num_lbs = size / lb_size; error = udf_mark_allocentry_queue(queue, lb_size, start, size, UDF_SPACE_ALLOCATED, NULL, NULL); return error; } /* get at most req_lbs from the partition and mark the area used */ static int udf_allocate_lbs_on_partition(struct udf_log_vol *udf_log_vol, uint16_t vpart_num, uint32_t req_lbs, int content, uint32_t *res_start_lb, uint32_t *res_num_lbs) { struct udf_partition *udf_partition; struct udf_part_mapping *udf_part_mapping; struct udf_alloc_entries *queue; uint64_t part_length; uint64_t metadata_granularity, metadata_blk_len; uint64_t part_offset; uint32_t lb_size, num_lbs; uint64_t req_size; uint32_t cnt; int error; assert(udf_log_vol); lb_size = udf_log_vol->lb_size; error = udf_logvol_vpart_to_partition(udf_log_vol, vpart_num, &udf_part_mapping, &udf_partition); if (error) return error; // part_start = (uint64_t) lb_size * udf_rw32(udf_partition->partition->start_loc); part_length = (uint64_t) lb_size * udf_rw32(udf_partition->partition->part_len); req_size = (uint64_t) lb_size * req_lbs; /* lock against corruption with free */ UDF_MUTEX_LOCK(&udf_partition->partition_space_mutex); switch (udf_part_mapping->udf_part_mapping_type) { case UDF_PART_MAPPING_PHYSICAL : case UDF_PART_MAPPING_SPARABLE : /* sparable is just like the physical mapping */ /* allways unalloc_space_queue ? */ queue = &udf_partition->unalloc_space_queue; udf_merge_allocentry_queue(queue, lb_size); DEBUG(udf_dump_allocentry_queue("Alloc ", queue, lb_size)); metadata_granularity = part_length / 1024; metadata_blk_len = metadata_granularity / 16; part_offset = 0; for (cnt = 0; cnt <= (metadata_granularity / metadata_blk_len); cnt++) { num_lbs = 0; error = udf_allocate_lbs_on_rewritables(udf_partition, part_offset, metadata_granularity, lb_size, req_size, content, res_start_lb, &num_lbs); if (error) { assert(error == ENOSPC); /* disc is most likely getting full with (meta) data; shift window */ part_offset += metadata_blk_len; num_lbs = 0; } else { assert(num_lbs >= 1); udf_partition->free_unalloc_space -= num_lbs * lb_size; udf_log_vol->free_space -= num_lbs * lb_size; break; /* for */ } } *res_num_lbs = num_lbs; break; case UDF_PART_MAPPING_VIRTUAL : /* strict increasing virtual adress giveout */ printf("UDF: get lbs from virtual partition mapping not implemented yet\n"); return EBADF; case UDF_PART_MAPPING_META : /* select blobs from the metadata file */ if (udf_part_mapping->meta_bitmap_file == NULL) return EROFS; printf("UDF: get lbs from metadata partition mapping not implemented yet\n"); break; case UDF_PART_MAPPING_PSEUDO_RW : /* strict increasing adress giveout from the pseudo over. track */ printf("UDF: get lbs from pseudo overwritable partition not implemented yet\n"); break; } /* sanity */ if (*res_num_lbs == 0) *res_start_lb = 0; /* release partition unalloced and freed space again */ UDF_MUTEX_UNLOCK(&udf_partition->partition_space_mutex); return error; } /****************************************************************************************** * * Upper level free space allocation and releasing. * ******************************************************************************************/ int udf_allocate_lbs(struct udf_log_vol *udf_log_vol, int content, uint32_t req_lbs, char *what, uint16_t *res_vpart_num, uint32_t *res_start_lb, uint32_t *res_num_lbs) { struct udf_partition *udf_partition; struct udf_part_mapping *udf_part_mapping; uint32_t num_lbs; uint16_t vpart_num; int is_meta, ok; int error; assert(udf_log_vol); num_lbs = 0; /* shutup gcc */ /* select udf partition to write to depending on the contents */ is_meta = ((content == UDF_C_FIDS) || (content == UDF_C_NODE)); vpart_num = is_meta ? udf_log_vol->metadata_vpart : udf_log_vol->data_vpart; /* TODO what about when space is freed in an earlier partition ? reset the vpart's ? */ DEBUG(printf("UDF allocate %d lbs for node `%s`\n", req_lbs, what)); do { DEBUG(printf("do: vpart_num = %d\n", vpart_num)); error = udf_logvol_vpart_to_partition(udf_log_vol, vpart_num, &udf_part_mapping, &udf_partition); ok = (udf_partition != NULL) && (udf_part_mapping != NULL); if (ok && !is_meta) ok = udf_part_mapping->data_writable; if (ok && is_meta) ok = udf_part_mapping->metadata_writable; if (ok) { /* try to snoop from this vpart */ error = udf_allocate_lbs_on_partition(udf_log_vol, vpart_num, req_lbs, content, res_start_lb, &num_lbs); if (!error) { *res_vpart_num = vpart_num; if (res_num_lbs) *res_num_lbs = num_lbs; } ok = !error; } if (!ok) { DEBUG(printf("advance vpart\n")); vpart_num = is_meta ? ++(udf_log_vol->metadata_vpart) : ++(udf_log_vol->data_vpart); if (vpart_num >= udf_log_vol->num_part_mappings) { udf_log_vol->metadata_vpart = udf_log_vol->data_vpart = 0; printf("UDF: logvol discs full ?\n"); return ENOSPC; } } } while (!ok); DEBUG(printf("udf_allocate_lbs: got space on vpart_num = %d; req %d, got %d\n", vpart_num, req_lbs, num_lbs)); assert((*res_start_lb != 0) && (num_lbs != 0)); return 0; } int udf_node_allocate_lbs(struct udf_node *udf_node, int req_lbs, uint16_t *res_vpart_num, uint32_t *res_start_lb, uint32_t *res_num_lbs) { char *what; int content; /* content can be USERDATA or FID stream here; checking on udf filetype */ switch (udf_node->udf_filetype) { case UDF_ICB_FILETYPE_DIRECTORY : case UDF_ICB_FILETYPE_STREAMDIR : content = UDF_C_FIDS; what = "FID stream"; break; default : content = UDF_C_USERDATA; what = "file content"; break; } return udf_allocate_lbs(udf_node->udf_log_vol, content, req_lbs, what, res_vpart_num, res_start_lb, res_num_lbs); } /* returns non zero if space is available */ int udf_confirm_freespace(struct udf_log_vol *udf_log_vol, int content, uint64_t size) { content = content; /* not used now */ /* generic check for now */ if (udf_log_vol->free_space >= udf_log_vol->await_alloc_space + size + UDF_MINFREE_LOGVOL) { return 1; } return 0; } int udf_release_lbs(struct udf_log_vol *udf_log_vol, uint16_t vpart_num, uint32_t lb_num, uint64_t size) { struct udf_partition *udf_partition; struct udf_part_mapping *udf_part_mapping; struct udf_alloc_entries *queue; uint32_t lb_size; int error; if (!udf_log_vol) return 0; lb_size = udf_log_vol->lb_size; error = udf_logvol_vpart_to_partition(udf_log_vol, vpart_num, &udf_part_mapping, &udf_partition); if (error) return error; /* space can only be freed in lb_size chuncks by definition */ size = (uint64_t) lb_size * ((size + lb_size -1) / lb_size); switch (udf_part_mapping->udf_part_mapping_type) { case UDF_PART_MAPPING_PHYSICAL : case UDF_PART_MAPPING_SPARABLE : /* sparable is just like the physical mapping */ queue = &udf_partition->unalloc_space_queue; /* TODO freed- for non sequential MO media */ UDF_MUTEX_LOCK(&udf_partition->partition_space_mutex); error = udf_mark_allocentry_queue(queue, lb_size, (uint64_t) lb_num * lb_size, size, UDF_SPACE_FREE, NULL, NULL); udf_partition->free_unalloc_space += size; udf_log_vol->free_space += size; UDF_MUTEX_UNLOCK(&udf_partition->partition_space_mutex); return error; case UDF_PART_MAPPING_VIRTUAL : /* freeing is not applicable */ return 0; case UDF_PART_MAPPING_META : /* free blobs in the metadata file */ printf("UDF: freeing lbs from metadata partition mapping not implemented yet\n"); break; case UDF_PART_MAPPING_PSEUDO_RW : /* do we have to keep a space bitmap? */ printf("UDF: freeing lbs from pseudo rewritable partition mapping not implemented yet\n"); break; } return 0; } /* !!! needs to be called with alloc entry mutex held !!! */ int udf_node_release_extent(struct udf_node *udf_node, uint64_t from, uint64_t to) { struct udf_allocentry *from_ae, *to_ae, *alloc_entry, *last_alloc_entry; uint32_t lb_size, lbnum, len; uint16_t vpart; int error, flags; assert(udf_node->alloc_mutex.locked); assert(udf_node->udf_log_vol); lb_size = udf_node->udf_log_vol->lb_size; error = udf_splitup_allocentry_queue(&udf_node->alloc_entries, lb_size, from, to-from, &from_ae, &to_ae); if (!error) { alloc_entry = from_ae; last_alloc_entry = TAILQ_NEXT(to_ae, next_alloc); while (alloc_entry != last_alloc_entry) { vpart = alloc_entry->vpart_num; lbnum = alloc_entry->lb_num; flags = alloc_entry->flags; len = alloc_entry->len; if (flags == UDF_SPACE_ALLOCATED) { error = udf_release_lbs(udf_node->udf_log_vol, vpart, lbnum, len); assert(!error); alloc_entry->flags = UDF_SPACE_FREE; /* WORM: or freed? */ } else { DEBUG(printf("udf_filepart_free_extent :freeing a non allocated piece : flags = %d\n", flags)); } alloc_entry = TAILQ_NEXT(alloc_entry, next_alloc); } } else { fprintf(stderr, "udf_filepart_free_extent: splitup failed\n"); } return 0; } /* end of udf_bmap.c */ UDFclient.0.8.8/udf_discop.c010066400001470000000000001260261307041400500151510ustar reinoudwheel/* $NetBSD$ */ /* * File "udf_discinfo.c" is part of the UDFclient toolkit. * File $Id: udf_discop.c,v 1.81 2017/01/16 14:33:06 reinoud Exp $ $Name: $ * * Copyright (c) 2003, 2004, 2005, 2006, 2011 * Reinoud Zandijk * All rights reserved. * * The UDFclient toolkit is distributed under the Clarified Artistic Licence. * A copy of the licence is included in the distribution as * `LICENCE.clearified.artistic' and a copy of the licence can also be * requested at the GNU foundantion's website. * * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* XXX strip this XXX */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "uscsilib.h" /* for locals */ #include "uscsilib.h" #include "udf_discop.h" #ifndef MAX # define MAX(a,b) ((a)>(b)?(a):(b)) # define MIN(a,b) ((a)<(b)?(a):(b)) #endif /* #define DEBUG(a) { a; } */ #define DEBUG(a) if (0) { a; } /* globals */ /****************************************************************************************** * * Tables and helper functions section * ******************************************************************************************/ int read_cd_hex2(int val) { int nl, nh; nl = val & 15; nh = val >> 4; if (nl >= 'A') nl -= 'A' + 10; if (nh >= 'A') nh -= 'A' + 10; return (nh*16) + nl; } int read_cd_bcd(int val) { int nl, nh; nl = (val & 15) - '0'; nh = (val >> 4) - '0'; if ((nl < 0 || nl > 9) || (nh < 0 || nh > 9)) return val; return nh*10 + nl; } int32_t cd_msf2lba(int h, int m, int s, int f) { return 270000*h + 4500*m + 75*s + f - 150; } /****************************************************************************************** * * Disc level operations * ******************************************************************************************/ int udf_discinfo_is_cd_or_dvd(struct udf_discinfo *disc) { /* check device type */ switch (disc->devdrv_class & UDF_DEVDRV_CLASS) { case UDF_DEVDRV_CLASS_FILE : case UDF_DEVDRV_CLASS_DISC : /* not nessisary */ return 0; case UDF_DEVDRV_CLASS_CD : case UDF_DEVDRV_CLASS_DVD : /* it really is */ return 1; default : break; } return ENODEV; } int udf_discinfo_check_disc_ready(struct udf_discinfo *disc) { scsicmd cmd; uint8_t buf[36]; int error; if (!udf_discinfo_is_cd_or_dvd(disc)) return 1; bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0; /* test unit ready */ error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 6, buf, 0, 30000, NULL); return (error == 0); } #define blk_len 10000 int udf_discinfo_set_recording_parameters(struct udf_discinfo *discinfo, int testwriting) { scsicmd cmd; uint8_t res[blk_len]; uint8_t *pos; uint32_t blockingnr; int val_len, packet; int error; if (!udf_discinfo_is_cd_or_dvd(discinfo)) return 0; /* Set up CD/DVD recording parameters */ if (!discinfo->recordable) return 0; blockingnr = discinfo->blockingnr; DEBUG(printf("Setting device's recording parameters\n")); packet = discinfo->packet; val_len = 0x32+2+8; bzero(res, val_len); pos = res + 8; bzero(cmd, SCSI_CMD_LEN); if (!packet) { pos[ 0] = 0x05; /* page code 5 : cd writing */ pos[ 1] = 0x32; /* length in bytes */ pos[ 2] = 64 + 0; /* BUFE + write type 1 : track at once */ if (testwriting) pos[ 2] += 16; pos[ 3] = (3<<6) | 5; /* next session OK, data packet, rec. incr. var packets */ pos[ 4] = 8; /* ISO mode 1 */ pos[ 8] = 0; /* normal CD-DA/CD-ROM or data disc */ DEBUG(printf("\tsetting up for sequential writing\n")); } else { pos[ 0] = 0x05; /* page code 5 : cd writing */ pos[ 1] = 0x32; /* length in bytes */ pos[ 2] = 0; /* write type 0 : packet/incremental */ if (testwriting) pos[ 2] += 16; pos[ 3] = (3<<6) | 32 | 5; /* next session OK, data packet, rec. incr. fixed packets */ pos[ 4] = 10; /* ISO mode 2; XA form 1 */ pos[ 8] = 0x20; /* CD-ROM XA disc or DDCD disc */ pos[10] = (blockingnr >> 24) & 0xff; /* MSB packet size */ pos[11] = (blockingnr >> 16) & 0xff; pos[12] = (blockingnr >> 8) & 0xff; pos[13] = (blockingnr ) & 0xff; /* LSB packet size in SECTORS */ DEBUG(printf("\tsetting up for packet writing with packet size %d\n", blockingnr)); } bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x55; /* MODE SELECT (10) */ cmd[1] = 16; /* PF format */ cmd[7] = val_len >> 8; /* length of blob */ cmd[8] = val_len & 0xff; cmd[9] = 0; /* control */ error = uscsi_command(SCSI_WRITECMD, discinfo->dev, cmd, 10, res, val_len, 3000, NULL); if (error) { perror("While WRTITING parameter page 5"); return error; } #if 0 /* Set CD/DVD speed to 'optimal' for it doesnt seem to do it automatically */ bzero(cmd, SCSI_CMD_LEN); cmd[ 0] = 0xBB; /* Set CD speed */ cmd[ 1] = 1; /* select CAV (1) or CLV (0) recording */ cmd[ 2] = 0xff; cmd[ 3] = 0xff; /* max read performance speed */ cmd[ 4] = 0xff; cmd[ 5] = 0xff; /* max write performance speed; applic? */ cmd[11] = 0; /* control */ error = scsi_call(SCSI_WRITECMD, discinfo, cmd, 12, NULL, 0, NULL); if (error) { /* CAV not possible? then go for CLV */ cmd[ 1] = 0; /* select CAV (1) or CLV (0) recording */ error = scsi_call(SCSI_WRITECMD, discinfo, cmd, 12, NULL, 0, NULL); if (error) { perror("While setting speed"); return error; } } #endif /* flag OK */ return 0; } #undef blk_len int udf_discinfo_synchronise_caches(struct udf_discinfo *discinfo) { scsicmd cmd; int error; /* bail out when we're in sequential emulation */ if (!udf_discinfo_is_cd_or_dvd(discinfo)) return 0; bzero(cmd, SCSI_CMD_LEN); cmd[ 0] = 0x35; /* Synchronise cache */ cmd[ 9] = 0; /* control */ error = uscsi_command(SCSI_WRITECMD, discinfo->dev, cmd, 10, NULL, 0, 30000, NULL); if (error) { perror("While synchronising write cache"); } return error; } /* * important: it must be called after write operations before read operations * are allowed again. When its allready finished with writing this call has no * effect and can be called at start to make sure the device knows that we're * going to read. */ int udf_discinfo_finish_writing(struct udf_discinfo *discinfo) { int error; if (!udf_discinfo_is_cd_or_dvd(discinfo)) return 0; error = udf_discinfo_synchronise_caches(discinfo); return error; } int udf_discinfo_reserve_track_in_logic_units(struct udf_discinfo *discinfo, uint32_t logic_units) { scsicmd cmd; int error; if (!udf_discinfo_is_cd_or_dvd(discinfo)) return ENODEV; bzero(cmd, SCSI_CMD_LEN); cmd[ 0] = 0x53; /* reserve track */ cmd[ 5] = (logic_units >> 24) & 0xff; /* size MSB */ cmd[ 6] = (logic_units >> 16) & 0xff; cmd[ 7] = (logic_units >> 8) & 0xff; cmd[ 8] = (logic_units ) & 0xff; /* size LSB */ cmd[ 9] = 0; /* control */ error = uscsi_command(SCSI_WRITECMD, discinfo->dev, cmd, 10, NULL, 0, 30000, NULL); return error; } int udf_discinfo_close_track(struct udf_discinfo *discinfo, uint16_t trackno) { scsicmd cmd; int error; if (!udf_discinfo_is_cd_or_dvd(discinfo)) return ENODEV; bzero(cmd, SCSI_CMD_LEN); cmd[ 0] = 0x5B; /* close session/track */ cmd[ 2] = 1; /* track */ cmd[ 4] = (trackno >> 8) & 0xff; /* specify trackno MSB */ cmd[ 5] = (trackno ) & 0xff; /* trackno LSB */ cmd[ 9] = 0; /* control */ error = uscsi_command(SCSI_WRITECMD, discinfo->dev, cmd, 10, NULL, 0, 30000, NULL); return error; } /* can only close last session */ int udf_discinfo_close_session(struct udf_discinfo *discinfo) { scsicmd cmd; int error; if (!udf_discinfo_is_cd_or_dvd(discinfo)) return ENODEV; bzero(cmd, SCSI_CMD_LEN); cmd[ 0] = 0x5B; /* close session/track */ cmd[ 2] = 2; /* session */ cmd[ 9] = 0; /* control */ error = uscsi_command(SCSI_WRITECMD, discinfo->dev, cmd, 10, NULL, 0, 30000, NULL); return error; } /* * Repair a damaged track when suspected. It'll try to make it writable again. * A track can be broken when sudden stops are made and the track end is left * in a inconsistent state in the ATIP/PMA/TOC. */ int udf_discinfo_repair_track(struct udf_discinfo *discinfo, uint16_t trackno) { scsicmd cmd; int error; if (!udf_discinfo_is_cd_or_dvd(discinfo)) return ENODEV; bzero(cmd, SCSI_CMD_LEN); cmd[ 0] = 0x58; /* repair track */ cmd[ 4] = (trackno >> 8) & 0xff; /* specify trackno MSB */ cmd[ 5] = (trackno ) & 0xff; /* trackno LSB */ cmd[ 9] = 0; /* control */ error = uscsi_command(SCSI_WRITECMD, discinfo->dev, cmd, 10, NULL, 0, 30000, NULL); return error; } /* * This routine 'get disc type' tries to get operational information from the * disc/drive combination and its capabilities. Fills in devdrv_class, MMC * profile and the various flags; no track info. */ int udf_discinfo_get_disc_type(struct udf_discinfo *disc) { struct stat stat; scsicmd cmd; uint8_t buf[256]; uint8_t features[1024+100], *rpos, *fpos; uint32_t pos, features_len, feat_tbl_len, val_len; uint32_t feature, last_feature; uint32_t feature_ver, feature_pers, feature_cur, feature_len; int error; /* assume generic CD-ROM with no known MMC profile */ disc->devdrv_class = UDF_DEVDRV_CLASS_CD; disc->mmc_profile = 0; /* check if its a regular file */ fstat(disc->dev->fhandle, &stat); if (S_ISREG(stat.st_mode)) { UDF_VERBOSE(printf("UDF device %s is a regular file\n", disc->dev->dev_name)); disc->devdrv_class = UDF_DEVDRV_CLASS_FILE; disc->sequential = 0; /* full r/w */ disc->recordable = 1; /* assuming rw access */ disc->blankable = 0; /* not applicable */ disc->rewritable = 1; disc->packet = 0; disc->blockingnr = 1; disc->strict_overwrite = 0; disc->sector_size = DISC_SECTOR_SIZE; return 0; } /* check if its a ATIPI/SCSI device */ error = uscsi_check_for_scsi(disc->dev); if (error) { /* obviously no ATIPI/SCSI device -> has to be IDE disc or other but no file either */ disc->devdrv_class = UDF_DEVDRV_CLASS_DISC; disc->sequential = 0; /* full r/w */ disc->recordable = 1; /* assuming rw access */ disc->blankable = 0; /* not applicable */ disc->rewritable = 1; disc->packet = 0; disc->blockingnr = 1; disc->strict_overwrite = 0; disc->sector_size = DISC_SECTOR_SIZE; UDF_VERBOSE(printf("Got error executing SCSI command, assuming IDE disc\n")); return 0; } /* check if its a SCSI disc -> if so, do NOT issue mmc profile check */ bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x12; /* INQUIRY */ cmd[1] = 0; /* basic inquiry */ cmd[2] = 0; /* no page or operation code */ cmd[3] = 0; /* reserved/MSB result */ cmd[4] = 96; /* all but vendor specific */ cmd[5] = 0; /* control */ error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 6, buf, 96, 30000, NULL); if (error) { fprintf(stderr, "Device claims to be SCSI but does NOT respond to inquiry!\n"); return ENOENT; } disc->scsi_device_type = buf[0] & 0x1f; switch (disc->scsi_device_type) { case 0x05 : break; /* MMC */ case 0x00 : /* Direct access device */ case 0x0E : /* Simplified direct access device */ /* read-write possible */ disc->devdrv_class = UDF_DEVDRV_CLASS_DISC; disc->sequential = 0; /* full r/w */ disc->recordable = 1; /* assuming rw access */ disc->blankable = 0; /* not applicable */ disc->rewritable = 1; disc->packet = 0; disc->blockingnr = 1; disc->strict_overwrite = 0; disc->sector_size = DISC_SECTOR_SIZE; return 0; case 0x04 : case 0x07 : /* Non MMC read only optical media */ disc->devdrv_class = UDF_DEVDRV_CLASS_DISC; disc->sequential = 0; /* */ disc->recordable = 0; /* assuming ro access */ disc->blankable = 0; /* not applicable */ disc->rewritable = 0; disc->packet = 0; disc->blockingnr = 1; disc->strict_overwrite = 0; disc->sector_size = DISC_SECTOR_SIZE; return 0; default: fprintf(stderr, "Device type 0x%02x not suitable for mass storage\n", disc->scsi_device_type); return ENOENT; } /* get MMC profile */ bzero(cmd, SCSI_CMD_LEN); cmd[ 0] = 0x46; /* Get configuration */ cmd[ 8] = 32; /* just a small buffer size */ cmd[ 9] = 0; /* control */ error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, buf, 32, 30000, NULL); if (!error) { disc->mmc_profile = buf[7] | (buf[6] << 8); } else { disc->mmc_profile = 0; /* mark unknown MMC profile */ } UDF_VERBOSE_MAX(printf("Device has MMC profile 0x%02x\n", disc->mmc_profile)); /* determine CD sector size */ bzero(buf, 8); bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x25; /* CD READ RECORDED CAPACITY */ error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, buf, 8, 30000, NULL); if (error) { fprintf(stderr, "Can't read CD recorded capacity; assuming sector size %d : %s", CD_SECTOR_SIZE, strerror(error)); disc->sector_size = CD_SECTOR_SIZE; } else { disc->sector_size = buf[7] | (buf[6]<<8) | (buf[5]<<16) | (buf[4]<<24); /* packet size is recorded for each track seperately */ } /* * Read in features to determine device flags. First take some initial * values. */ disc->sequential = 0; disc->recordable = 0; disc->erasable = 0; disc->blankable = 0; disc->formattable = 0; disc->rewritable = 0; disc->mrw = 0; disc->packet = 0; disc->strict_overwrite = 0; disc->blockingnr = 1; /* not relevant if non packet write */ feat_tbl_len = 1024; last_feature = feature = 0; do { bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x46; /* Get configuration */ cmd[1] = 0; /* RT=0 -> all independent of current setting */ cmd[2] = (last_feature) >> 8; /* MSB feature number */ cmd[3] = (last_feature) & 0xff; /* LSB feature number */ cmd[7] = (feat_tbl_len) >> 8; /* MSB buffersize */ cmd[8] = (feat_tbl_len) & 0xff; /* LSB buffersize */ cmd[9] = 0; /* control */ error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, features, feat_tbl_len, 30000, NULL); if (error) { fprintf(stderr, "While reading feature table : %s\n", strerror(error)); return EIO; } features_len = features[3] | (features[2]<<8) | (features[1]<<16) | (features[0]<<24); disc->mmc_profile = features[7] | (features[6]<<8); pos = 8; while (pos < features_len) { fpos = &features[pos]; feature = fpos[1] | (fpos[0] << 8); feature_ver = (fpos[2] >> 2) & 15; feature_cur = (fpos[2] & 1); feature_pers= (fpos[2] & 2); feature_len = fpos[3]; if (feature_cur == 1) { rpos = &fpos[4]; switch (feature) { case 0x0010 : /* random readable feature */ disc->sector_size = rpos[3] | (rpos[2] << 8) | (rpos[1] << 16) | (rpos[0] << 24); disc->blockingnr = rpos[5] | (rpos[4] << 8); /* RW error page */ break; case 0x0020 : /* random writable feature */ disc->recordable = 1; disc->rewritable = 1; break; case 0x0021 : /* incremental streaming write feature */ disc->recordable = 1; disc->sequential = 1; disc->link_size = rpos[7]; if (rpos[6] & 1) disc->link_size = 0; break; case 0x0022 : /* (obsolete) erase support feature */ disc->recordable = 1; disc->erasable = 1; break; case 0x0023 : /* formatting media support feature */ disc->recordable = 1; disc->formattable = 1; break; case 0x0024 : /* hardware assisted defect management feature */ /* XXX set mrw ? */ break; case 0x0025 : /* write once */ disc->recordable = 1; break; case 0x0026 : /* restricted overwrite feature */ disc->recordable = 1; disc->rewritable = 1; disc->strict_overwrite = 1; break; case 0x0028 : /* MRW formatted media support feature */ disc->mrw = 1; break; case 0x002b : /* read/write DVD+R formatted media */ disc->sequential = 1; if (rpos[0] & 1) /* write support */ disc->recordable = 1; break; case 0x002c : /* regid restricted overwrite feature */ disc->recordable = 1; disc->rewritable = 1; disc->strict_overwrite = 1; if (rpos[0] & 1) /* blank bit */ disc->blankable = 1; break; case 0x002d : /* track at once recording feature */ disc->recordable = 1; disc->sequential = 1; break; case 0x002f : /* DVD-R/-RW write feature */ disc->recordable = 1; if (rpos[0] & 2) /* DVD-RW bit */ disc->blankable = 1; break; case 0x0038 : /* pseuro overwritable */ break; default : /* ignore */ break; } } last_feature = MAX(last_feature, feature); if (feature_len & 3) { UDF_VERBOSE(printf("Drive returned feature %d %swith bad length %d\n", feature, (feature_cur == 1? "(current) ":""), feature_len)); feature_len = (feature_len + 3) & ~3; } pos += 4 + feature_len; } } while (features_len >= 0xffff); /* * fixup DVD and CD-RW drives that are on crack. */ if (disc->mmc_profile == 0x0a) { /* some forget to mention strict overwrite when not sequential and forget the blocking size */ if (!disc->sequential) { disc->strict_overwrite = 1; disc->blockingnr = 32; /* fixed for CD-RW */ } /* some say they are strict overwrite but also sequential */ if (disc->strict_overwrite) disc->sequential = 0; /* some forget that if they are mrw they can't the be other */ if (disc->mrw) { disc->sequential = 0; disc->strict_overwrite = 0; } } /* some think a CD-R is rewritable */ if (disc->mmc_profile == 0x09) { disc->rewritable = 0; } /* derivatives */ if (disc->blockingnr > 1) disc->packet = 1; switch (disc->mmc_profile) { case 0x01 : case 0x02 : /* SCSI discs class; treat like normal discs */ disc->devdrv_class = UDF_DEVDRV_CLASS_DISC; UDF_VERBOSE(printf("SCSI disc detected; treating like normal disc device\n")); return 0; case 0x03 : /* Magneto Optical with sector erase */ case 0x04 : /* Magneto Optical write once */ case 0x05 : /* Advance Storage Magneto Optical */ disc->devdrv_class = UDF_DEVDRV_CLASS_MO; break; /* 0x00, 0x08, 0x09, 0x0a : different types of CD-ROM devices like CD-R/RW etc. */ case 0x00 : disc->devdrv_class = UDF_DEVDRV_CLASS_CD; /* not allways clear */ break; case 0x08 : /* CD-ROM */ case 0x09 : /* CD-R */ case 0x0a : /* CD-RW */ disc->devdrv_class = UDF_DEVDRV_CLASS_CD; break; /* 0x10...0x14 DVD-ROM and DVD- devices */ case 0x10 : /* DVD-ROM */ case 0x11 : /* DVD-R */ case 0x12 : /* DVD-RAM */ case 0x13 : /* DVD-RW (restricted overwrite) */ case 0x14 : /* DVD-RW (sequential) */ /* 0x1a..0x1b DVD+ devices */ case 0x1a : /* DVD+RW */ case 0x1b : /* DVD+R */ case 0x2b : /* DVD+R double layer */ disc->devdrv_class = UDF_DEVDRV_CLASS_DVD; break; case 0x40 : /* BD-ROM */ case 0x41 : /* BD-R Sequential Recording (SRM) */ case 0x42 : /* BD-R Random Recording (RRM) */ case 0x43 : /* BD-RE */ disc->devdrv_class = UDF_DEVDRV_CLASS_BD; break; default : fprintf(stderr, "Not recognized MMC profile %d encountered, marking readonly\n", disc->mmc_profile); disc->devdrv_class = UDF_DEVDRV_CLASS_CD; /* go for the `dummy' */ break; } /* * ok, if we're on an CD-MRW or DVD+MRW, we ought to have switched * automatically to DMA space. However, this drive at times just * refuses with all messy things around. */ /* Select `Defect managed area' LBA space */ if (!disc->mrw) return 0; DEBUG(printf("Setting DMA LBA space")); val_len = 6 + 8 + 2; /* 2 for 4 byte alignment */ rpos = buf + 8; bzero(buf, val_len); rpos[ 0] = 0x03; /* GAA/DMA space select */ rpos[ 1] = 6; /* page length */ rpos[ 3] = 0; /* select GAA bit in bit 0 */ bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x55; /* MODE SELECT (10) */ cmd[1] = 16; /* PF format */ cmd[7] = val_len >> 8; /* length of blob */ cmd[8] = val_len & 0xff; cmd[9] = 0; /* control */ error = uscsi_command(SCSI_WRITECMD, disc->dev, cmd, 10, buf, val_len, 30000, NULL); if (error) { perror("While WRTITING parameter page 3"); return error; } /* shutup gcc */ feature_pers = feature_pers; feature_ver = feature_ver; return 0; } #if defined(__NetBSD__) || defined(__OpenBSD__) #include #include #include int udf_get_partition_info(struct udf_discinfo *disc) { struct disklabel disklab; struct partition *dp; struct stat st; int partnr; /* read disklabel partition */ if (ioctl(disc->dev->fhandle, DIOCGDINFO, &disklab) == -1) { /* failed to get disclabel! */ perror("disklabel"); return errno; } /* get disk partition it refers to */ fstat(disc->dev->fhandle, &st); partnr = DISKPART(st.st_rdev); dp = &disklab.d_partitions[partnr]; if (dp->p_size == 0) { perror("faulty disklabel partition returned, check label\n"); return EIO; } disc->sector_size = disklab.d_secsize; disc->session_start [0] = 0; disc->session_end [0] = dp->p_size - 1; return 0; } #elif defined(__linux__) #include int udf_get_partition_info(struct udf_discinfo *disc) { long p_size, p_size512; int secsize; /* get device length and sector size */ if (ioctl(disc->dev->fhandle, BLKSSZGET, &secsize) == -1) { perror("Can't read my sector size\n"); return errno; } if (ioctl(disc->dev->fhandle, BLKGETSIZE, &p_size512) == -1) { perror("Can't read my partition size\n"); return errno; } p_size = p_size512 * (secsize / 512); disc->sector_size = secsize; disc->session_start [0] = 0; disc->session_end [0] = p_size - 1; return 0; } #else int udf_get_partition_info(struct udf_discinfo *disc) { perror(" UDF: no explicit support for disc devices yet for this operating system.\n"); perror("Trying readonly access...\n"); disc->recordable = disc->rewritable = 0; return 0; } #endif /* 10000 is arbitrary */ /* TODO split up one day for its updating values unnessisarily */ #define res_len 10000 int udf_get_disc_info(struct udf_discinfo *disc) { scsicmd cmd; struct stat stat; uint32_t val_len; uint32_t first_track, last_track; uint32_t first_session, last_session; uint32_t next_writable_addr, packet_size; uint32_t cntrl, addr, tno, point, min, sec, frame, pmin, psec, pframe; uint32_t data_length, pos; uint8_t res[res_len]; int first_track_last_session, last_track_last_session; int track, session, sector_size; int nwa_valid; off_t track_start, track_end, track_size, disc_size, free_blocks; int error; if (disc->devdrv_class == UDF_DEVDRV_CLASS_FILE) { sector_size = disc->alt_sector_size ? disc->alt_sector_size : disc->sector_size; fstat(disc->dev->fhandle, &stat); disc->link_size = 0; /* no link lossage */ disc->disc_state = DISC_STATE_NOT_SERIAL; disc->last_session_state = SESSION_STATE_INCOMPLETE; disc->num_sessions = 1; disc->session_start [0] = 0; disc->session_end [0] = (stat.st_size / sector_size); /* inclusive */ disc->next_writable [0] = (stat.st_size / sector_size) + 1; disc->packet_size [0] = stat.st_blksize / sector_size; return 0; } if (disc->devdrv_class == UDF_DEVDRV_CLASS_DISC) { disc->link_size = 0; /* no link lossage */ disc->disc_state = DISC_STATE_NOT_SERIAL; disc->last_session_state = SESSION_STATE_COMPLETE; disc->num_sessions = 1; disc->session_start [0] = 0; disc->session_end [0] = 0; error = udf_get_partition_info(disc); if (error) return error; fprintf(stderr, "UDF: warning... reading/writing on 'disc' device\n"); return 0; } /* classes CD and DVD remain; we can be on a DVD/CD recordable or on a legacy CD-ROM */ /* Get track information */ val_len = 12; bzero(res, val_len); bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x51; /* Read disc information */ cmd[7] = val_len >> 8; /* MSB allocation length */ cmd[8] = val_len & 0xff; /* LSB allocation length */ cmd[9] = 0; /* control */ error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, res, val_len, 30000, NULL); if (!error) { /* we are a MMC3+ device! */ disc->disc_state = res[2] & 3; /* just 'happends' to be the same as we use */ disc->last_session_state = (res[2] >> 2) & 3; /* ditto */ disc->blankable = res[2] & 16; /* blankable -> update possibility */ disc->num_sessions = res[4] | (res[ 9] << 8); first_track = res[3]; first_track_last_session = res[5] | (res[10] << 8); /* to build up the last 'session' */ last_track_last_session = res[6] | (res[11] << 8); /* Initialise the sessions to be taken as overspanning tracks */ for (session = 0; session < disc->num_sessions; session++) { disc->session_start[session] = INT_MAX; disc->session_end [session] = 0; } for (track = first_track; track <= last_track_last_session; track++) { /* each track record is 36 bytes long */ val_len = 36; bzero(res, val_len); bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x52; /* Read track information */ cmd[1] = 1; /* indexed on track */ cmd[4] = track >> 8; /* track number 0-0xff ? */ cmd[5] = track & 0xff; cmd[7] = val_len >> 8; /* MSB length resultbuf */ cmd[8] = val_len & 0xff; /* LSB ,, */ cmd[9] = 0; error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, res, val_len, 30000, NULL); if (error) { perror("While reading track info"); break; } #if 0 data_length = res[1] | (res[0] << 8); // track_number = res[2] | (res[32] << 8); /* why? */ session = res[3] | (res[33] << 8); // is_track_mode = res[5] & 15; // is_copy = res[5] & 16; // is_damage = res[5] & 32; // is_fixed_packet = res[6] & 16; // is_packet_or_inc = res[6] & 32; // is_blank = res[6] & 64; // is_reserved = res[6] & 128; // is_data_mode = res[6] & 15; nwa_valid = res[7] & 1; // lra_valid = res[7] & 2; #endif data_length = res[1] | (res[0] << 8); session = res[3] | (res[33] << 8); nwa_valid = res[7] & 1; track_start = res[11] | (res[10]<<8) | (res[ 9]<<16) | (res[ 8]<<24); next_writable_addr = res[15] | (res[14]<<8) | (res[13]<<16) | (res[12]<<24); free_blocks = res[19] | (res[18]<<8) | (res[17]<<16) | (res[16]<<24); packet_size = res[23] | (res[22]<<8) | (res[21]<<16) | (res[20]<<24); track_size = res[27] | (res[26]<<8) | (res[25]<<16) | (res[24]<<24); /* last_recorded_addr = res[32] | (res[30]<<8) | (res[29]<<16) | (res[28]<<24); */ track_end = track_start + track_size; if (data_length <= 30) session &= 0xff; disc->session_start[session-1] = MIN(disc->session_start[session-1], track_start); disc->session_end [session-1] = MAX(disc->session_end [session-1], track_end); disc->free_blocks [session-1] = free_blocks; disc->packet_size [session-1] = packet_size; if (nwa_valid) disc->next_writable[session-1] = next_writable_addr; } if (disc->session_start[disc->num_sessions-1] == INT_MAX) { if (disc->disc_state == DISC_STATE_FULL) { if (disc->last_session_state == SESSION_STATE_COMPLETE) disc->num_sessions--; } } /* XXX * initialise default link size to zero; only set DEFAULT * link lossage for CD-R we are using `Burn Free' for writing * but if it fails its good to know the penalty for recovery * XXX */ disc->link_size = 0; if (disc->mmc_profile == 0x09) { disc->link_size = 7; } return 0; } /* Start with legacy CD-ROM .... trying to get as much info from it as possible */ disc->sequential = 0; disc->recordable = 0; disc->blankable = 0; disc->packet = 0; disc->blockingnr = 32; disc->strict_overwrite = 0; disc->disc_state = DISC_STATE_FULL; disc->last_session_state = SESSION_STATE_COMPLETE; disc->link_size = 7; /* DEFAULT link lossage for CDs */ /* Read session range */ val_len = 4; /* only head */ bzero(res, val_len); bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x43; /* READ TOC/PMA/ATIP INFO */ cmd[1] = 2; /* no LBA's are defined */ cmd[2] = 2; /* format 2 also this time */ cmd[6] = 0; /* obligatory zero */ cmd[7] = val_len >> 8; cmd[8] = val_len & 0xff; cmd[9] = 0; error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, res, val_len, 30000, NULL); if (error) { perror("TOC reading of sessions failed"); return error; } first_session = read_cd_hex2(res[2]); last_session = read_cd_hex2(res[3]); disc->num_sessions = last_session - first_session + 1; /* Initialise the sessions to be taken as overspanning tracks */ for(session = 0; session <= disc->num_sessions; session++) { disc->session_start[session] = INT_MAX; disc->session_end [session] = 0; } /* calculate how big the result buffer ought to be to get the whole TOC */ /* NOTE: don't count the 2 length bytes */ val_len = res[1] + (res[0] << 8); /* fix length for ATAPI drives */ if (val_len & 1) val_len++; assert(val_len < res_len); /* Read the complete TOC and extract information */ bzero(res, val_len); bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x43; /* READ TOC/PMA/ATIP INFO */ cmd[1] = 2; /* LBA's are not defined */ cmd[2] = 2; /* format 2; full TOC */ cmd[6] = first_session; /* start at first session */ cmd[7] = val_len >> 8; cmd[8] = val_len & 0xff; cmd[9] = 0; error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, res, val_len, 30000, NULL); if (error) { perror("TOC reading of full TOC failed"); return error; } data_length =res[1] | (res[0] << 8); if (data_length != val_len) { fprintf(stderr, "Warning: device didn't return all data requested when reading full TOC\nn"); fprintf(stderr, "\treturned %d bytes instead of %d\n", data_length, val_len); } pos = 4; track_start = INT_MAX; track_end = 0; while (pos < data_length + 2) { session = read_cd_bcd(res[pos+ 0]); cntrl = res[pos+1] & 15; addr = res[pos+1] >> 4; tno = read_cd_bcd(res[pos+ 2]); point = read_cd_bcd(res[pos+ 3]); min = read_cd_bcd(res[pos+ 4]); sec = read_cd_bcd(res[pos+ 5]); frame = read_cd_bcd(res[pos+ 6]); pmin = read_cd_bcd(res[pos+ 8]); psec = read_cd_bcd(res[pos+ 9]); pframe = read_cd_bcd(res[pos+10]); /* extract information; explicit writeout. See SCSI docs */ if (tno == 0 && session && addr == 1) { switch (point) { case 0xa0 : first_track = pmin; break; case 0xa1 : last_track = pmin; break; case 0xa2 : track_end = cd_msf2lba(0, pmin, psec, pframe); disc->session_end [session-1] = MAX(disc->session_end [session-1], track_end); break; default : track_start = cd_msf2lba(0, pmin, psec, pframe); disc->session_start[session-1] = MIN(disc->session_start[session-1], track_start); break; } } if (tno == 0 && session && addr == 5) { if (point == 0xb0) { next_writable_addr = cd_msf2lba(0, min, sec, frame); disc_size = cd_msf2lba(0, pmin, psec, pframe); /* TODO use nwa & size */ printf("UDF: ignoring B0 Q channel : next writable address; pre MMC3 device; fix me\n"); } } pos += 11; } /* Last session information is notoriously flawed in TOC format so update it */ bzero(res, 8); bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x25; /* CD READ RECORDED CAPACITY */ error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, res, 8, 30000, NULL); if (error) { fprintf(stderr, "Can't read CD recorded capacity, last session end might not be OK : %s\n", strerror(error)); return 0; } session = disc->num_sessions-1; disc->session_end[session] = res[3] | (res[2]<<8) | (res[1]<<16) | (res[0]<<24); /* shut up gcc */ disc_size = disc_size; first_track_last_session = first_track_last_session; cntrl = cntrl; last_track = last_track; return 0; } #undef res_len int udf_open_disc(char *dev_name, int discop_flags, struct udf_discinfo **discptr) { struct udf_discinfo *disc; if (!discptr) return EINVAL; *discptr = NULL; /* determine what kind of file/device we are dealing with */ disc = calloc(1, sizeof(struct udf_discinfo)); if (!disc) return ENOMEM; disc->dev = calloc(1, sizeof(struct uscsi_dev)); if (!disc->dev) { free(disc); return ENOMEM; } /* fill in the name */ disc->dev->dev_name = strdup(dev_name); if (uscsi_open(disc->dev) != 0) { perror("Failure to open device or file"); free(disc->dev); free(disc); return ENODEV; } /* determine disc type */ if (udf_discinfo_get_disc_type(disc)) { perror("Error during classification of disc; skipping disc\n"); uscsi_close(disc->dev); free(disc->dev); free(disc); return ENODEV; } /* get disc info */ if (udf_get_disc_info(disc)) { fprintf(stderr, "Can't get disc info"); uscsi_close(disc->dev); free(disc->dev); free(disc); return ENODEV; } /* process discop_flags */ if (discop_flags & UDF_DISCOP_BSWAP) disc->bswap_sectors = 1; /* return the pointer */ *discptr = disc; /* set recording parameters */ udf_discinfo_set_recording_parameters(disc, 0); /* no testwrite */ return 0; } int udf_close_disc(struct udf_discinfo *disc) { if (!disc) return 0; /* udf_stop_disc_thread(disc); */ uscsi_close(disc->dev); printf("Disc access statistics\n"); printf("\tsector reads %8"PRIu64" (%"PRIu64" Kbyte)\n", disc->sectors_read, ((uint64_t) (disc->sectors_read) * disc->sector_size) / 1024); printf("\tsector written %8"PRIu64" (%"PRIu64" Kbyte)\n", disc->sectors_written, ((uint64_t) (disc->sectors_written) * disc->sector_size) / 1024); printf("\tswitches %8d\n", disc->switchings); return 0; } int udf_discinfo_alter_perception(struct udf_discinfo *disc, uint32_t sec_size, uint32_t num_sectors) { struct stat stat; assert(disc); if ((disc->devdrv_class & UDF_DEVDRV_CLASS) != UDF_DEVDRV_CLASS_FILE) { return EINVAL; } fstat(disc->dev->fhandle, &stat); if (sec_size == 0) sec_size = disc->sector_size; if (num_sectors == 0) num_sectors = stat.st_size / sec_size; if (((sec_size % 512) != 0) || (sec_size == 0)) { fprintf(stderr, "Size of blocks need to be a multiple of 512\n"); return EINVAL; } if (stat.st_size / sec_size >= (uint32_t) -1) { fprintf(stderr, "Disc needs to many logical sectors, please increase blocksize\n"); return EINVAL; } if (num_sectors < 300) { fprintf(stderr, "Disc size too small to put an UDF filingsystem on\n"); return EINVAL; } if (stat.st_size != (off_t) sec_size * num_sectors) { fprintf(stderr, "Size of image file is not equal to specified size parameters\n"); return EINVAL; } disc->sequential = 0; /* full r/w */ disc->recordable = 1; /* assuming rw access */ disc->rewritable = 1; disc->sector_size = sec_size; disc->alt_sector_size = sec_size; /* altered value */ disc->link_size = 0; /* no link lossage */ disc->disc_state = DISC_STATE_NOT_SERIAL; disc->last_session_state = SESSION_STATE_INCOMPLETE; disc->num_sessions = 1; disc->session_start [0] = 0; disc->session_end [0] = num_sectors; disc->next_writable [0] = num_sectors + 1; disc->packet_size [0] = stat.st_blksize / sec_size; /* best blocking size */ return 0; } /****************************************************************************************** * * Sector readers and writers * ******************************************************************************************/ /* read an extent of sectors in the `result' buffer */ int udf_read_physical_sectors(struct udf_discinfo *disc, off_t sector, uint32_t num_sectors, char *what, uint8_t *result) { struct uscsi_sense sense; scsicmd cmd; int size, size_read, chunk; uint32_t session, skipped, sector_size; int pos, lb, hb, error; /* protect us */ if (((long) result) & 3) { printf("Unaligned read of sector : possible panic() on some systems avoided\n"); return EIO; } sector_size = disc->sector_size; /* read one UDF sector at a physical address specified in UDF_SECTOR size units */ size = num_sectors * disc->sector_size; size_read = 0; bzero(result, size); /* just in case */ /* has to go? */ assert(sector_size); assert(num_sectors <= 0xffff); /* statistics and cache control */ if (disc->am_writing) { disc->switchings++; /* XXX how about pseudo-overwrite? is this nessisary then too ? XXX */ if (disc->sequential) { /* * we need to synchronise the write caches before we * are allowed to read from the disc again. */ error = udf_discinfo_synchronise_caches(disc); while (error) { printf("udf_discinfo: failed to sync caches, retrying\n"); error = udf_discinfo_synchronise_caches(disc); } /* we need to update our NWA's after the sync on sequentials */ udf_get_disc_info(disc); } /* mark reading access only */ disc->am_writing = 0; } error = 0; DEBUG(printf("\r%08d : %s; read %d bytes\n", (int) sector, what, size)); while (num_sectors) { switch (disc->devdrv_class & UDF_DEVDRV_CLASS) { case UDF_DEVDRV_CLASS_CD : case UDF_DEVDRV_CLASS_DVD : /* * Use a SCSI command to read it so we can go past the last session; * allthough READ (12) is available, some older CD-ROM * devices only want to do READ (10). */ /* limited by MAXPHYS, taking 64kb as limitation */ chunk = MIN(64*1024 / sector_size, num_sectors); size_read = chunk * sector_size; /* definition */ skipped = session = 0; bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x28; /* READ (10) command */ cmd[1] = 0; /* normal access */ cmd[2] = (sector >> 24) & 0xff; cmd[3] = (sector >> 16) & 0xff; cmd[4] = (sector >> 8) & 0xff; cmd[5] = (sector ) & 0xff; cmd[6] = 0; /* reserved */ cmd[7] = (chunk >> 8) & 0xff; /* MSB transfer */ cmd[8] = (chunk ) & 0xff; /* number of logical block(s) */ cmd[9] = 0; /* control */ do { error = uscsi_command(SCSI_READCMD, disc->dev, cmd, 10, result, size_read - skipped, 30000, &sense); /* TODO: if busy, ask drive how long it'll take to be available again and wait */ if (sense.asc == 4) usleep(5000); } while (sense.asc == 4); if (error) return ENOENT; break; default : /* XXX first and only reference to {p}read() XXX */ if (sector>=0) size_read = pread(disc->dev->fhandle, result, (uint64_t) num_sectors * sector_size, sector * sector_size); break; } /* statistics */ disc->sectors_read += size_read / sector_size; /* swap space if requested */ if (disc->bswap_sectors) { for (pos = 0; pos < size_read;) { lb = result[pos ]; hb = result[pos+1]; result[pos ] = hb; result[pos+1] = lb; pos += 2; } } /* advance */ num_sectors -= size_read / sector_size; sector += size_read / sector_size; result += size_read; if (size_read <= 0) { UDF_VERBOSE_MAX( if (what) { printf("Can't read sectors %d+%d for %s\n", (int) sector, num_sectors, what); } ); if (size_read == 0) return ENOENT; return error; } } return 0; /* flag ok */ } /* write an extent of sectors to disc */ int udf_write_physical_sectors(struct udf_discinfo *disc, off_t sector, uint32_t num_sectors, char *what, uint8_t *source) { struct uscsi_sense sense; scsicmd cmd; int trans_length, size, size_written, chunk; uint32_t sector_size; uint8_t *buffer; int lb, hb, pos, error; /* if (!disc->udf_recording) return ENODEV; */ /* protect us */ if (((long) source) & 3) { printf("Unaligned write of sector : possible panic() on some systems avoided\n"); return EIO; } sector_size = disc->sector_size; /* XXX clean up XXX */ assert(sector_size); assert(num_sectors <= 0xffff); /* compatible with WRITE (10)? */ DEBUG(printf("\r%08d : %s ;WRITE %d bytes\n", (int) sector, what, num_sectors * sector_size)); /* swap space if requested */ buffer = source; if (disc->bswap_sectors) { size = num_sectors * sector_size; buffer = malloc(num_sectors * sector_size); for (pos = 0; pos < size;) { lb = source[pos ]; hb = source[pos+1]; buffer[pos ] = hb; buffer[pos+1] = lb; pos += 2; } } error = 0; while (num_sectors) { size_written = 0; switch (disc->devdrv_class & UDF_DEVDRV_CLASS) { case UDF_DEVDRV_CLASS_CD : case UDF_DEVDRV_CLASS_DVD : /* * Use WRITE (12) command to write to the disc; we * might have to downgrade later to using WRITE (10) * on older discs though :-/ */ /* limited by MAXPHYS, taking 64kb as limitation */ chunk = MIN(64*1024 / sector_size, num_sectors); /* in sectors */ trans_length = chunk; /* in sectors */ bzero(cmd, SCSI_CMD_LEN); cmd[ 0] = 0xAA; /* WRITE (12) */ cmd[ 1] = 0; /* no force unit access */ cmd[ 2] = (sector >> 24) & 0xff; cmd[ 3] = (sector >> 16) & 0xff; cmd[ 4] = (sector >> 8) & 0xff; cmd[ 5] = (sector ) & 0xff; cmd[ 6] = (trans_length >> 24) & 0xff; /* MSB */ cmd[ 7] = (trans_length >> 16) & 0xff; cmd[ 8] = (trans_length >> 8) & 0xff; cmd[ 9] = (trans_length ) & 0xff; /* LSB */ cmd[10] = 0; /* no streaming */ cmd[11] = 0; /* control */ do { error = uscsi_command(SCSI_WRITECMD, disc->dev, cmd, 12, buffer, trans_length * sector_size, 30000, &sense); /* TODO: if busy, ask drive how long it'll take to be available again and wait */ if (sense.asc == 4) usleep(5000); } while (sense.asc == 4); /* write one UDF sector at a physical address specified in UDF_SECTOR size units */ size = trans_length * sector_size; size_written = error ? 0 : size; break; default : /* XXX first and only reference to {p}write() XXX */ DEBUG(printf("udf_discop: pwrite %"PRIu64" + %d\n", (uint64_t) sector * sector_size, (int) num_sectors * sector_size)); /* write one UDF sector at a physical address specified in UDF_SECTOR size units */ size = num_sectors * sector_size; size_written = pwrite(disc->dev->fhandle, buffer, (uint64_t) num_sectors * sector_size, sector * sector_size); if (size_written < 0) size_written = 0; break; } /* free our copy if we created one */ if (buffer != source) free(buffer); /* statistics */ disc->sectors_written += size_written / sector_size; if (!disc->am_writing) disc->switchings++; disc->am_writing = 1; num_sectors -= size_written / sector_size; sector += size_written / sector_size; buffer += size_written; if ((size_written < size) || error) { DEBUG(if (error) printf("Writing %s at sectors %d+%d failed\n", what, (int) sector, num_sectors)); return EIO; } } return 0; } /* End of udf_discinfo.c */ UDFclient.0.8.8/cd_sessions.c010066400001470000000000000043271307041400500153450ustar reinoudwheel/* $NetBSD$ */ /* * File "cd_sessions.c" is part of the UDFclient toolkit. * File $Id: cd_sessions.c,v 1.34 2011/02/01 20:43:40 reinoud Exp $ $Name: $ * * Copyright (c) 2003, 2004, 2005, 2006, 2011 * Reinoud Zandijk * All rights reserved. * * The UDFclient toolkit is distributed under the Clarified Artistic Licence. * A copy of the licence is included in the distribution as * `LICENCE.clearified.artistic' and a copy of the licence can also be * requested at the GNU foundantion's website. * * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include "udf.h" #include "udf_bswap.h" struct udf_discinfo *disc; extern int udf_verbose; extern int uscsilib_verbose; extern void udf_dump_discinfo(struct udf_discinfo *disc); int main(int argc, char **argv) { char *dev_name; int error; if (argc != 2) { printf("Usage : %s devicename\n", argv[0]); return 1; } dev_name = argv[1]; udf_verbose = UDF_VERBLEV_ACTIONS; udf_verbose = UDF_VERBLEV_MAX; uscsilib_verbose = 0; printf("Opening device %s\n", dev_name); error = udf_open_disc(dev_name, /* discop_flags */ 0, &disc); if (error) { fprintf(stderr, "Can't open my device : %s\n", strerror(error)); exit(1); } udf_dump_discinfo(disc); udf_close_disc(disc); return 0; } UDFclient.0.8.8/udf_discop.h010066400001470000000000000126661307041400500151620ustar reinoudwheel/* $NetBSD$ */ /* * File "udf_discop.h" is part of the UDFclient toolkit. * File $Id: udf_discop.h,v 1.30 2011/02/01 20:43:41 reinoud Exp $ $Name: $ * * Copyright (c) 2003, 2004, 2005, 2006, 2011 * Reinoud Zandijk * All rights reserved. * * The UDFclient toolkit is distributed under the Clarified Artistic Licence. * A copy of the licence is included in the distribution as * `LICENCE.clearified.artistic' and a copy of the licence can also be * requested at the GNU foundantion's website. * * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef _UDF_DISCOP_H_ #define _UDF_DISCOP_H_ #include #include "defs.h" #include "uscsilib.h" #include "queue.h" /* setup constants */ #define UDF_DISCOP_BSWAP 1 /* Implementation constants */ #define MAX_SESSIONS 100 #define CD_SECTOR_SIZE 2048 #define DISC_SECTOR_SIZE 512 /* State and driver constants */ #define DISC_STATE_EMPTY 0 /* nothing on the disc */ #define DISC_STATE_INCOMPLETE 1 /* can be appended */ #define DISC_STATE_FULL 2 /* no appending possible */ #define DISC_STATE_NOT_SERIAL 3 /* not serial */ #define SESSION_STATE_EMPTY 0 /* still empty */ #define SESSION_STATE_INCOMPLETE 1 /* session is open */ #define SESSION_STATE_CLOSED 2 /* we need a new session */ #define SESSION_STATE_COMPLETE 3 /* no appending possible */ #define UDF_DEVDRV_CLASS 0xFF #define UDF_DEVDRV_CLASS_FILE 0x00 #define UDF_DEVDRV_CLASS_DISC 0x01 #define UDF_DEVDRV_CLASS_CD 0x02 #define UDF_DEVDRV_CLASS_DVD 0x04 #define UDF_DEVDRV_CLASS_MO 0x08 #define UDF_DEVDRV_CLASS_BD 0x10 /* will go? */ struct udf_session; /* * The complete disc, all cd sessions and how to access the drive */ struct udf_discinfo { struct uscsi_dev *dev; /* uscsi device associated */ int scsi_device_type; /* in case of SCSI */ int mmc_profile; /* in case of SCSI */ int devdrv_class; int sequential; /* media is sequential writable only */ int recordable; /* media is record-able; i.e. not static */ int erasable; /* drive can erase sectors */ int blankable; /* media can be blanked by the drive */ int formattable; /* media can be formatted by the drive */ int rewritable; /* media can be rewritten */ int mrw; /* media is identified as being MRW formatted */ int packet; /* media is using packet recording */ int strict_overwrite; /* media can only be written a packet at a time */ int blockingnr; /* blocking size for ECC/modification */ int sector_size; /* sector size in bytes */ int alt_sector_size; /* if non zero, override normal sectorsize */ int link_size; /* link size lossage when having underruns */ int disc_state; /* empty - incomplete - full - not_serial */ int last_session_state; /* empty - incomplete - closed - complete */ /* flags that alter udf_discop's behaviour */ int udf_recording; /* flags if a recording is initialised */ int bswap_sectors; /* swap all bytes in a sector */ /* statistics */ int am_writing; uint64_t sectors_read; uint64_t sectors_written; uint32_t switchings; /* sessions */ int num_sessions; int num_udf_sessions; int session_is_UDF[MAX_SESSIONS]; int session_quirks[MAX_SESSIONS]; off_t session_start [MAX_SESSIONS]; off_t session_end [MAX_SESSIONS]; uint32_t next_writable [MAX_SESSIONS]; uint32_t free_blocks [MAX_SESSIONS]; uint32_t packet_size [MAX_SESSIONS]; STAILQ_HEAD(udf_sessions, udf_session) sessions; SLIST_ENTRY(udf_discinfo) next_disc; }; /* exported functions */ extern int udf_open_disc(char *dev_name, int discop_flags, struct udf_discinfo **discptr); extern int udf_close_disc(struct udf_discinfo *disc); extern int udf_discinfo_get_type(struct udf_discinfo *disc); extern int udf_discinfo_check_disc_ready(struct udf_discinfo *disc); extern int udf_discinfo_is_cd_or_dvd(struct udf_discinfo *disc); extern int udf_discinfo_set_recording_parameters(struct udf_discinfo *discinfo, int testwriting); extern int udf_discinfo_alter_perception(struct udf_discinfo *disc, uint32_t sec_size, uint32_t num_sectors); extern int udf_discinfo_finish_writing(struct udf_discinfo *discinfo); extern int udf_discinfo_reserve_track_in_logic_units(struct udf_discinfo *discinfo, uint32_t logic_units); extern int udf_discinfo_close_track(struct udf_discinfo *discinfo, uint16_t trackno); extern int udf_discinfo_repair_track(struct udf_discinfo *discinfo, uint16_t trackno); extern int udf_read_physical_sectors(struct udf_discinfo *disc, off_t sector, uint32_t num_sectors, char *what, uint8_t *result); extern int udf_write_physical_sectors(struct udf_discinfo *disc, off_t sector, uint32_t num_sectors, char *what, uint8_t *source); #endif /* _UDF_DISCOP_H_ */ UDFclient.0.8.8/uscsi_subr.c010066400001470000000000000354571307041400500152220ustar reinoudwheel/* $NetBSD: uscsi_subr.c,v 1.7 2002/10/08 20:17:06 soren Exp $ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Charles M. Hannum; Jason R. Thorpe of the Numerical Aerospace * Simulation Facility, NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Small changes, generalisations and Linux support by Reinoud Zandijk * . * */ /* * SCSI support subroutines. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "uscsilib.h" int uscsilib_verbose = 0; #ifdef USCSI_SCSIPI /* * scsipi is a integrated SCSI and ATAPI layer under NetBSD and exists * in a modified form under OpenBSD and possibly also under other * operating systems. */ #include #ifdef __OpenBSD__ #include #else #include #endif int uscsi_open(struct uscsi_dev *disc) { struct stat stat; disc->fhandle = open(disc->dev_name, O_RDWR, 0); /* no create */ if (disc->fhandle<0) { perror("Failure to open device or file"); return ENODEV; } if (fstat(disc->fhandle, &stat) < 0) { perror("Can't stat device or file"); uscsi_close(disc); return ENODEV; } return 0; } int uscsi_close(struct uscsi_dev * disc) { close(disc->fhandle); disc->fhandle = -1; return 0; } int uscsi_command(int flags, struct uscsi_dev *disc, void *cmd, size_t cmdlen, void *data, size_t datalen, uint32_t timeout, struct uscsi_sense *uscsi_sense) { scsireq_t req; memset(&req, 0, sizeof(req)); if (uscsi_sense) bzero(uscsi_sense, sizeof(struct uscsi_sense)); memcpy(req.cmd, cmd, cmdlen); req.cmdlen = cmdlen; req.databuf = data; req.datalen = datalen; req.timeout = timeout; req.flags = flags; req.senselen = SENSEBUFLEN; if (ioctl(disc->fhandle, SCIOCCOMMAND, &req) == -1) return EIO; if (req.retsts == SCCMD_OK) return 0; /* Some problem; report it and exit. */ if (req.retsts == SCCMD_TIMEOUT) { if (uscsilib_verbose) fprintf(stderr, "%s: SCSI command timed out\n", disc->dev_name); return EAGAIN; } else if (req.retsts == SCCMD_BUSY) { if (uscsilib_verbose) fprintf(stderr, "%s: device is busy\n", disc->dev_name); return EBUSY; } else if (req.retsts == SCCMD_SENSE) { if (uscsi_sense) { uscsi_sense->asc = req.sense[12]; uscsi_sense->ascq = req.sense[13]; uscsi_sense->skey_valid = req.sense[15] & 128; uscsi_sense->sense_key = (req.sense[16] << 8) | (req.sense[17]); } if (uscsilib_verbose) uscsi_print_sense((char *) disc->dev_name, req.cmd, req.cmdlen, req.sense, req.senselen_used, 1); return EIO; } else if (uscsilib_verbose) fprintf(stderr, "%s: device had unknown status %x\n", disc->dev_name, req.retsts); return EFAULT; } /* * The reasoning behind this explicit copy is for compatibility with changes * in our uscsi_addr structure. */ int uscsi_identify(struct uscsi_dev *disc, struct uscsi_addr *saddr) { struct scsi_addr raddr; int error; bzero(saddr, sizeof(struct scsi_addr)); error = ioctl(disc->fhandle, SCIOCIDENTIFY, &raddr); if (error) { saddr->type = USCSI_TYPE_UNKNOWN; return error; } #ifdef __NetBSD__ /* scsi and atapi are split up like in uscsi_addr */ if (raddr.type == 0) { saddr->type = USCSI_TYPE_SCSI; saddr->addr.scsi.scbus = raddr.addr.scsi.scbus; saddr->addr.scsi.target = raddr.addr.scsi.target; saddr->addr.scsi.lun = raddr.addr.scsi.lun; } else { saddr->type = USCSI_TYPE_ATAPI; saddr->addr.atapi.atbus = raddr.addr.atapi.atbus; saddr->addr.atapi.drive = raddr.addr.atapi.drive; } #endif #ifdef __OpenBSD__ /* atapi's are shown as SCSI devices */ if (raddr.type == 0) { saddr->type = USCSI_TYPE_SCSI; saddr->addr.scsi.scbus = raddr.scbus; saddr->addr.scsi.target = raddr.target; saddr->addr.scsi.lun = raddr.lun; } else { saddr->type = USCSI_TYPE_ATAPI; saddr->addr.atapi.atbus = raddr.scbus; /* overload */ saddr->addr.atapi.drive = raddr.target; /* overload */ } #endif return 0; } #endif /* SCSILIB_SCSIPI */ #ifdef USCSI_LINUX_SCSI /* * Support code for Linux SCSI code. It uses the ioctl() way of * communicating since this is more close to the origional NetBSD * scsipi implementation. */ #include #include #define SENSEBUFLEN 48 int uscsi_open(struct uscsi_dev * disc) { int flags; struct stat stat; /* in Linux we are NOT allowed to open it blocking */ /* no create! */ disc->fhandle = open(disc->dev_name, O_RDWR | O_NONBLOCK, 0); if (disc->fhandle < 0) disc->fhandle = open(disc->dev_name, O_RDONLY | O_NONBLOCK, 0); if (disc->fhandle < 0) { perror("Failure to open device or file"); return ENODEV; } /* explicitly mark it non blocking (again) (silly Linux) */ flags = fcntl(disc->fhandle, F_GETFL); flags &= ~O_NONBLOCK; fcntl(disc->fhandle, F_SETFL, flags); if (fstat(disc->fhandle, &stat) < 0) { perror("Can't stat device or file"); uscsi_close(disc); return ENODEV; } return 0; } int uscsi_close(struct uscsi_dev * disc) { close(disc->fhandle); disc->fhandle = -1; return 0; } int uscsi_command(int flags, struct uscsi_dev *disc, void *cmd, size_t cmdlen, void *data, size_t datalen, uint32_t timeout, struct uscsi_sense *uscsi_sense) { struct sg_io_hdr req; uint8_t sense_buffer[SENSEBUFLEN]; int error; bzero(&req, sizeof(req)); if (flags == SG_DXFER_FROM_DEV) bzero(data, datalen); req.interface_id = 'S'; req.dxfer_direction = flags; req.cmd_len = cmdlen; req.mx_sb_len = SENSEBUFLEN; req.iovec_count = 0; req.dxfer_len = datalen; req.dxferp = data; req.cmdp = cmd; req.sbp = sense_buffer; req.flags = 0; req.timeout = timeout; error = ioctl(disc->fhandle, SG_IO, &req); if (req.status) { /* Is this OK? */ if (uscsi_sense) { uscsi_sense->asc = sense_buffer[12]; uscsi_sense->ascq = sense_buffer[13]; uscsi_sense->skey_valid = sense_buffer[15] & 128; uscsi_sense->sense_key = (sense_buffer[16] << 8) | (sense_buffer[17]); } if (uscsilib_verbose) { uscsi_print_sense((char *) disc->dev_name, cmd, cmdlen, sense_buffer, req.sb_len_wr, 1); } } return error; } int uscsi_identify(struct uscsi_dev *disc, struct uscsi_addr *saddr) { struct sg_scsi_id sg_scsi_id; struct sg_id { /* target | lun << 8 | channel << 16 | low_ino << 24 */ uint32_t tlci; uint32_t uniq_id; } sg_id; int emulated; int error; /* clean result */ bzero(saddr, sizeof(struct uscsi_addr)); /* check if its really SCSI or emulated SCSI (ATAPI f.e.) */ saddr->type = USCSI_TYPE_SCSI; ioctl(disc->fhandle, SG_EMULATED_HOST, &emulated); if (emulated) saddr->type = USCSI_TYPE_ATAPI; /* try 2.4 kernel or older */ error = ioctl(disc->fhandle, SG_GET_SCSI_ID, &sg_scsi_id); if (!error) { saddr->addr.scsi.target = sg_scsi_id.scsi_id; saddr->addr.scsi.lun = sg_scsi_id.lun; saddr->addr.scsi.scbus = sg_scsi_id.channel; return 0; } /* 2.6 kernel or newer */ error = ioctl(disc->fhandle, SCSI_IOCTL_GET_IDLUN, &sg_id); if (error) return error; saddr->addr.scsi.target = (sg_id.tlci ) & 0xff; saddr->addr.scsi.lun = (sg_id.tlci >> 8) & 0xff; saddr->addr.scsi.scbus = (sg_id.tlci >> 16) & 0xff; return 0; } #endif /* USCSI_LINUX_SCSI */ #ifdef USCSI_FREEBSD_CAM int uscsi_open(struct uscsi_dev *disc) { disc->devhandle = cam_open_device(disc->dev_name, O_RDWR); if (disc->devhandle == NULL) { disc->fhandle = open(disc->dev_name, O_RDWR | O_NONBLOCK, 0); if (disc->fhandle < 0) { perror("Failure to open device or file"); return ENODEV; } } return 0; } int uscsi_close(struct uscsi_dev *disc) { if (disc->devhandle != NULL) { cam_close_device(disc->devhandle); disc->devhandle = NULL; } else { close(disc->fhandle); disc->fhandle = -1; } return 0; } int uscsi_command(int flags, struct uscsi_dev *disc, void *cmd, size_t cmdlen, void *data, size_t datalen, uint32_t timeout, struct uscsi_sense *uscsi_sense) { struct cam_device *cam_dev; struct scsi_sense_data *cam_sense_data; union ccb ccb; uint32_t cam_sense; uint8_t *keypos; int camflags; memset(&ccb, 0, sizeof(ccb)); cam_dev = (struct cam_device *) disc->devhandle; if (cam_dev == 0) return EIO; if (datalen == 0) flags = SCSI_NODATACMD; /* optional : */ /* if (data) assert(flags == SCSI_NODATACMD); */ camflags = CAM_DIR_NONE; if (flags & SCSI_READCMD) camflags = CAM_DIR_IN; if (flags & SCSI_WRITECMD) camflags = CAM_DIR_OUT; cam_fill_csio( &ccb.csio, 0, /* retries */ NULL, /* cbfcnp */ camflags, /* flags */ MSG_SIMPLE_Q_TAG, /* tag_action */ (u_int8_t *) data, /* data_ptr */ datalen, /* dxfer_len */ SSD_FULL_SIZE, /* sense_len */ cmdlen, /* cdb_len */ timeout /* timeout */ ); /* Disable freezing the device queue */ ccb.ccb_h.flags |= CAM_DEV_QFRZDIS; memcpy(ccb.csio.cdb_io.cdb_bytes, cmd, cmdlen); /* Send the command down via the CAM interface */ if (cam_send_ccb(cam_dev, &ccb) < 0) { err(1, "cam_send_ccb"); } if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) return 0; /* print error using the uscsi_sense routines? */ cam_sense = (ccb.ccb_h.status & (CAM_STATUS_MASK | CAM_AUTOSNS_VALID)); if (cam_sense != (CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID)) return EFAULT; /* drive responds with sense information */ if (!uscsilib_verbose) return EFAULT; /* print sense info */ cam_sense_data = &ccb.csio.sense_data; if (uscsi_sense) { uscsi_sense->asc = cam_sense_data->add_sense_code; uscsi_sense->ascq = cam_sense_data->add_sense_code_qual; keypos = cam_sense_data->sense_key_spec; uscsi_sense->skey_valid = keypos[0] & 128; uscsi_sense->sense_key = (keypos[1] << 8) | (keypos[2]); } uscsi_print_sense((char *) disc->dev_name, cmd, cmdlen, (uint8_t *) cam_sense_data, 8 + cam_sense_data->extra_len, 1); return EFAULT; } int uscsi_identify(struct uscsi_dev *disc, struct uscsi_addr *saddr) { struct cam_device *cam_dev; /* clean result */ bzero(saddr, sizeof(struct uscsi_addr)); cam_dev = (struct cam_device *) disc->devhandle; if (!cam_dev) return ENODEV; /* check if its really SCSI or emulated SCSI (ATAPI f.e.) ? */ saddr->type = USCSI_TYPE_SCSI; saddr->addr.scsi.target = cam_dev->target_id; saddr->addr.scsi.lun = cam_dev->target_lun; saddr->addr.scsi.scbus = cam_dev->bus_id; return 0; } #endif /* USCSI_FREEBSD_CAM */ #ifndef SCSI int uscsi_open(struct uscsi_dev *disc) { disc->devhandle = NULL; disc->fhandle = open(disc->dev_name, O_RDWR | O_NONBLOCK, 0); if (disc->fhandle < 0) { perror("Failure to open device or file"); return ENODEV; } return 0; } int uscsi_close(struct uscsi_dev *disc) { close(disc->fhandle); disc->fhandle = -1; return 0; } int uscsi_identify(struct uscsi_dev *disc, struct uscsi_addr *saddr) { bzero(saddr, sizeof(struct uscsi_addr)); saddr->type = USCSI_TYPE_UNKNOWN; } int uscsi_command(int flags, struct uscsi_dev *disc, void *cmd, size_t cmdlen, void *data, size_t datalen, uint32_t timeout, struct uscsi_sense *uscsi_sense) { return ENODEV; } #endif /* !SCSI */ /* * Checks if SCSI is available by issueing the obligatory INQUIRY. */ int uscsi_check_for_scsi(struct uscsi_dev *disc) { scsicmd cmd; uint8_t buf[256]; int error; bzero(cmd, SCSI_CMD_LEN); cmd[0] = 0x12; /* INQUIRY */ cmd[1] = 0; /* basic inquiry */ cmd[2] = 0; /* no page or operation code */ cmd[3] = 0; /* reserved/MSB result */ cmd[4] = 96; /* all but vendor specific */ cmd[5] = 0; /* control */ error = uscsi_command(SCSI_READCMD, disc, cmd, 6, buf, 96, 30000, NULL); return error; } /* * Generic SCSI funtions also used by the sense printing functionality. * FreeBSD support has it allready asked for by the CAM. */ int uscsi_mode_sense(struct uscsi_dev *dev, uint8_t pgcode, uint8_t pctl, void *buf, size_t len) { scsicmd cmd; bzero(buf, len); /* initialise recieving buffer */ bzero(cmd, SCSI_CMD_LEN); cmd[ 0] = 0x1a; /* MODE SENSE */ cmd[ 1] = 0; /* - */ cmd[ 2] = pgcode | pctl; /* page code and control flags */ cmd[ 3] = 0; /* - */ cmd[ 4] = len; /* length of recieve buffer */ cmd[ 5] = 0; /* control */ return uscsi_command(SCSI_READCMD, dev, &cmd, 6, buf, len, 10000, NULL); } int uscsi_mode_select(struct uscsi_dev *dev, uint8_t byte2, void *buf, size_t len) { scsicmd cmd; bzero(cmd, SCSI_CMD_LEN); cmd[ 0] = 0x15; /* MODE SELECT */ cmd[ 1] = 0x10 | byte2; /* SCSI-2 page format select */ cmd[ 4] = len; /* length of page settings */ cmd[ 5] = 0; /* control */ return uscsi_command(SCSI_WRITECMD, dev, &cmd, 6, buf, len, 10000, NULL); } int uscsi_request_sense(struct uscsi_dev *dev, void *buf, size_t len) { scsicmd cmd; bzero(buf, len); /* initialise recieving buffer */ bzero(cmd, SCSI_CMD_LEN); cmd[ 0] = 0x03; /* REQUEST SENSE */ cmd[ 4] = len; /* length of data to be read */ cmd[ 5] = 0; /* control */ return uscsi_command(SCSI_WRITECMD, dev, &cmd, 6, buf, len, 10000, NULL); } /* end of uscsi_subr.c */ UDFclient.0.8.8/config.h010066400001470000000000000000151307041400500142710ustar reinoudwheel#define yes UDFclient.0.8.8/vfs_dirhash.c010064400001470000000000000302221307041400500153200ustar reinoudwheel/* $NetBSD: vfs_dirhash.c,v 1.8 2008/10/31 16:04:59 reinoud Exp $ */ /* * Copyright (c) 2008, 2011 Reinoud Zandijk * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #if 0 #include __KERNEL_RCSID(0, "$NetBSD: vfs_dirhash.c,v 1.8 2008/10/31 16:04:59 reinoud Exp $"); #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "uscsilib.h" #include "queue.h" #include "hash.h" #include "dirhash.h" #if 1 # define DPRINTF(a) ; #else # define DPRINTF(a) printf(a); #endif /* compat */ #define KASSERT(a) assert(a) #define mutex_enter(mtx) pthread_mutex_lock(mtx) #define mutex_exit(mtx) pthread_mutex_unlock(mtx) /* * The locking protocol of the dirhash structures is fairly simple: * * The global dirhash_queue is protected by the dirhashmutex. This lock is * internal only and is FS/mountpoint/vnode independent. On exit of the * exported functions this mutex is not helt. * * The dirhash structure is considered part of the vnode/inode/udf_node * structure and will thus use the lock that protects that vnode/inode. * * The dirhash entries are considered part of the dirhash structure and thus * are on the same lock. */ //static struct sysctllog *sysctl_log; //static struct pool dirhash_pool; //static struct pool dirhash_entry_pool; static pthread_mutex_t dirhashmutex; static uint32_t maxdirhashsize = DIRHASH_SIZE; static uint32_t dirhashsize = 0; static TAILQ_HEAD(_dirhash, dirhash) dirhash_queue; void dirhash_init(void) { // const struct sysctlnode *rnode, *cnode; // size_t sz; // uint32_t max_entries; /* initialise dirhash queue */ TAILQ_INIT(&dirhash_queue); pthread_mutex_init(&dirhashmutex, 0); #if 0 /* init dirhash pools */ sz = sizeof(struct dirhash); pool_init(&dirhash_pool, sz, 0, 0, 0, "dirhpl", NULL, IPL_NONE); sz = sizeof(struct dirhash_entry); pool_init(&dirhash_entry_pool, sz, 0, 0, 0, "dirhepl", NULL, IPL_NONE); mutex_init(&dirhashmutex, MUTEX_DEFAULT, IPL_NONE); max_entries = maxdirhashsize / sz; pool_sethiwat(&dirhash_entry_pool, max_entries); dirhashsize = 0; /* create sysctl knobs and dials */ sysctl_log = NULL; sysctl_createv(&sysctl_log, 0, NULL, &rnode, CTLFLAG_PERMANENT, CTLTYPE_NODE, "dirhash", NULL, NULL, 0, NULL, 0, CTL_VFS, VFS_GENERIC, CTL_CREATE, CTL_EOL); sysctl_createv(&sysctl_log, 0, &rnode, &cnode, CTLFLAG_PERMANENT, CTLTYPE_INT, "memused", SYSCTL_DESCR("current dirhash memory usage"), NULL, 0, &dirhashsize, 0, CTL_CREATE, CTL_EOL); sysctl_createv(&sysctl_log, 0, &rnode, &cnode, CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, "maxmem", SYSCTL_DESCR("maximum dirhash memory usage"), NULL, 0, &maxdirhashsize, 0, CTL_CREATE, CTL_EOL); #endif } #if 0 void dirhash_finish(void) { pool_destroy(&dirhash_pool); pool_destroy(&dirhash_entry_pool); mutex_destroy(&dirhashmutex); /* sysctl_teardown(&sysctl_log); */ } #endif /* * generic dirhash implementation */ void dirhash_purge_entries(struct dirhash *dirh) { struct dirhash_entry *dirh_e; uint32_t hashline; if (dirh == NULL) return; if (dirh->size == 0) return; for (hashline = 0; hashline < DIRHASH_HASHSIZE; hashline++) { dirh_e = LIST_FIRST(&dirh->entries[hashline]); while (dirh_e) { LIST_REMOVE(dirh_e, next); //pool_put(&dirhash_entry_pool, dirh_e); free(dirh_e); dirh_e = LIST_FIRST(&dirh->entries[hashline]); } } while ((dirh_e = LIST_FIRST(&dirh->free_entries)) != NULL) { LIST_REMOVE(dirh_e, next); //pool_put(&dirhash_entry_pool, dirh_e); free(dirh_e); } dirh->flags &= ~DIRH_COMPLETE; dirh->flags |= DIRH_PURGED; dirhashsize -= dirh->size; dirh->size = 0; } void dirhash_purge(struct dirhash **dirhp) { struct dirhash *dirh = *dirhp; if (dirh == NULL) return; /* purge its entries */ dirhash_purge_entries(dirh); /* recycle */ mutex_enter(&dirhashmutex); TAILQ_REMOVE(&dirhash_queue, dirh, next); mutex_exit(&dirhashmutex); //pool_put(&dirhash_pool, dirh); free(dirh); *dirhp = NULL; } void dirhash_get(struct dirhash **dirhp) { struct dirhash *dirh; uint32_t hashline; /* if no dirhash was given, allocate one */ dirh = *dirhp; if (dirh == NULL) { // dirh = pool_get(&dirhash_pool, PR_WAITOK); dirh = malloc(sizeof(struct dirhash)); assert(dirh); memset(dirh, 0, sizeof(struct dirhash)); for (hashline = 0; hashline < DIRHASH_HASHSIZE; hashline++) { LIST_INIT(&dirh->entries[hashline]); } } /* implement LRU on the dirhash queue */ mutex_enter(&dirhashmutex); if (*dirhp) { /* remove from queue to be requeued */ TAILQ_REMOVE(&dirhash_queue, dirh, next); } dirh->refcnt++; TAILQ_INSERT_HEAD(&dirhash_queue, dirh, next); mutex_exit(&dirhashmutex); *dirhp = dirh; } void dirhash_put(struct dirhash *dirh) { mutex_enter(&dirhashmutex); dirh->refcnt--; mutex_exit(&dirhashmutex); } void dirhash_enter(struct dirhash *dirh, struct dirent *dirent, uint64_t offset, uint32_t entry_size, int new) { struct dirhash *del_dirh, *prev_dirh; struct dirhash_entry *dirh_e; uint32_t hashvalue, hashline; int entrysize; /* make sure we have a dirhash to work on */ KASSERT(dirh); KASSERT(dirh->refcnt > 0); /* are we trying to re-enter an entry? */ if (!new && (dirh->flags & DIRH_COMPLETE)) return; /* calculate our hash */ hashvalue = hash32_strn(dirent->d_name, DIRENT_NAMLEN(dirent), HASH32_STR_INIT); hashline = hashvalue & DIRHASH_HASHMASK; /* lookup and insert entry if not there yet */ LIST_FOREACH(dirh_e, &dirh->entries[hashline], next) { /* check for hash collision */ if (dirh_e->hashvalue != hashvalue) continue; if (dirh_e->offset != offset) continue; /* got it already */ KASSERT(dirh_e->d_namlen == DIRENT_NAMLEN(dirent)); KASSERT(dirh_e->entry_size == entry_size); return; } DPRINTF(("dirhash enter %"PRIu64", %d, %d for `%*.*s`\n", offset, entry_size, DIRENT_NAMLEN(dirent), DIRENT_NAMLEN(dirent), DIRENT_NAMLEN(dirent), dirent->d_name)); /* check if entry is in free space list */ LIST_FOREACH(dirh_e, &dirh->free_entries, next) { if (dirh_e->offset == offset) { DPRINTF(("\tremoving free entry\n")); LIST_REMOVE(dirh_e, next); //pool_put(&dirhash_entry_pool, dirh_e); free(dirh_e); break; } } /* ensure we are not passing the dirhash limit */ entrysize = sizeof(struct dirhash_entry); if (dirhashsize + entrysize > maxdirhashsize) { /* we walk the dirhash_queue, so need to lock it */ mutex_enter(&dirhashmutex); del_dirh = TAILQ_LAST(&dirhash_queue, _dirhash); KASSERT(del_dirh); while (dirhashsize + entrysize > maxdirhashsize) { /* no use trying to delete myself */ if (del_dirh == dirh) break; prev_dirh = TAILQ_PREV(del_dirh, _dirhash, next); if (del_dirh->refcnt == 0) dirhash_purge_entries(del_dirh); del_dirh = prev_dirh; } mutex_exit(&dirhashmutex); } /* add to the hashline */ // dirh_e = pool_get(&dirhash_entry_pool, PR_WAITOK); dirh_e = malloc(sizeof(struct dirhash_entry)); assert(dirh_e); memset(dirh_e, 0, sizeof(struct dirhash_entry)); dirh_e->hashvalue = hashvalue; dirh_e->offset = offset; dirh_e->d_namlen = DIRENT_NAMLEN(dirent); dirh_e->entry_size = entry_size; dirh->size += sizeof(struct dirhash_entry); dirhashsize += sizeof(struct dirhash_entry); LIST_INSERT_HEAD(&dirh->entries[hashline], dirh_e, next); } void dirhash_enter_freed(struct dirhash *dirh, uint64_t offset, uint32_t entry_size) { struct dirhash_entry *dirh_e; /* make sure we have a dirhash to work on */ KASSERT(dirh); KASSERT(dirh->refcnt > 0); /* check for double entry of free space */ LIST_FOREACH(dirh_e, &dirh->free_entries, next) { KASSERT(dirh_e->offset != offset); } DPRINTF(("dirhash enter FREED %"PRIu64", %d\n", offset, entry_size)); //dirh_e = pool_get(&dirhash_entry_pool, PR_WAITOK); dirh_e = malloc(sizeof(struct dirhash_entry)); assert(dirh_e); memset(dirh_e, 0, sizeof(struct dirhash_entry)); dirh_e->hashvalue = 0; /* not relevant */ dirh_e->offset = offset; dirh_e->d_namlen = 0; /* not relevant */ dirh_e->entry_size = entry_size; /* XXX it might be preferable to append them at the tail */ LIST_INSERT_HEAD(&dirh->free_entries, dirh_e, next); dirh->size += sizeof(struct dirhash_entry); dirhashsize += sizeof(struct dirhash_entry); } void dirhash_mark_freed(struct dirhash *dirh, struct dirhash_entry *dirh_e, struct dirent *dirent) { uint64_t offset; uint32_t entry_size; /* make sure we have a dirhash to work on */ KASSERT(dirh_e); KASSERT(dirh); KASSERT(dirh->refcnt > 0); KASSERT(dirent); DPRINTF(("dirhash remove `%*.*s`\n", DIRENT_NAMLEN(dirent), DIRENT_NAMLEN(dirent), dirent->d_name)); offset = dirh_e->offset; entry_size = dirh_e->entry_size; LIST_REMOVE(dirh_e, next); free(dirh_e); dirh->size -= sizeof(struct dirhash_entry); dirhashsize -= sizeof(struct dirhash_entry); dirhash_enter_freed(dirh, offset, entry_size); return; } /* * BUGALERT: don't use result longer than needed, never past the node lock. * Call with NULL *result initially and it will return nonzero if again. */ int dirhash_lookup(struct dirhash *dirh, const char *d_name, int d_namlen, struct dirhash_entry **result) { struct dirhash_entry *dirh_e; uint32_t hashvalue, hashline; /* make sure we have a dirhash to work on */ KASSERT(dirh); KASSERT(dirh->refcnt > 0); /* start where we were */ if (*result) { dirh_e = *result; /* retrieve information to avoid recalculation and advance */ hashvalue = dirh_e->hashvalue; dirh_e = LIST_NEXT(*result, next); } else { /* calculate our hash and lookup all entries in hashline */ hashvalue = hash32_strn(d_name, d_namlen, HASH32_STR_INIT); hashline = hashvalue & DIRHASH_HASHMASK; dirh_e = LIST_FIRST(&dirh->entries[hashline]); } for (; dirh_e; dirh_e = LIST_NEXT(dirh_e, next)) { /* check for hash collision */ if (dirh_e->hashvalue != hashvalue) continue; if (dirh_e->d_namlen != (uint32_t) d_namlen) continue; /* might have an entry in the cache */ *result = dirh_e; return 1; } *result = NULL; return 0; } /* * BUGALERT: don't use result longer than needed, never past the node lock. * Call with NULL *result initially and it will return nonzero if again. */ int dirhash_lookup_freed(struct dirhash *dirh, uint32_t min_entrysize, struct dirhash_entry **result) { struct dirhash_entry *dirh_e; /* make sure we have a dirhash to work on */ KASSERT(dirh); KASSERT(dirh->refcnt > 0); /* start where we were */ if (*result) { dirh_e = LIST_NEXT(*result, next); } else { /* lookup all entries that match */ dirh_e = LIST_FIRST(&dirh->free_entries); } for (; dirh_e; dirh_e = LIST_NEXT(dirh_e, next)) { /* check for minimum size */ if (dirh_e->entry_size < min_entrysize) continue; /* might be a candidate */ *result = dirh_e; return 1; } *result = NULL; return 0; } UDFclient.0.8.8/udf_verbose.c010066400001470000000000001617511307041400500153410ustar reinoudwheel/* $NetBSD$ */ /* * File "udf_verbose.c" is part of the UDFclient toolkit. * File $Id: udf_verbose.c,v 1.118 2016/04/25 21:01:40 reinoud Exp $ $Name: $ * * Copyright (c) 2003, 2004, 2005, 2006, 2011 * Reinoud Zandijk * All rights reserved. * * The UDFclient toolkit is distributed under the Clarified Artistic Licence. * A copy of the licence is included in the distribution as * `LICENCE.clearified.artistic' and a copy of the licence can also be * requested at the GNU foundantion's website. * * Visit the UDFclient toolkit homepage http://www.13thmonkey.org/udftoolkit/ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include "udf.h" #include "udf_bswap.h" /* globals */ void udf_dump_id(char *prefix, int len, char *id, struct charspec *chsp); void udf_dump_long_ad(char *prefix, struct long_ad *adr); void udf_dump_descriptor(union dscrptr *dscrpt); void udf_dump_vat_table(struct udf_part_mapping *udf_part_mapping); void udf_dump_unimpl(union dscrptr *dscrpt, char *name) { dscrpt = dscrpt; printf("\t\t(unimplemented dump of `%s` tag)\n", name); } void udf_dump_desc(struct desc_tag *tag) { printf("\tTAG: descriptor %d, serial_num %d at sector %d, crc length %d bytes\n", udf_rw16(tag->id), udf_rw16(tag->serial_num), udf_rw32(tag->tag_loc), udf_rw16(tag->desc_crc_len)); } void udf_dump_anchor(struct anchor_vdp *vdp) { printf("\t\tAnchor\n"); printf("\t\t\tMain volume descriptor set at %d for %d bytes\n", udf_rw32(vdp->main_vds_ex.loc), udf_rw32(vdp->main_vds_ex.len)); printf("\t\t\tReserve volume descriptor set at %d for %d bytes\n", udf_rw32(vdp->reserve_vds_ex.loc), udf_rw32(vdp->reserve_vds_ex.len)); } void udf_dump_disc_anchors(struct udf_discinfo *disc) { int session; printf("\nUDF Dump of disc in device %s\n", disc->dev->dev_name); printf("UDF sessions : "); for (session = 0; session < disc->num_sessions; session++) { if (disc->session_is_UDF[session]) { printf("Yes"); #if 0 if (disc->session_quirks[session] & CD_SESS_QUIRK_SESSION_LOCAL) { printf("(local)"); } #endif printf(" "); } else { printf("No "); } } printf("\n\n"); UDF_VERBOSE_TABLES( struct udf_session *udf_session; /* Dump anchors */ STAILQ_FOREACH(udf_session, &disc->sessions, next_session) { printf("UDF session %d (lba %d + %d sectors) anchor dump : \n", udf_session->session_num, (uint32_t) disc->session_start[udf_session->session_num], (uint32_t) udf_session->session_length); udf_dump_descriptor((union dscrptr *) &udf_session->anchor); } ) } char *udf_messy_unicode_conv(char *buf) { static char out_buf[1024]; uint16_t *uni_pos, uni_char; char *pos; pos = out_buf; uni_pos = (uint16_t *) buf; while ((uni_char = *uni_pos++)) { if (uni_char & 0xff00) uni_char='_'; *pos++ = uni_char; } return out_buf; } char *udf_get_osname(int os_class, int os_id) { static char buffer[40]; switch (os_class) { case 0 : return "undefined OS"; case 1 : return "DOS/Windows 3.x"; case 2 : return "OS/2"; case 3 : return "MacOS"; case 4 : switch (os_id) { case 0 : return "UNIX"; case 1 : return "IBM AIX"; case 2 : return "SunOS/Solaris"; case 3 : return "HP/UX"; case 4 : return "Silicon Graphics Irix"; case 5 : return "Linux"; case 6 : return "MKLinux"; case 7 : return "FreeBSD"; case 8 : return "NetBSD"; default : sprintf(buffer, "unknown UNIX (%d)", os_id); return buffer; } case 5 : return "MS Windows 9x"; case 6 : return "MS Windows NT"; case 7 : return "OS/400"; case 8 : return "BeOS"; case 9 : return "MS Windows CE"; default : break; } sprintf(buffer, "unknown OS (%d, %d)", os_class, os_id); return buffer; } void udf_dump_regid(char *prefix, struct regid *id, int regid_type) { char buffer[UDF_REGID_ID_SIZE+1]; int cnt, version; uint8_t *pos; memcpy(buffer, id->id, UDF_REGID_ID_SIZE); buffer[UDF_REGID_ID_SIZE] = 0; printf("%s `%s`", prefix, buffer); if (regid_type == UDF_REGID_NAME) { printf("\n"); return; } printf(" ("); pos = id->id_suffix; switch (regid_type) { case UDF_REGID_DOMAIN : version = udf_rw16(*((uint16_t *) pos)); printf("UDFv %x; ", version); if ((pos[2]) & UDF_DOMAIN_FLAG_HARD_WRITE_PROTECT) printf("HARD "); if ((pos[2]) & UDF_DOMAIN_FLAG_SOFT_WRITE_PROTECT) printf("SOFT"); if (((pos[2]) & 3) == 0) printf("no"); printf(" write protect "); if ((pos[2]) & ~3) printf("; also undefined flags 0x%d", pos[2] & ~3); break; case UDF_REGID_UDF : version = udf_rw16(*((uint16_t *) pos)); printf("UDFv %x; ", version); printf("%s ", udf_get_osname(pos[2], pos[3])); break; case UDF_REGID_IMPLEMENTATION : printf("%s [", udf_get_osname(pos[0], pos[1])); for(cnt=2; cnt < 8; cnt++) { printf("%02x ", *pos++); } printf("]"); break; case UDF_REGID_NAME : break; case UDF_REGID_APPLICATION : default : printf("["); for(cnt=0; cnt < 8; cnt++) { printf("%02x ", *pos++); } printf("]"); break; } printf(") (flags=%d)\n", id->flags); } void udf_dump_timestamp(char *prefix, struct timestamp *t) { printf("%s (%4d %02d %02d at %02d:%02d:%02d.%02d.%02d.%02d)\n", prefix, udf_rw16(t->year), t->month, t->day, t->hour, t->minute, t->second, t->centisec, t->hund_usec, t->usec); } #if 0 void udf_dump_charspec(char *prefix, struct charspec *chsp) { int cnt, ch; printf("%s type CS%d (", prefix, chsp->type); for (cnt=0; cnt<63; cnt++) { ch = chsp->inf[cnt]; if (ch < 32 || ch > 126) { printf("."); } else { printf("%c", ch); } } printf(")\n"); } #endif void udf_dump_sparing_table(struct udf_sparing_table *spt) { struct spare_map_entry *sp_entry; uint32_t entry, entries; printf("\t\tSparing table descriptor\n"); udf_dump_regid("\t\t\tSparing table Id ", &spt->id, UDF_REGID_UDF); printf("\t\t\tRelocation table entries %d\n", udf_rw16(spt->rt_l)); printf("\t\t\tSequence number %d\n", udf_rw32(spt->seq_num)); printf("\t\t\tMappings :"); entries = udf_rw16(spt->rt_l); for(entry = 0; entry < entries; entry++) { if (entry % 4 == 0) printf("\n\t\t\t\t"); sp_entry = &spt->entries[entry]; printf("[%08x -> %08x] ", udf_rw32(sp_entry->org), udf_rw32(sp_entry->map)); } printf("\n"); } void udf_dump_pri_vol(struct pri_vol_desc *pvd) { struct extent_ad *ext; printf("\t\tPrimary volume descriptor\n"); printf("\t\t\tVolume descriptor sequence number %d\n", udf_rw32(pvd->seq_num)); printf("\t\t\tPrimary volume descriptor number %d\n", udf_rw32(pvd->pvd_num)); udf_dump_id("\t\t\tVolume Id ", 32, pvd->vol_id, &pvd->desc_charset); printf("\t\t\tVolume sequence number %d\n", udf_rw16(pvd->vds_num)); printf("\t\t\tMaximum volume sequence number %d\n", udf_rw16(pvd->max_vol_seq)); printf("\t\t\tInterchange level %d\n", udf_rw16(pvd->ichg_lvl)); printf("\t\t\tMaximum interchange level %d\n", udf_rw16(pvd->max_ichg_lvl)); udf_dump_id("\t\t\tVolume set Id ", 128, pvd->volset_id, &pvd->desc_charset); /* udf_dump_charspec("\t\t\tCharspec for this descriptor ", &pvd->desc_charset); */ /* udf_dump_charspec("\t\t\tCharspec for the explaination ", &pvd->explanatory_charset); */ ext = &pvd->vol_abstract; printf("\t\t\tVolume abstract at %d for %d bytes\n", udf_rw32(ext->loc), udf_rw32(ext->len)); ext = &pvd->vol_copyright; printf("\t\t\tVolume copyright at %d for %d bytes\n", udf_rw32(ext->loc), udf_rw32(ext->len)); udf_dump_regid("\t\t\tApplication id", &pvd->app_id, UDF_REGID_APPLICATION); udf_dump_timestamp("\t\t\tTimestamp", &pvd->time); udf_dump_regid("\t\t\tImplementator id", &pvd->imp_id, UDF_REGID_IMPLEMENTATION); printf("\t\t\tPrevious volume descriptor sequence locator at sector %d\n", udf_rw32(pvd->prev_vds_loc)); printf("\t\t\tFlags %d\n", udf_rw16(pvd->flags)); } void udf_dump_implementation_volume(struct impvol_desc *ivd) { struct charspec *charspec; printf("\t\tImplementation use volume descriptor\n"); printf("\t\t\tVolume descriptor sequence number %d\n", udf_rw32(ivd->seq_num)); udf_dump_regid("\t\t\tImplementator identifier", &ivd->impl_id, UDF_REGID_UDF); /* check on UDF implementation info ... */ if (strcmp((char *) ivd->impl_id.id, "*UDF LV Info") == 0) { charspec = &ivd->_impl_use.lv_info.lvi_charset; /* udf_dump_charspec("\t\t\tLV info charspec ", charspec); */ udf_dump_id("\t\t\tLogical volume identifier ", 128, ivd->_impl_use.lv_info.logvol_id, charspec); udf_dump_id("\t\t\tLV info 1 ", 36, ivd->_impl_use.lv_info.lvinfo1, charspec); udf_dump_id("\t\t\tLV info 2 ", 36, ivd->_impl_use.lv_info.lvinfo2, charspec); udf_dump_id("\t\t\tLV info 3 ", 36, ivd->_impl_use.lv_info.lvinfo3, charspec); udf_dump_regid("\t\t\tImplementation identifier", &ivd->_impl_use.lv_info.impl_id, UDF_REGID_IMPLEMENTATION); } } char *udf_dump_partition_access_type(int type) { switch (type) { case UDF_ACCESSTYPE_PSEUDO_OVERWITE : return "Pseudo overwiteable"; case UDF_ACCESSTYPE_READ_ONLY : return "Read only"; case UDF_ACCESSTYPE_WRITE_ONCE : return "Write once"; case UDF_ACCESSTYPE_REWRITEABLE : return "Rewritable (blocked or with erase)"; case UDF_ACCESSTYPE_OVERWRITABLE : return "Overwritable"; } return "Unknown partion access type"; } void udf_dump_part(struct part_desc *pd) { struct part_hdr_desc *part_hdr_desc; printf("\t\tPartition descriptor\n"); printf("\t\t\tVolume descriptor sequence number %d\n", udf_rw32(pd->seq_num)); printf("\t\t\tFlags %d\n", udf_rw16(pd->flags)); printf("\t\t\tPartition number %d\n", udf_rw16(pd->part_num)); udf_dump_regid("\t\t\tContents", &pd->contents, UDF_REGID_APPLICATION); printf("\t\t\tAccessType %s\n", udf_dump_partition_access_type(udf_rw32(pd->access_type))); printf("\t\t\tPartition starts at sector %u for %u sectors\n", udf_rw32(pd->start_loc), udf_rw32(pd->part_len)); udf_dump_regid("\t\t\tImplementator id", &pd->imp_id, UDF_REGID_IMPLEMENTATION); printf("\t\t\tPartition contents use (file) descriptors:\n"); if (strncmp((char *) pd->contents.id, "+NSR0", 5) == 0) { part_hdr_desc = &pd->pd_part_hdr; printf("\t\t\t\tUnallocated space table at logic block %u for %u bytes\n", udf_rw32(part_hdr_desc->unalloc_space_table.lb_num), udf_rw32(part_hdr_desc->unalloc_space_table.len) ); printf("\t\t\t\tUnallocated space bitmap at logic block %u for %u bytes\n", udf_rw32(part_hdr_desc->unalloc_space_bitmap.lb_num), udf_rw32(part_hdr_desc->unalloc_space_bitmap.len) ); printf("\t\t\t\tPartition integrity table at logic block %u for %u bytes\n", udf_rw32(part_hdr_desc->part_integrity_table.lb_num), udf_rw32(part_hdr_desc->part_integrity_table.len) ); printf("\t\t\t\tReusable (freed) space table at logic block %u for %u bytes\n", udf_rw32(part_hdr_desc->freed_space_table.lb_num), udf_rw32(part_hdr_desc->freed_space_table.len) ); printf("\t\t\t\tReusable (freed) space bitmap at logic block %u for %u bytes\n", udf_rw32(part_hdr_desc->freed_space_bitmap.lb_num), udf_rw32(part_hdr_desc->freed_space_bitmap.len) ); } else { printf("\t\t\t\tWARNING: Unknown or unused contents\n"); } } void udf_dump_log_vol(struct logvol_desc *lvd) { union udf_pmap *pmap; uint8_t pmap_type, pmap_size; uint8_t *pmap_pos; uint32_t map, sparing_table; uint32_t lb_size, packet_len; lb_size = udf_rw32(lvd->lb_size); printf("\t\tLogical volume descriptor\n"); printf("\t\t\tVolume descriptor sequence number %d\n", udf_rw32(lvd->seq_num)); udf_dump_id("\t\t\tLogical volume id ", 128, lvd->logvol_id, &lvd->desc_charset); printf("\t\t\tLogical block size %d\n", udf_rw32(lvd->lb_size)); udf_dump_regid("\t\t\tDomainId", &lvd->domain_id, UDF_REGID_DOMAIN); udf_dump_long_ad("\t\t\tFileset descriptor at", &lvd->_lvd_use.fsd_loc); printf("\t\t\tMap table length %d\n", udf_rw32(lvd->mt_l)); printf("\t\t\tNumber of part maps %d\n", udf_rw32(lvd->n_pm)); udf_dump_regid("\t\t\tImplementation id", &lvd->imp_id, UDF_REGID_IMPLEMENTATION); printf("\t\t\tIntegrety sequence at %d for %d bytes\n", udf_rw32(lvd->integrity_seq_loc.loc), udf_rw32(lvd->integrity_seq_loc.len)); printf("\t\t\tPartion maps follow\n"); pmap_pos = &lvd->maps[0]; for (map = 0; map < udf_rw32(lvd->n_pm); map++) { pmap = (union udf_pmap *) pmap_pos; pmap_type = pmap->data[0]; pmap_size = pmap->data[1]; printf("\t\t\t\tPartion map type %d length %d \n", pmap_type, pmap_size); /* only pmap types 1 and pmap types 2 are to be used */ printf("\t\t\t\t\tLogical %d maps to ", map); switch (pmap_type) { case 1 : printf("partition %d on volume seq. number %d directly\n", udf_rw16(pmap->pm1.part_num), udf_rw16(pmap->pm1.vol_seq_num)); break; case 2 : printf("partition %d on volume seq. number %d using\n", udf_rw16(pmap->pm2.part_num), udf_rw16(pmap->pm2.vol_seq_num)); udf_dump_regid("\t\t\t\t\tmapping type", &pmap->pm2.part_id, UDF_REGID_UDF); if (strncmp((char *) pmap->pm2.part_id.id, "*UDF Virtual Partition", UDF_REGID_ID_SIZE) == 0) { /* nothing to print... */ } if (strncmp((char *) pmap->pm2.part_id.id, "*UDF Sparable Partition", UDF_REGID_ID_SIZE) == 0) { packet_len = udf_rw16(pmap->pms.packet_len); printf("\t\t\t\t\t\tPacket length %d sectors (%d bytes)\n", packet_len, packet_len * lb_size); printf("\t\t\t\t\t\tNumber of sparing tables %d\n", pmap->pms.n_st); printf("\t\t\t\t\t\tSize of each sparing table %d\n", udf_rw32(pmap->pms.st_size)); if (pmap->pms.n_st) { printf("\t\t\t\t\t\tSparing tables at sectors "); for (sparing_table = 0; sparing_table < pmap->pms.n_st; sparing_table++) { printf("%d ", udf_rw32(pmap->pms.st_loc[sparing_table])); } printf("\n"); } } if (strncmp((char *) pmap->pm2.part_id.id, "*UDF Metadata Partition", UDF_REGID_ID_SIZE) == 0) { printf("\t\t\t\t\t\tMetadata is %sduplicated on disc\n", pmap->pmm.flags & METADATA_DUPLICATED ? "":"NOT "); printf("\t\t\t\t\t\tAllocation unit size %d sectors\n", udf_rw32(pmap->pmm.alloc_unit_size)); printf("\t\t\t\t\t\tAlignment unit size %d sectors\n", udf_rw32(pmap->pmm.alignment_unit_size)); printf("\t\t\t\t\t\tMetadata file at part. sector %d\n", udf_rw32(pmap->pmm.meta_file_lbn)); if (udf_rw32(pmap->pmm.meta_mirror_file_lbn) != (uint32_t) -1) printf("\t\t\t\t\t\tMetadata mirror file at part. sector %d\n", udf_rw32(pmap->pmm.meta_mirror_file_lbn)); if (udf_rw32(pmap->pmm.meta_bitmap_file_lbn) != (uint32_t) -1) printf("\t\t\t\t\t\tMetadata bitmap file at part. sector %d\n", udf_rw32(pmap->pmm.meta_bitmap_file_lbn)); } break; default : break; } pmap_pos += pmap_size; } } void udf_dump_unalloc_space(struct unalloc_sp_desc *usd) { struct extent_ad *alloc_desc; uint32_t desc_num; printf("\t\tUnallocated space descriptor\n"); printf("\t\t\tVolume descriptor sequence number %d\n", udf_rw32(usd->seq_num)); printf("\t\t\tNumber of free space slots %d\n", udf_rw32(usd->alloc_desc_num)); if (udf_rw32(usd->alloc_desc_num)) { printf("\t\t\tFree space at : "); for (desc_num = 0; desc_num < udf_rw32(usd->alloc_desc_num); desc_num++) { alloc_desc = &usd->alloc_desc[desc_num]; printf("[%d %d] ", udf_rw32(alloc_desc->loc), udf_rw32(alloc_desc->loc)+udf_rw32(alloc_desc->len)); } printf("\n"); } } void udf_dump_terminating_desc(union dscrptr *desc) { desc = desc; printf("\t\tTerminating descriptor\n"); } void udf_dump_logvol_integrity(struct logvol_int_desc *lvid) { struct udf_logvol_info *impl; uint32_t part, num_part; uint32_t *pos1, *pos2; uint32_t free, size, rest_bytes; uint32_t version; const char *inttp; printf("\t\tLogical volume integrity descriptor\n"); udf_dump_timestamp("\t\t\tTimestamp ", &lvid->time); inttp = "UNKNOWN/INVALID"; if (udf_rw32(lvid->integrity_type) == UDF_INTEGRITY_CLOSED) inttp = "closed"; if (udf_rw32(lvid->integrity_type) == UDF_INTEGRITY_OPEN) inttp = "closed"; printf("\t\t\tIntegrity type %s\n", inttp); printf("\t\t\tNext integrity sequence at %d for %d bytes\n", udf_rw32(lvid->next_extent.loc), udf_rw32(lvid->next_extent.len)); printf("\t\t\tNext free unique file ID %d\n", (uint32_t) udf_rw64(lvid->lvint_next_unique_id)); printf("\t\t\tLength of implementation use area %d bytes\n", udf_rw32(lvid->l_iu)); num_part = udf_rw32(lvid->num_part); printf("\t\t\tNumber of partitions %d\n", num_part); for (part=0; part < num_part; part++) { pos1 = &lvid->tables[0] + part; pos2 = &lvid->tables[0] + num_part + part; free = udf_rw32(*pos1); size = udf_rw32(*pos2); printf("\t\t\tPartition %d : %u blocks free space out of %u blocks\n", part, free, size); } /* printout the implementation use field */ impl = (struct udf_logvol_info *) (lvid->tables + 2*num_part); udf_dump_regid("\t\t\tImplemenator Id", &impl->impl_id, UDF_REGID_IMPLEMENTATION ); printf("\t\t\tNumber of files %d\n", udf_rw32(impl->num_files)); printf("\t\t\tNumber of directories %d\n", udf_rw32(impl->num_directories)); version = udf_rw16(impl->min_udf_readver); printf("\t\t\tMinimum readversion UDFv %x\n", version); version = udf_rw16(impl->min_udf_writever); printf("\t\t\tMinimum writeversion UDFv %x\n", version); version = udf_rw16(impl->max_udf_writever); printf("\t\t\tMaximum writeversion UDFv %x\n", version); rest_bytes = udf_rw32(lvid->l_iu)-sizeof(struct udf_logvol_info); if (rest_bytes > 0) printf("\t\t\t<%d bytes of undumped extra implementation use area>", rest_bytes); printf("\n"); } void udf_dump_fileset_desc(struct fileset_desc *fsd) { printf("\t\tFileset descriptor\n"); udf_dump_timestamp("\t\t\tTimestamp ", &fsd->time); printf("\t\t\tInterchange level %d\n", udf_rw16(fsd->ichg_lvl)); printf("\t\t\tMax interchange level %d\n", udf_rw16(fsd->max_ichg_lvl)); printf("\t\t\tCharset lists %d\n", udf_rw32(fsd->charset_list)); printf("\t\t\tMax charset lists %d\n", udf_rw32(fsd->max_charset_list)); printf("\t\t\tFileset number %d\n", udf_rw32(fsd->fileset_num)); printf("\t\t\tFileset descriptor number %d\n", udf_rw32(fsd->fileset_desc_num)); /* udf_dump_charspec("\t\t\tLogical volume id charspec ", &fsd->logvol_id_charset); */ /* udf_dump_charspec("\t\t\tFileset id charspec ", &fsd->fileset_charset); */ udf_dump_id("\t\t\tLogical volume id ", 128, fsd->logvol_id, &fsd->logvol_id_charset); udf_dump_id("\t\t\tFileset id ", 32, fsd->fileset_id, &fsd->fileset_charset); udf_dump_id("\t\t\tCopyright file id ", 32, fsd->copyright_file_id, &fsd->fileset_charset); udf_dump_id("\t\t\tAbstract file id ", 32, fsd->abstract_file_id, &fsd->fileset_charset); udf_dump_regid("\t\t\tDomainId", &fsd->domain_id, UDF_REGID_DOMAIN); udf_dump_long_ad("\t\t\tRootdir ICB found ", &fsd->rootdir_icb); udf_dump_long_ad("\t\t\tNext extend for fileset ", &fsd->next_ex); udf_dump_long_ad("\t\t\tStreamdir ICB found ", &fsd->streamdir_icb); } void udf_dump_fileid_in_charspec(struct fileid_desc *fid, struct charspec *chsp) { char *pos, file_char; printf("\tFile id entry\n"); printf("\t\tFile version number %d\n", udf_rw16(fid->file_version_num)); file_char = fid->file_char; printf("\t\tFile characteristics %d :\t", file_char); if (file_char & UDF_FILE_CHAR_VIS) printf("hidden "); if (file_char & UDF_FILE_CHAR_DEL) printf("deleted "); if (file_char & UDF_FILE_CHAR_PAR) printf("parent(..) "); if (file_char & UDF_FILE_CHAR_DIR) printf("directory "); if (file_char & UDF_FILE_CHAR_META) printf("METADATA "); printf("\n"); udf_dump_long_ad("\t\tFile ICB", &fid->icb); printf("\t\tLength of file identifier area %d\n", fid->l_fi); printf("\t\tOSTA UDF Unique ID %d\n", udf_rw32(fid->icb.impl.im_used.unique_id)); printf("\t\tOSTA UDF fileflags %d\n", udf_rw16(fid->icb.impl.im_used.flags)); printf("\t\tImplementation use length %d\n", udf_rw16(fid->l_iu)); if (udf_rw16(fid->l_iu)) { /* Ecma 1/7.4 demands a (padded if wanted) implementation identifier */ if (udf_rw16(fid->l_iu) >= sizeof(struct regid)) { udf_dump_regid("\t\t\tModified by", (struct regid *) &fid->data, UDF_REGID_IMPLEMENTATION); } else { printf("\t\t\tBROKEN fid, expected at least enough space for implementation regid\n"); } } pos = (char *) fid->data + udf_rw16(fid->l_iu); if (file_char & UDF_FILE_CHAR_PAR) { printf("\t\tParent directory ..\n"); } else { udf_dump_id("\t\tFilename", fid->l_fi, pos, chsp); } } void udf_dump_fileid(struct fileid_desc *fid) { struct charspec chsp; /* prolly OSTA compressed unicode anyway */ chsp.type = 0; strcpy((char *) chsp.inf, "OSTA Compressed Unicode"); udf_dump_fileid_in_charspec(fid, &chsp); } void udf_dump_icb_tag(struct icb_tag *icb_tag) { uint32_t flags, strat_param16; flags = udf_rw16(icb_tag->flags); strat_param16 = udf_rw16(icb_tag->strat_param16); printf("\t\tICB Prior direct entries recorded (excl.) %d\n", udf_rw32(icb_tag->prev_num_dirs)); printf("\t\tICB Strategy type %d\n", udf_rw16(icb_tag->strat_type)); printf("\t\tICB Strategy type flags %d %d\n", icb_tag->strat_param[0], icb_tag->strat_param[1]); printf("\t\tICB Maximum number of entries (non strat 4) %d\n", udf_rw16(icb_tag->max_num_entries)); printf("\t\tICB indirect entries/depth %d\n", strat_param16); printf("\t\tICB File type %d\n", icb_tag->file_type); printf("\t\tICB Parent ICB in logical block %d of mapped partition %d\n", udf_rw32(icb_tag->parent_icb.lb_num), udf_rw16(icb_tag->parent_icb.part_num)); printf("\t\tICB Flags %d\n", udf_rw16(icb_tag->flags)); printf("\t\t\tFile/directory information using : "); switch (flags & UDF_ICB_TAG_FLAGS_ALLOC_MASK) { case UDF_ICB_SHORT_ALLOC : printf("short allocation descriptor\n"); break; case UDF_ICB_LONG_ALLOC : printf("long allocation descriptor\n"); break; case UDF_ICB_EXT_ALLOC : printf("extended allocation descriptor (out of specs)\n"); break; case UDF_ICB_INTERN_ALLOC : printf("internal in the ICB\n"); break; } if (icb_tag->file_type == UDF_ICB_FILETYPE_DIRECTORY) if (flags & UDF_ICB_TAG_FLAGS_DIRORDERED) printf("\t\t\tOrdered directory\n"); if (flags & UDF_ICB_TAG_FLAGS_NONRELOC) printf("\t\t\tNot relocatable\n"); printf("\t\t\tFile flags :"); if (flags & UDF_ICB_TAG_FLAGS_SETUID) printf("setuid() "); if (flags & UDF_ICB_TAG_FLAGS_SETGID) printf("setgid() "); if (flags & UDF_ICB_TAG_FLAGS_STICKY) printf("sticky "); printf("\n"); if (flags & UDF_ICB_TAG_FLAGS_CONTIGUES) printf("\t\t\tFile is contigues i.e. in one piece effectively \n"); if (flags & UDF_ICB_TAG_FLAGS_MULTIPLEVERS) printf("\t\t\tExpect multiple versions of a file in this directory\n"); } void udf_dump_indirect_entry(struct indirect_entry *inde) { printf("\tIndirect (ICB) entry\n"); udf_dump_icb_tag(&inde->icbtag); udf_dump_long_ad("\t\tPointing at", &inde->indirect_icb); printf("\n"); } void udf_dump_allocation_entries(uint8_t addr_type, uint8_t *pos, uint32_t data_length) { union icb *icb; uint32_t size, piece_length, piece_flags; uint32_t entry; entry = 0; size = 0; while (data_length) { if (entry % 1 == 0) printf("\n\t"); printf(" [ "); printf("blob at "); /* what to do with strat type == 3 ? or is all set up ok then ? */ icb = (union icb *) pos; switch (addr_type) { case UDF_ICB_SHORT_ALLOC : piece_length = udf_rw32(icb->s_ad.len) & (((uint32_t) 1<<30)-1); piece_flags = udf_rw32(icb->s_ad.len) >> 30; /* XXX ecma167 48.14.1.1 XXX */ printf("sector %8u for %8d bytes", udf_rw32(icb->s_ad.lb_num), piece_length); if (piece_flags) printf(" flags %d", piece_flags); size = sizeof(struct short_ad); if (piece_length == 0) size = data_length; break; case UDF_ICB_LONG_ALLOC : piece_length = udf_rw32(icb->l_ad.len) & (((uint32_t) 1<<30)-1); piece_flags = udf_rw32(icb->l_ad.len) >> 30; /* XXX ecma167 48.14.1.1 XXX */ printf("sector %8d for %8d bytes in logical partion %d", udf_rw32(icb->l_ad.loc.lb_num), piece_length, udf_rw16(icb->l_ad.loc.part_num)); if (piece_flags) printf(" flags %d", piece_flags); size = sizeof(struct long_ad); if (piece_length == 0) size = data_length; break; case UDF_ICB_EXT_ALLOC : printf("extended alloc (help)"); size = sizeof(struct ext_ad); break; case UDF_ICB_INTERN_ALLOC : printf("internal blob here for %d bytes", data_length); size = data_length; break; } printf(" ] "); entry++; pos += size; data_length -=size; } printf("\n"); } /* TODO create a read-in/insert/cleanup etc. for extra attributes */ void udf_dump_extattrseq(uint8_t *start, uint32_t offset, uint32_t impl_offset, uint32_t appl_offset, uint32_t length) { struct impl_extattr_entry *impl_extattr; struct appl_extattr_entry *appl_extattr; struct filetimes_extattr_entry *filetimes_extattr; struct device_extattr_entry *device_extattr; struct vatlvext_extattr_entry *vatlvext_extattr; struct extattr_entry *extattr; struct timestamp *timestamp; struct charspec chsp; uint32_t extattr_len, au_l, iu_l, d_l; uint32_t type, subtype, chksum, attr_space, print_attr_space; uint32_t existence; uint8_t *pos; char *type_txt, what[256]; int is_free_ea_space, is_free_app_ea_space, is_vatlvext_space, bit; /* if used its OSTA compressed unicode anyway */ chsp.type = 0; strcpy((char *) chsp.inf, "OSTA Compressed Unicode"); /* if one of the offsets is `-1' (0xffffffff), it indicates that its not present; God i hate magic values */ if (impl_offset == UDF_IMPL_ATTR_LOC_NOT_PRESENT) printf("\t\tNOTE: indicated no implementation related attributes are recorded in this extent\n"); if (appl_offset == UDF_IMPL_ATTR_LOC_NOT_PRESENT) printf("\t\tNOTE: indicated no application related attributes are recorded in this extent\n"); pos = start; attr_space = UDF_REGID_UDF; /* really? */ while (length > 0) { extattr = (struct extattr_entry *) pos; extattr_len = udf_rw32(extattr->a_l); type = udf_rw32(extattr->type); subtype = extattr->subtype; if (pos == start) printf("\t\tStart of extended file related attributes area\n"); if (offset == impl_offset) printf("\t\tStart of implementation related attributes area\n"); if (offset == appl_offset) printf("\t\tStart of application related attributes area\n"); if (pos == start) attr_space = UDF_REGID_UDF; if (offset == impl_offset) attr_space = UDF_REGID_IMPLEMENTATION; if (offset == appl_offset) attr_space = UDF_REGID_APPLICATION; if (subtype != 1) printf("\t\t\tWARNING: unknown subtype %d\n", subtype); print_attr_space = attr_space; switch (type) { case 65536 : /* [4/48.10.8] application use extended attributes */ appl_extattr = (struct appl_extattr_entry *) pos; au_l = udf_rw32(appl_extattr->au_l); printf("\t\t\tApplication use extended attribute\n"); if (attr_space != UDF_REGID_APPLICATION) printf("\t\t\t\t*** application use extended attribute found in non application use area ***\n"); printf("\t\t\t\tLength of application use space %d\n", au_l); udf_dump_regid("\t\t\t\tApplication use Id", &appl_extattr->appl_id, attr_space); break; case 2048 : /* [4/48.10.9] implementation use extended attributes */ impl_extattr = (struct impl_extattr_entry *) pos; iu_l = udf_rw32(impl_extattr->iu_l); chksum = udf_rw16(impl_extattr->data16); printf("\t\t\tImplementation use extended attribute\n"); if (chksum != udf_ea_cksum(pos)) printf("\t\t\t\t*** header checksum failed (%d should be %d) ***\n", chksum, udf_ea_cksum(pos)); if (attr_space != UDF_REGID_IMPLEMENTATION) printf("\t\t\t\t*** implementation use extended attribute found in non implementation use area ***\n"); if (strncmp((char *) impl_extattr->imp_id.id, "*UDF", 4) == 0) print_attr_space = UDF_REGID_UDF; printf("\t\t\t\tLength of implementation use space %d\n", iu_l); udf_dump_regid("\t\t\t\tImplemenation use Id", &impl_extattr->imp_id, print_attr_space); is_free_ea_space = (strcmp((char *) impl_extattr->imp_id.id, "*UDF FreeEASpace") == 0); is_free_app_ea_space = (strcmp((char *) impl_extattr->imp_id.id, "*UDF FreeAppEASpace") == 0); is_vatlvext_space = (strcmp((char *) impl_extattr->imp_id.id, "*UDF VAT LVExtension") == 0); if (is_free_ea_space || is_free_app_ea_space) { printf("\t\t\t\tFree space for new extended attributes (%d bytes total)\n", extattr_len); } else if (is_vatlvext_space) { vatlvext_extattr = (struct vatlvext_extattr_entry *) (impl_extattr->data + iu_l); printf("\t\t\t\t\tUniqueID check %"PRIu64"\n", udf_rw64(vatlvext_extattr->unique_id_chk)); printf("\t\t\t\t\tNumber of files %d\n", udf_rw32(vatlvext_extattr->num_files)); printf("\t\t\t\t\tNumber of directories %d\n", udf_rw32(vatlvext_extattr->num_directories)); udf_dump_id("\t\t\t\t\tLogical volume id ", 128, vatlvext_extattr->logvol_id, &chsp); } else { printf("\t\t\t\t\n", iu_l); } break; case 1 : /* [4/48.10.3] : Character set information; UDF does allow/disallow explicitly */ printf("\t\t\tCharacter set information attribute\n"); printf("\t\t\t\t\n", extattr_len); break; case 3 : /* [4/48.10.4] : Alternate permissions; UDF 3.3.4.2: not to be recorded */ printf("\t\t\tAlternate permission attribute\n"); printf("\t\t\t\t\n", extattr_len); break; case 5 : /* [4/48.10.5] : File Times Extended Attribute */ case 6 : /* [4/48.10.6] : Information Times Extended Attribute; recorded in UDF ? */ /* ASSUMPTION : bit fields are not exlusive */ filetimes_extattr = (struct filetimes_extattr_entry *) pos; d_l = udf_rw32(filetimes_extattr->d_l); existence = udf_rw32(filetimes_extattr->existence); type_txt = "File"; if (type == 6) type_txt = "File information"; printf("\t\t\t%s times extended attribute\n", type_txt); timestamp = &filetimes_extattr->times[0]; for (bit = 0; bit < 32; bit++) { if (d_l == 0) break; if ((existence & (1 << bit)) == 0) continue; switch (bit) { case 0 : /* File Creation Date and Time: the date and time of the day at which the file was created. */ sprintf(what, "\t\t\t\t%s created at ", type_txt); break; case 1 : /* Information Last Modification Date and Time: the date and time of the day at which the information in the file was last modified. */ sprintf(what, "\t\t\t\t%s last modified at ", type_txt); break; case 2 : /* File Deletion Date and Time: the date and time of the day after which the file may be deleted. */ sprintf(what, "\t\t\t\t%s may be deleted after ", type_txt); break; case 3 : /* File Effective Date and Time: the date and time of the day after which the file may be used. */ sprintf(what, "\t\t\t\t%s may only be used after ", type_txt); break; case 5 : /* File Last Backup Date and Time: the date and time of the day at which the file was last backed up. */ sprintf(what, "\t\t\t\t%s last backuped at ", type_txt); break; default : /* unspec */ sprintf(what, "\t\t\t\tUndefined meaning for %s time stamp ", type_txt); break; } udf_dump_timestamp(what, timestamp); d_l -= sizeof(struct timestamp); timestamp++; /* advance */ } break; case 12 : /* [4/48.10.7] : Device Specification Extended Attribute */ device_extattr = (struct device_extattr_entry *) pos; iu_l = udf_rw32(device_extattr->iu_l); printf("\t\t\tDevice node extended attribute\n"); printf("\t\t\t\tMajor %d\n", udf_rw32(device_extattr->major)); printf("\t\t\t\tMinor %d\n", udf_rw32(device_extattr->minor)); if (iu_l >= sizeof(struct regid)) { udf_dump_regid("\t\t\t\tImplementator", (struct regid *) (device_extattr->data), UDF_REGID_IMPLEMENTATION); } break; default : printf("\t\t\tUndumped extended attribute type %d\n", type); printf("\t\t\t\tSubtype %d\n", subtype); printf("\t\t\t\tLength %d\n", extattr_len); break; } if (extattr_len == 0) { printf("\t\t\tABORTing dump\n"); break; } pos += extattr_len; offset += extattr_len; length -= extattr_len; } printf("\n"); } void udf_dump_extattr_hdr(struct extattrhdr_desc *eahd, uint32_t length) { uint32_t hdr_len, impl_attr_loc, appl_attr_loc; uint8_t *pos; hdr_len = (uint32_t) sizeof(struct extattrhdr_desc); impl_attr_loc = udf_rw32(eahd->impl_attr_loc); appl_attr_loc = udf_rw32(eahd->appl_attr_loc); printf("\t\tExtended attributes header:\n"); printf("\t\t\tLength %d bytes\n", length); printf("\t\t\tImplementation attributes at offset %d\n", impl_attr_loc); printf("\t\t\tApplication attributes at offset %d\n", appl_attr_loc); printf("\t\t\tBytes remaining after header %d\n", length - hdr_len); /* determine length of file related attributes space */ pos = (uint8_t *) eahd; pos += hdr_len; length -= hdr_len; udf_dump_extattrseq(pos, hdr_len, impl_attr_loc, appl_attr_loc, length); } void udf_dump_file_entry(struct file_entry *fe) { uint8_t *pos; uint32_t length; uint8_t addr_type; /* direct_entries = udf_rw32(fe->icbtag.prev_num_dirs); */ //strat_param16 = udf_rw16(* (uint16_t *) (fe->icbtag.strat_param)); //entries = udf_rw16(fe->icbtag.max_num_entries); //strategy = udf_rw16(fe->icbtag.strat_type); addr_type = udf_rw16(fe->icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK; printf("\tFile entry\n"); udf_dump_icb_tag(&fe->icbtag); printf("\t\tUid %d\n", udf_rw32(fe->uid)); printf("\t\tGid %d\n", udf_rw32(fe->gid)); printf("\t\tPermissions %x\n", udf_rw32(fe->perm)); printf("\t\tLink count %d\n", udf_rw16(fe->link_cnt)); printf("\t\tRecord format %d\n", fe->rec_format); printf("\t\tRecord display attributes %d\n", fe->rec_disp_attr); printf("\t\tRecord length %d\n", fe->rec_len); printf("\t\tInformation length %"PRIu64"\n", (uint64_t) udf_rw64(fe->inf_len)); printf("\t\tLogical blocks recorded %"PRIu64"\n", (uint64_t) udf_rw64(fe->logblks_rec)); udf_dump_timestamp("\t\tAccess time ", &fe->atime); udf_dump_timestamp("\t\tModification time ", &fe->mtime); udf_dump_timestamp("\t\tAttribute time ", &fe->attrtime); printf("\t\tCheckpoint %d\n", udf_rw32(fe->ckpoint)); udf_dump_long_ad("\t\tExtended attributes ICB at", &fe->ex_attr_icb); udf_dump_regid("\t\tImplementation", &fe->imp_id, UDF_REGID_IMPLEMENTATION); printf("\t\tUniqueID %d\n", (uint32_t) udf_rw64(fe->unique_id)); printf("\t\tLength of extended attribute area %d\n", udf_rw32(fe->l_ea)); printf("\t\tLength of allocation descriptors %d\n", udf_rw32(fe->l_ad)); if (udf_rw32(fe->l_ea)) { udf_dump_extattr_hdr((struct extattrhdr_desc *) &fe->data[0], udf_rw32(fe->l_ea)); } if (udf_rw32(fe->ex_attr_icb.len)) { printf("\t\tex_attr_icb.len)); } printf("\t\tAllocation descriptors : \n"); pos = &fe->data[0] + udf_rw32(fe->l_ea); length = udf_rw32(fe->l_ad); udf_dump_allocation_entries(addr_type, pos, length); } void udf_dump_extfile_entry(struct extfile_entry *efe) { uint8_t *pos; uint32_t length; uint8_t addr_type; /* direct_entries = udf_rw32(efe->icbtag.prev_num_dirs); */ //strat_param16 = udf_rw16(* (uint16_t *) (efe->icbtag.strat_param)); //entries = udf_rw16(efe->icbtag.max_num_entries); //strategy = udf_rw16(efe->icbtag.strat_type); addr_type = udf_rw16(efe->icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK; printf("\tExtended file entry\n"); udf_dump_icb_tag(&efe->icbtag); printf("\t\tUid %d\n", udf_rw32(efe->uid)); printf("\t\tGid %d\n", udf_rw32(efe->gid)); printf("\t\tPermissions %x\n", udf_rw32(efe->perm)); printf("\t\tLink count %d\n", udf_rw16(efe->link_cnt)); printf("\t\tRecord format %d\n", efe->rec_format); printf("\t\tRecord display attributes %d\n", efe->rec_disp_attr); printf("\t\tRecord length %d\n", efe->rec_len); printf("\t\tInformation length %"PRIu64"\n", (uint64_t) udf_rw64(efe->inf_len)); printf("\t\tObject size %"PRIu64"\n", (uint64_t) udf_rw64(efe->obj_size)); printf("\t\tLogical blocks recorded %"PRIu64"\n", (uint64_t) udf_rw64(efe->logblks_rec)); udf_dump_timestamp("\t\tAccess time ", &efe->atime); udf_dump_timestamp("\t\tModification time ", &efe->mtime); udf_dump_timestamp("\t\tCreation time ", &efe->ctime); udf_dump_timestamp("\t\tAttribute time ", &efe->attrtime); printf("\t\tCheckpoint %d\n", udf_rw32(efe->ckpoint)); udf_dump_long_ad("\t\tExtended attributes ICB at", &efe->ex_attr_icb); udf_dump_long_ad("\t\tStreamdir ICB at", &efe->streamdir_icb); udf_dump_regid("\t\tImplementation", &efe->imp_id, UDF_REGID_IMPLEMENTATION); printf("\t\tUniqueID %d\n", (uint32_t) udf_rw64(efe->unique_id)); printf("\t\tLength of extended attribute area %d\n", udf_rw32(efe->l_ea)); printf("\t\tLength of allocation descriptors %d\n", udf_rw32(efe->l_ad)); if (udf_rw32(efe->l_ea)) { udf_dump_extattr_hdr((struct extattrhdr_desc *) &efe->data[0], udf_rw32(efe->l_ea)); } if (udf_rw32(efe->ex_attr_icb.len)) { printf("\t\tex_attr_icb.len)); } printf("\t\tAllocation descriptors : \n"); pos = &efe->data[0] + udf_rw32(efe->l_ea); length = udf_rw32(efe->l_ad); udf_dump_allocation_entries(addr_type, pos, length); } /* dump allocation extention descriptor */ void udf_dump_alloc_extent(struct alloc_ext_entry *ext, int addr_type) { uint8_t *pos; uint32_t length; int isshort, islong; /* note we DONT know if its filled with short_ad's or long_ad's! */ printf("\tAllocation Extent descriptor\n"); printf("\t\tPrevious entry %d\n", udf_rw32(ext->prev_entry)); printf("\t\tLength of allocation descriptors %d\n", udf_rw32(ext->l_ad)); pos = &ext->data[0]; length = udf_rw32(ext->l_ad); if (addr_type < 0) { isshort = ((length % sizeof(struct short_ad)) == 0); islong = ((length % sizeof(struct long_ad)) == 0); if (isshort) addr_type = UDF_ICB_SHORT_ALLOC; if (islong) addr_type = UDF_ICB_LONG_ALLOC; if (!(isshort ^ islong)) { printf("\t\tCan't determine if its filled with long_ad's or short_ad's !\n"); return; } } udf_dump_allocation_entries(addr_type, pos, length); } /* dump a space table(entry) descriptor */ void udf_dump_space_entry(struct space_entry_desc *sed) { union icb *icb; uint32_t addr_type, size, bytes; uint32_t piece_sector, piece_length, piece_part; uint8_t *pos; printf("\tSpace entry table\n"); udf_dump_icb_tag(&sed->icbtag); printf("\t\tSize in bytes %d\n", udf_rw32(sed->l_ad)); pos = &sed->entry[0]; bytes = udf_rw32(sed->l_ad); addr_type = udf_rw16(sed->icbtag.flags) & UDF_ICB_TAG_FLAGS_ALLOC_MASK; while (bytes) { size = piece_length = piece_sector = piece_part = 0; icb = (union icb *) pos; switch (addr_type) { case UDF_ICB_SHORT_ALLOC : piece_length = udf_rw32(icb->s_ad.len) & (((uint32_t) 1<<31)-1); piece_sector = udf_rw32(icb->s_ad.lb_num); printf("[at sec %u for %d bytes] ", piece_sector, piece_length); size = sizeof(struct short_ad); break; case UDF_ICB_LONG_ALLOC : piece_length = udf_rw32(icb->l_ad.len) & (((uint32_t) 1<<31)-1); piece_sector = udf_rw32(icb->l_ad.loc.lb_num); piece_part = udf_rw16(icb->l_ad.loc.part_num); size = sizeof(struct long_ad); printf("[at sec %u for %d bytes at partition %d] ", piece_sector, piece_length, piece_part); break; case UDF_ICB_EXT_ALLOC : case UDF_ICB_INTERN_ALLOC : printf("\t\t\tWARNING : an internal alloc in a space entry?\n"); return; } bytes -= size; } } /* dump a space bitmap descriptor */ void udf_dump_space_bitmap(struct space_bitmap_desc *sbd) { uint32_t bits, from, now, cnt; uint8_t byte, bit, bitpos, state, *pos; printf("\t\tSpace bitmap\n"); printf("\t\t\tNumber of bits %u\n", udf_rw32(sbd->num_bits)); printf("\t\t\tNumber of bytes %u\n", udf_rw32(sbd->num_bytes)); printf("\t\t\tMarked parts at :\n"); pos = sbd->data; bits = udf_rw32(sbd->num_bits); /* shield */ /* if (bits > 2000*8) bits = 2000*8; */ printf("\t\t\t\t"); cnt = 0; from = 0; now = 0; bitpos = 0; byte = *pos; state = byte & 1; while (now < bits) { if (bitpos == 0) { byte = *pos++; } bit = byte & 1; if (bit != state) { if (state) { printf("[%08u - %08u]", from, now-1); if (cnt % 4 == 3) printf("\n\t\t\t\t"); else printf(" "); cnt++; } from = now; state = bit; } byte >>= 1; bitpos = (bitpos+1) & 7; now++; } if (state) printf("[%08u - %08u]", from, now); if (bits < udf_rw32(sbd->num_bits)) printf(" .... \n"); } /* main descriptor `dump' function */ void udf_dump_descriptor(union dscrptr *dscrpt) { struct desc_tag *tag = &dscrpt->tag; int error; if (!dscrpt) return; /* check if its a valid descritor */ if (udf_rw16(tag->id == 0) && udf_rw16(tag->descriptor_ver) == 0) return; udf_dump_desc(tag); error = udf_check_tag(dscrpt); if (error) { printf("\tBAD TAG\n"); return; } switch (udf_rw16(tag->id)) { case TAGID_SPARING_TABLE : udf_dump_sparing_table(&dscrpt->spt); break; case TAGID_PRI_VOL : udf_dump_pri_vol(&dscrpt->pvd); break; case TAGID_ANCHOR : udf_dump_anchor(&dscrpt->avdp); break; case TAGID_VOL : udf_dump_unimpl(dscrpt, "volume descriptor"); break; case TAGID_IMP_VOL : udf_dump_implementation_volume(&dscrpt->ivd); break; case TAGID_PARTITION : udf_dump_part(&dscrpt->pd); break; case TAGID_LOGVOL : udf_dump_log_vol(&dscrpt->lvd); break; case TAGID_UNALLOC_SPACE : udf_dump_unalloc_space(&dscrpt->usd); break; case TAGID_TERM : udf_dump_terminating_desc(dscrpt); break; case TAGID_LOGVOL_INTEGRITY : udf_dump_logvol_integrity(&dscrpt->lvid); break; case TAGID_FSD : udf_dump_fileset_desc(&dscrpt->fsd); break; case TAGID_FID : udf_dump_fileid(&dscrpt->fid); break; case TAGID_ALLOCEXTENT : udf_dump_alloc_extent(&dscrpt->aee, -1); break; case TAGID_INDIRECT_ENTRY : udf_dump_indirect_entry(&dscrpt->inde); break; case TAGID_FENTRY : udf_dump_file_entry(&dscrpt->fe); break; case TAGID_EXTATTR_HDR : udf_dump_extattr_hdr(&dscrpt->eahd, sizeof(struct extattrhdr_desc)); break; case TAGID_UNALL_SP_ENTRY : udf_dump_space_entry(&dscrpt->sed); break; case TAGID_SPACE_BITMAP : udf_dump_space_bitmap(&dscrpt->sbd); break; case TAGID_PART_INTEGRETY : udf_dump_unimpl(dscrpt, "partition integrity"); break; case TAGID_EXTFENTRY : udf_dump_extfile_entry(&dscrpt->efe); break; default : break; } printf("\n"); } /* this one is special since the VAT table has no tag but is a file */ void udf_dump_vat_table(struct udf_part_mapping *udf_part_mapping) { struct charspec chsp; struct udf_vat *vat; uint32_t previous_vat, entry, vat_entries, *vat_pos, version; /* prolly OSTA compressed unicode anyway */ chsp.type = 0; strcpy((char *) chsp.inf, "OSTA Compressed Unicode"); vat = udf_part_mapping->vat; printf("\tVAT table: "); printf("%s UDF 2.00 format\n", vat?"post":"pre"); vat_entries = udf_part_mapping->vat_entries; vat_pos = (uint32_t *) udf_part_mapping->vat_translation; if (vat) { printf("\t\tHeader length %d\n", udf_rw16(vat->header_len)); printf("\t\tImplementation use length %d\n", udf_rw16(vat->impl_use_len)); udf_dump_id("\t\tLogical volume id ", 128, vat->logvol_id, &chsp); printf("\t\tNumber of files %d\n", udf_rw32(vat->num_files)); printf("\t\tNumber of directories %d\n", udf_rw32(vat->num_directories)); version = udf_rw16(vat->min_udf_readver); printf("\t\tMinimum readversion UDFv %x\n", version); version = udf_rw16(vat->min_udf_writever); printf("\t\tMinimum writeversion UDFv %x\n", version); version = udf_rw16(vat->max_udf_writever); printf("\t\tMaximum writeversion UDFv %x\n", version); if (udf_rw16(vat->impl_use_len)) printf("\t\t"); previous_vat = udf_rw32(vat->prev_vat); } else { udf_dump_regid("\t\tIdentifier id (can be wrong) ", (struct regid *) (vat_pos+vat_entries), UDF_REGID_NAME); previous_vat = udf_rw32(*(vat_pos + vat_entries + 32/4)); /* definition */ } if (previous_vat == 0xffffffff) { printf("\t\tNo previous VAT recorded\n"); } else { printf("\t\tPrevious VAT recorded at offset %d\n", previous_vat); } printf("\t\tNumber of VAT entries %d\n", vat_entries); printf("\t\tVAT dump :"); for (entry=0; entry < vat_entries; entry++) { if ((entry % 4) == 0) printf("\n\t"); printf("[0x%08x -> 0x%08x] ", entry, *vat_pos++); } printf("\n"); } void udf_dump_volumeset_info(struct udf_volumeset *udf_volumeset) { struct udf_pri_vol *primary; struct udf_log_vol *logical; struct udf_partition *udf_partition; struct udf_part_mapping *udf_part_mapping; struct udf_discinfo *disc; char *name; int num_volumes, num_partitions; int subvolume, part_num, track_num; num_volumes = 0; /* shut up gcc */ if (udf_volumeset->obsolete) return; primary = STAILQ_FIRST(&udf_volumeset->primaries); if (primary) { num_volumes = udf_rw16(primary->pri_vol->max_vol_seq); if (udf_volumeset->obsolete) printf("OBSOLETE\n"); /* XXX */ printf("Volume set "); udf_dump_id(NULL, 32, primary->pri_vol->volset_id, &primary->pri_vol->desc_charset); printf(" (%d volume%s) ", num_volumes, num_volumes>1?"s":""); num_partitions = udf_volumeset->max_partnum; printf("with %d partition%s\n", num_partitions, (num_partitions!=1)?"s":""); /* better loop trough the partition numbers to display them in a defined order */ SLIST_FOREACH(udf_partition, &udf_volumeset->parts, next_partition) { part_num = udf_rw16(udf_partition->partition->part_num); if (udf_partition) { /* there is information */ assert(udf_partition->udf_session); assert(udf_partition->udf_session->disc); assert(udf_partition->partition); assert(part_num == udf_rw16(udf_partition->partition->part_num)); track_num = udf_partition->udf_session->session_num; disc = udf_partition->udf_session->disc; printf("\tPartition number %d at device `%s' session %d from sector %d(+%d) for %u sectors\n", part_num, disc->dev->dev_name, track_num, udf_rw32(udf_partition->partition->start_loc), udf_partition->udf_session->session_offset, udf_rw32(udf_partition->partition->part_len) ); } else { printf("\tUnknown partition %d [unknown]\n", part_num); } } } STAILQ_FOREACH(primary, &udf_volumeset->primaries, next_primary) { subvolume = udf_rw16(primary->pri_vol->vds_num); printf("\tPrimary volume "); udf_dump_id(NULL, 32, primary->pri_vol->vol_id, &primary->pri_vol->desc_charset); printf(" (part %d/%d) ", subvolume, num_volumes); printf("created by implementator `%s' ", primary->pri_vol->imp_id.id); if (*primary->pri_vol->app_id.id) printf("by/for application `%s' ",primary->pri_vol->app_id.id); printf("\n"); SLIST_FOREACH(logical, &primary->log_vols, next_logvol) { name = logical->log_vol->logvol_id; udf_dump_id("\t\tcontains logical volume ", 128, name, &logical->log_vol->desc_charset); if (logical->broken) { printf("\t\t\tBROKEN\n"); continue; } SLIST_FOREACH(udf_part_mapping, &logical->part_mappings, next_mapping) { printf("\t\t\tmapping %d on %d as ", udf_part_mapping->udf_virt_part_num, udf_part_mapping->udf_phys_part_num); switch (udf_part_mapping->udf_part_mapping_type) { case UDF_PART_MAPPING_ERROR : printf("bad partition"); break; case UDF_PART_MAPPING_PHYSICAL : printf("direct"); break; case UDF_PART_MAPPING_VIRTUAL : printf("virtual partition"); break; case UDF_PART_MAPPING_SPARABLE : printf("sparable"); break; case UDF_PART_MAPPING_META : printf("metadata only"); } printf(" recording"); if (udf_part_mapping->data_writable) printf(" data"); if (udf_part_mapping->metadata_writable) printf(" metadata"); if (!udf_part_mapping->data_writable && !udf_part_mapping->metadata_writable) printf(" nothing"); printf("\n"); } } printf("\n"); } } void udf_dump_alive_sets(void) { struct udf_volumeset *udf_volumeset; printf("UDF volume sets marked alive :\n"); SLIST_FOREACH(udf_volumeset, &udf_volumeset_list, next_volumeset) { udf_dump_volumeset_info(udf_volumeset); } printf("\n"); } /* * extern defined read_logvol_descriptor breaks splitting rules but how * otherwise to provide a detailed description of the file entry udf_node */ #define DUMP_DIRBUFFER_SIZE (16*1024) void udf_dump_file_entry_node(struct udf_node *udf_node, char *prefix) { struct long_ad udf_icbptr; struct uio dir_uio; struct iovec dir_iovec; struct dirent *dirent; struct fileid_desc *fid; struct udf_node *entry_node; uint32_t pos, lb_size; uint8_t *buffer; char fullpath[1024]; /* XXX arbitrary length XXX */ int isdot, isdotdot, isdir, found, eof; int error; if (!udf_node) return; /* XXX could pass on dirent XXX */ isdir = (udf_node->udf_filetype == UDF_ICB_FILETYPE_DIRECTORY); isdir |= (udf_node->udf_filetype == UDF_ICB_FILETYPE_STREAMDIR); if (isdir) { buffer = malloc(DUMP_DIRBUFFER_SIZE); if (!buffer) return; lb_size = udf_node->udf_log_vol->lb_size; fid = malloc(lb_size); assert(fid); /* or just return? */ /* recurse into this directory */ dir_uio.uio_offset = 0; /* begin at start */ do { dir_iovec.iov_base = buffer; dir_iovec.iov_len = DUMP_DIRBUFFER_SIZE; dir_uio.uio_resid = DUMP_DIRBUFFER_SIZE; dir_uio.uio_iovcnt = 1; dir_uio.uio_iov = &dir_iovec; dir_uio.uio_rw = UIO_WRITE; error = udf_readdir(udf_node, &dir_uio, &eof); if (error) { printf("While reading in dirbuffer for dumping file entry udf_node : %s\n", strerror(error)); break; } pos = 0; while (pos < DUMP_DIRBUFFER_SIZE - dir_uio.uio_resid) { dirent = (struct dirent *) (buffer + pos); sprintf(fullpath, "%s/%s", prefix, dirent->d_name); /* looking for '.' or '..' ? */ isdot = (strncmp(dirent->d_name, ".", DIRENT_NAMLEN(dirent)) == 0); isdotdot = (strncmp(dirent->d_name, "..", DIRENT_NAMLEN(dirent)) == 0); pos += sizeof(struct dirent); /* XXX variable size dirents possible XXX */ if (isdotdot) continue; if (isdot) continue; error = udf_lookup_name_in_dir(udf_node, dirent->d_name, DIRENT_NAMLEN(dirent), &udf_icbptr, fid, &found); if (!error) { error = ENOENT; if (found) error = udf_readin_udf_node(udf_node, &udf_icbptr, fid, &entry_node); } if (!error) udf_dump_file_entry_node(entry_node, fullpath); } } while (!eof); free(fid); free(buffer); return; } /* leaf udf_node */ printf("%s\n", prefix); } #undef DUMP_DIRBUFFER_SIZE void udf_dump_root_dir(struct udf_mountpoint *mountpoint) { printf("\n\nRoot dir dump\n"); if (mountpoint->rootdir_node) udf_dump_file_entry_node(mountpoint->rootdir_node, ":Rootdir"); printf("\n\nStreamdir dump\n"); if (mountpoint->streamdir_node) udf_dump_file_entry_node(mountpoint->streamdir_node, ":Streamdir"); } /* XXX These should move to form one cd verbose file with cd_discect XXX */ static char *print_disc_state(int state) { switch (state) { case 0: return "empty disc"; case 1: return "incomplete (appendable)"; case 2: return "full (not appendable)"; case 3: return "random writable"; } return "unknown disc state"; } static char *print_session_state(int state) { switch (state) { case 0 : return "empty"; case 1 : return "incomplete"; case 2 : return "reserved/damaged"; case 3 : return "complete/closed disc"; } return "unknown session_state"; } static char *print_mmc_profile(int profile) { static char scrap[100]; switch (profile) { case 0x00 : return "Unknown[0] profile"; case 0x01 : return "Non removable disc"; case 0x02 : return "Removable disc"; case 0x03 : return "Magneto Optical with sector erase"; case 0x04 : return "Magneto Optical write once"; case 0x05 : return "Advance Storage Magneto Optical"; case 0x08 : return "CD-ROM"; case 0x09 : return "CD-R recordable"; case 0x0a : return "CD-RW rewritable"; case 0x10 : return "DVD-ROM"; case 0x11 : return "DVD-R sequential"; case 0x12 : return "DVD-RAM rewritable"; case 0x13 : return "DVD-RW restricted overwrite"; case 0x14 : return "DVD-RW sequential"; case 0x1a : return "DVD+RW rewritable"; case 0x1b : return "DVD+R recordable"; case 0x20 : return "DDCD readonly"; case 0x21 : return "DDCD-R recodable"; case 0x22 : return "DDCD-RW rewritable"; case 0x2b : return "DVD+R double layer"; case 0x40 : return "BD-ROM"; case 0x41 : return "BD-R Sequential Recording (SRM)"; case 0x42 : return "BD-R Random Recording (RRM)"; case 0x43 : return "BD-RE rewritable"; } sprintf(scrap, "Reserved profile 0x%02x", profile); return scrap; } void udf_dump_discinfo(struct udf_discinfo *disc) { int session; printf("Disc info for disc in device %s\n", disc->dev->dev_name); printf("\tMMC profile : %s\n", print_mmc_profile(disc->mmc_profile)); printf("\tsequential : %s\n", disc->sequential ?"yes":" no"); printf("\trecordable : %s\n", disc->recordable ?"yes":" no"); printf("\terasable : %s\n", disc->erasable ?"yes":" no"); printf("\tblankable : %s\n", disc->blankable ?"yes":" no"); printf("\tformattable : %s\n", disc->formattable ?"yes":" no"); printf("\trewritable : %s\n", disc->rewritable ?"yes":" no"); printf("\tmount raineer : %s\n", disc->mrw ?"yes":" no"); printf("\tpacket writing : %s\n", disc->packet ?"yes":" no"); printf("\tstrict overwrite : %s\n", disc->strict_overwrite ?"yes":" no"); printf("\tblocking number : %d\n", disc->blockingnr); printf("\tdisc state : %s\n", print_disc_state(disc->disc_state)); printf("\tlast session state : %s\n", print_session_state(disc->last_session_state)); printf("\tsectorsize : %d\n", disc->sector_size); printf("\tNumber of sessions %d\n", disc->num_sessions); for (session = 0; session < disc->num_sessions; session++) { printf("\tSession %d\n", session); printf("\t\tstart at %u\n", (uint32_t) disc->session_start[session]); printf("\t\tends at %u\n", (uint32_t) disc->session_end[session]); printf("\t\tlength for %u\n", (uint32_t) (disc->session_end[session] - disc->session_start[session])); printf("\t\tnext writable at %u\n", disc->next_writable[session]); printf("\t\tfree blocks %u\n", disc->free_blocks[session]); printf("\t\tpacket size %u\n", disc->packet_size[session]); printf("\n"); } } /* end of udf_verbose.c */ UDFclient.0.8.8/config.h.in010064400001470000000000000000251307041400500146750ustar reinoudwheel#define @HAVE_SCSI@ UDFclient.0.8.8/hash.h010064400001470000000000000063121307041400500137530ustar reinoudwheel/* $NetBSD: hash.h,v 1.6 2008/04/28 20:24:10 martin Exp $ */ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Luke Mewburn. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SYS_HASH_H_ #define _SYS_HASH_H_ #include #ifdef __HAVE_MACHINE_HASH_H #include #endif #ifndef __HAVE_HASH32_BUF /* not overridden by MD hash */ #define HASH32_BUF_INIT 5381 /* * uint32_t * hash32_buf(const void *bf, size_t len, uint32_t hash) * return a 32 bit hash of the binary buffer buf (size len), * seeded with an initial hash value of hash (usually HASH32_BUF_INIT). */ static __inline uint32_t hash32_buf(const void *bf, size_t len, uint32_t hash) { const uint8_t *s = bf; while (len-- != 0) /* "nemesi": k=257, r=r*257 */ hash = hash * 257 + *s++; return (hash * 257); } #endif /* __HAVE_HASH32_BUF */ #ifndef __HAVE_HASH32_STR /* not overridden by MD hash */ #define HASH32_STR_INIT 5381 /* * uint32_t * hash32_str(const void *bf, uint32_t hash) * return a 32 bit hash of NUL terminated ASCII string buf, * seeded with an initial hash value of hash (usually HASH32_STR_INIT). */ static __inline uint32_t hash32_str(const void *bf, uint32_t hash) { const uint8_t *s = bf; uint8_t c; while ((c = *s++) != 0) hash = hash * 33 + c; /* "perl": k=33, r=r+r/32 */ return (hash + (hash >> 5)); } /* * uint32_t * hash32_strn(const void *bf, size_t len, uint32_t hash) * return a 32 bit hash of NUL terminated ASCII string buf up to * a maximum of len bytes, * seeded with an initial hash value of hash (usually HASH32_STR_INIT). */ static __inline uint32_t hash32_strn(const void *bf, size_t len, uint32_t hash) { const uint8_t *s = bf; uint8_t c; while ((c = *s++) != 0 && len-- != 0) hash = hash * 33 + c; /* "perl": k=33, r=r+r/32 */ return (hash + (hash >> 5)); } #endif /* __HAVE_HASH32_STR */ #endif /* !_SYS_HASH_H_ */ UDFclient.0.8.8/newfs_udf.8010044400001470000000000000123501307041400500147250ustar reinoudwheel.\" $NetBSD: newfs_udf.8,v 1.18 2013/08/06 12:15:20 wiz Exp $ .\" .\" Copyright (c) 2008 Reinoud Zandijk .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" .Dd August 2, 2013 .Dt NEWFS_UDF 8 .Os .Sh NAME .Nm newfs_udf .Nd construct a new UDF file system .Sh SYNOPSIS .Nm .Op Fl cFM .Op Fl B Ar blockingsize .Op Fl L Ar loglabel .Op Fl P Ar discid .Op Fl p Ar percentage .Op Fl S Ar sectorsize .Op Fl s Ar size .Op Fl t Ar gmtoff .Op Fl V Ar max_udf .Op Fl v Ar min_udf .Ar special .Sh DESCRIPTION The .Nm utility creates an UDF file system on device .Ar special suitable for the media currently inserted. .Pp The options are as follow: .Bl -tag -width indent .It Fl B Ar blockingsize When creating image files, specify the blocking size or packetsize of the media to .Ar blockingsize . .It Fl c Perform a crude surface check first to weed out disc faults on rewritable media. .It Fl F Force file system construction on non-empty recordable media or create an image file. .It Fl L Ar loglabel Set the disc logical label to the specified .Ar loglabel . .It Fl M Disable metadata partition creation when selected UDF version or media dictates this. For strict conformance and interchange, don't disable this unless its causing problems. .It Fl P Ar discid Set the physical disc label to the specified .Ar discid . .Pp Prepend .Ar discid with volsetname separated with a ':' if wanted. For strict conformance and interchange, don't set this manually unless it has a unique hex number in the first 8 character positions. .It Fl p Ar percentage Percentage of partition to be initially reserved for metadata on the Metadata partition. It defaults to 20 %. .It Fl S Ar sectorsize Set the sectorsize for image files. For strict conformance and interchange, don't set this manually. .It Fl s Ar size For image files, set the file size to the humanized size .Ar size . .It Fl t Ar gmtoff Use the specified .Ar gmtoff as gmt time offset for recording times on the disc. .It Fl V Ar max_udf Select .Ar max_udf as the maximum UDF version to be supported. For UDF version 2.50, use .Dq 0x250 or .Dq 2.50 . .It Fl v Ar min_udf Select .Ar min_udf as the minimum UDF version to be supported. For UDF version 2.01, use .Dq 0x201 or .Dq 2.01 . .El .Sh NOTES The UDF file system is defined for the entire optical medium. It can only function on the entire CD/DVD/BD so the raw partition has to be specified for read/write actions. For .Nm this means specifying the raw device with the raw partition, i.e. .Pa /dev/rcd0d or .Pa /dev/rcd0c . .Pp Some rewritable optical media needs to be formatted first before it can be used by UDF. This can be done using .Xr mmcformat 8 . .Pp The default UDF version is version 2.01. .Sh EXAMPLES Create a file system, using the specified names on the device .Pa /dev/rcd0d with the default UDF version : .Bd -literal -offset indent newfs_udf -P "Encyclopedia:copy-nr-1" -L "volume 2" /dev/rcd0d .Ed .Pp Create a 4.8 GiB sparse file and configure it using .Xr vnconfig 8 to be a 2048 sector size disc and create a new UDF file system on .Pa /dev/rvnd0d : .Bd -literal -offset indent dd if=/dev/zero of=bigdisk.2048.udf seek=9999999 count=1 vnconfig -c vnd0 bigdisk.2048.udf 2048/1/1/1 newfs_udf -L bigdisk /dev/rvnd0d .Ed .Pp Create a 2 GiB file and create a new UDF file system on it using the default 512 byte sector size : .Bd -literal -offset indent newfs_udf -L bigdisk2 -F -s 2G bigdisk2.iso .Ed .Pp Create a 200 MiB file and create a new UDF file system on it using a sector size of 2048 : .Bd -literal -offset indent newfs_udf -L bigdisk2 -F -s 200M -S 2048 bigdisk3.iso .Ed .Pp Create a new UDF file system on the inserted USB stick using its native sectorsize of 512 : .Bd -literal -offset indent newfs_udf -L "My USB stick" /dev/rsd0d .Ed .Sh SEE ALSO .Xr disktab 5 , .Xr disklabel 8 , .Xr mmcformat 8 , .Xr newfs 8 .Sh HISTORY The .Nm command first appeared in .Nx 5.0 . .Sh AUTHORS .An Reinoud Zandijk Aq Mt reinoud@NetBSD.org .Sh BUGS The .Ar P and the .Ar S arguments have changed meaning. The meaning of .Ar S has been merged into .Ar P since .Nx 6.1 . UDFclient.0.8.8/mmc_format.8010044400001470000000000000076561307041400500151060ustar reinoudwheel.\" $NetBSD: mmcformat.8,v 1.6 2014/03/18 18:20:47 riastradh Exp $ .\" .\" Copyright (c) 2008 Reinoud Zandijk .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS .\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE .\" GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" .Dd May 9, 2008 .Dt MMCFORMAT 8 .Os .Sh NAME .Nm mmc_format .Nd format optical media .Sh SYNOPSIS .Nm .Op Fl BDFGHhIMOpRrSsw .Op Fl b Ar blockingnr .Op Fl c Ar cert-num .\" .Op X format is not implemented yet .Ar special .Sh DESCRIPTION The .Nm utility formats optical media conforming to the MMC standard. This includes CD, DVD, and Blu-Ray (BD) media. .Pp The options are as follows: .Bl -tag -width XbXblockingnrXX .It Fl B Blank media when possible before formatting it. .It Fl b Ar blockingnr Explicitly select packet size in sectors .Pq for CD-RW only . It is not recommended to change this from its default of 32. .It Fl c Ar cert-num Certify media for DVD-RAM / DV-RE. The argument cert-num specifies: .Bl -tag -offset indent .It 0 no certification .It 1 full certification .It 2 quick certification .El .It Fl D Debug mode. Print all SCSI/ATAPI command errors. .It Fl F Format media. .It Fl G Grow last CD-RW/DVD-RW session. .It Fl H Show help and print formatting choices for the inserted media. .It Fl h Show help and print formatting choices for the inserted media. .It Fl I Show help and print formatting choices for the inserted media. .It Fl M Select MRW (Mount Rainier) error correcting background format. .It Fl O Old style CD-RW formatting; recommended for CD-RW. .It Fl p Explicitly set packet format. .It Fl R Restart previously stopped MCD-MRW or DVD+RW background format. .It Fl r Recompile defect list for DVD-RAM. .It Fl S Grow spare space DVD-RAM / BD-RE. .It Fl s Format DVD+MRW / BD-RE with extra spare space. .It Fl w Wait until completion of background format. .El .Sh NOTES Due to the enormous varieties in optical media, .Nm is made as generic as possible. This can result in confusion. .Sh EXAMPLES .Dl Ic mmc_format -B -O /dev/rcd0d .Pp Blanks and then formats a CD-RW disc using the .Dq old style format command. It is recommended to use this .Dq old style command unless your drive reports that it's not supported; in that case, resort to the default .Fl F . Note that a CD-RW disc can be reformatted without being blanked. Blanking switches between sequential and fixed packet writing by erasing the disc. This can also help to revive old discs. .Pp .Dl Ic mmc_format -F -M /dev/rcd0d .Pp Format a CD-RW or a DVD+RW to use MRW (Mount Rainier). This format tries to hide media flaws as much as possible by relocation. .Sh SEE ALSO .Xr scsictl 8 .Sh HISTORY The .Nm command first appeared in .Nx 5.0 . .Sh AUTHORS .An Reinoud Zandijk Aq Mt reinoud@NetBSD.org .Sh BUGS .Nm could be merged with .Xr scsictl 8 but that tool is very hard disk oriented. UDFclient.0.8.8/Makefile010066400001470000000000000047051307042673100143360ustar reinoudwheel# # UDFclient toolkit # # Copyright 2003,2004,2005 Reinoud P.Zandijk # # # File $Id: Makefile.in,v 1.24 2017/01/10 09:52:30 reinoud Exp $ $Name: $ # srcdir= . prefix= /usr/local exec_prefix= ${prefix} sbindir= ${exec_prefix}/sbin mandir= ${datarootdir}/man bindir= ${exec_prefix}/bin datarootdir= ${prefix}/share CC= clang LD= $(CC) CPPFLAGS= -DNO_DIRENT_NAMLEN -DSCSI -DUSCSI_SCSIPI -DPACKAGE_NAME=\"udfclient\" -DPACKAGE_TARNAME=\"udfclient\" -DPACKAGE_VERSION=\"0.8.8\" -DPACKAGE_STRING=\"udfclient\ 0.8.8\" -DPACKAGE_BUGREPORT=\"reinoud@NetBSD.org\" -DPACKAGE_URL=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_SYS_ENDIAN_H=1 -DHAVE_MACHINE_ENDIAN_H=1 -DHAVE_MACHINE_BSWAP_H=1 -DHAVE_SYS_BSWAP_H=1 -DHAVE_MACHINE_INT_FMTIO_H=1 -DHAVE_STRUCT_STAT_ST_ATIMESPEC=1 -DHAVE_STRUCT_STAT_ST_BIRTHTIMESPEC=1 -DHAVE_DEV_SCSIPI_SCSIPI_ALL_H=1 -I$(srcdir) CFLAGS= -g -O2 LDFLAGS= INSTALL= /usr/bin/install -c # NetBSD #CFLAGS+= -Wall \ # -Wuninitialized \ # -fno-strict-aliasing \ # -Wextra -Werror # -Werror ${COPTS} \ # -DNDEBUG # Anonymising this client (for comformity) #CFLAGS+= -D__ANONYMOUSUDF__ #CFLAGS+= -fPIC -DPIC POSTOBJ+= -lpthread -lc # For use with the cpuflags package #CPROCFLAGS != cpuflags CFLAGS+= ${CPROCFLAGS} # Main programs APPS= udfdump udfclient newfs_udf cd_sessions SCSI_APPS= cd_disect mmc_format LIB= osta.o udf.o udf_bmap.o udf_allocentries.o udf_discop.o uio.o LIB+= udf_verbose.o udf_readwrite.o udf_unix.o vfs_dirhash.o USCSILIB= uscsi_sense.o uscsi_subr.o CFLAGS+= -DNEEDS_ISPRINT $(CPPFLAGS) all: $(APPS) $(SCSI_APPS) install: $(APPS) $(SCSI_APPS) $(INSTALL) -d $(DESTDIR)/$(bindir) for app in $(APPS) $(SCSI_APPS); do \ echo "$(INSTALL) $$app $(DESTDIR)/$(bindir)/$$app"; \ $(INSTALL) $$app $(DESTDIR)/$(bindir)/$$app; \ done depend: mkdep $(CFLAGS) *.c clean: rm -f *.o *.a *.core core.* core .depend *~ *.bak $(APPS) $(SCSI_APPS) rm -fr autom*.cache config.log config.status configure.lineno cleandir: clean rm -f Makefile libuscsi.a: $(USCSILIB) ar -rsc libuscsi.a $(USCSILIB) libudf.a: $(LIB) ar -rsc libudf.a $(LIB) $(SCSI_APPS): $(.TARGET).o libuscsi.a $(LD) -o $(.TARGET) $(LDFLAGS) $(.TARGET).o libuscsi.a $(POSTOBJ) $(APPS): $(.TARGET).o libuscsi.a libudf.a $(LD) -o $(.TARGET) $(LDFLAGS) $(.TARGET).o libudf.a libuscsi.a $(POSTOBJ) # DO NOT DELETE