diff options
Diffstat (limited to 'kioslave')
26 files changed, 3374 insertions, 1 deletions
diff --git a/kioslave/Makefile.am b/kioslave/Makefile.am index 42f294e76..e6472a9c8 100644 --- a/kioslave/Makefile.am +++ b/kioslave/Makefile.am @@ -20,7 +20,7 @@ if include_bzip2 BZIP2DIR=bzip2 endif -SUBDIRS = file http ftp gzip $(BZIP2DIR) metainfo +SUBDIRS = file http ftp gzip $(BZIP2DIR) metainfo iso messages: # they get into kio.pot diff --git a/kioslave/iso/Makefile.am b/kioslave/iso/Makefile.am new file mode 100644 index 000000000..8151bec5c --- /dev/null +++ b/kioslave/iso/Makefile.am @@ -0,0 +1,67 @@ +kde_module_LTLIBRARIES = kio_iso.la + + +INCLUDES = $(all_includes) + + +#LDFLAGS = + +kio_iso_la_METASOURCES=AUTO + +kio_iso_la_SOURCES = kisodirectory.cpp kisofile.cpp qfilehack.cpp kiso.cpp iso.cpp +kio_iso_la_LIBADD = libisofs/libisofs.la $(LIB_QT) $(LIB_KDECORE) $(LIB_KIO) + +kio_iso_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) + + +SUBDIRS = libisofs + +noinst_HEADERS = iso.h kiso.h qfilehack.h kisofile.h kisodirectory.h +EXTRA_DIST = iso.protocol isoservice.desktop kio_iso.desktop + +install-data-local: + $(mkinstalldirs) $(DESTDIR)$(kde_servicesdir)/ + $(INSTALL_DATA) $(srcdir)/iso.protocol $(DESTDIR)$(kde_servicesdir)/iso.protocol + $(mkinstalldirs) $(DESTDIR)$(kde_datadir)/konqueror/servicemenus/ + $(INSTALL_DATA) $(srcdir)/isoservice.desktop $(DESTDIR)$(kde_datadir)/konqueror/servicemenus/isoservice.desktop + $(mkinstalldirs) $(DESTDIR)$(kde_confdir)/ + $(INSTALL_DATA) $(srcdir)/kio_isorc $(DESTDIR)$(kde_confdir)/kio_isorc + $(mkinstalldirs) $(DESTDIR)$(kde_appsdir)/ + $(INSTALL_DATA) $(srcdir)/kio_iso.desktop $(DESTDIR)$(kde_appsdir)/kio_iso.desktop + +uninstall-local: + -rm -f $(DESTDIR)$(kde_servicesdir)/iso.protocol + -rm -f $(DESTDIR)$(kde_datadir)/konqueror/servicemenus/isoservice.desktop + -rm -f $(DESTDIR)$(kde_confdir)/kio_isorc + -rm -f $(DESTDIR)$(kde_appsdir)/kio_iso.desktop + +# These paths are KDE specific. Use them: +# kde_appsdir Where your application's menu entry (.desktop) should go to. +# kde_icondir Where your icon should go to - better use KDE_ICON. +# kde_sounddir Where your sounds should go to. +# kde_htmldir Where your docs should go to. (contains lang subdirs) +# kde_datadir Where you install application data. (Use a subdir) +# kde_locale Where translation files should go to. (contains lang subdirs) +# kde_cgidir Where cgi-bin executables should go to. +# kde_confdir Where config files should go to (system-wide ones with default values). +# kde_mimedir Where mimetypes .desktop files should go to. +# kde_servicesdir Where services .desktop files should go to. +# kde_servicetypesdir Where servicetypes .desktop files should go to. +# kde_toolbardir Where general toolbar icons should go to (deprecated, use KDE_ICON). +# kde_wallpaperdir Where general wallpapers should go to. +# kde_templatesdir Where templates for the "New" menu (Konqueror/KDesktop) should go to. +# kde_bindir Where executables should go to. Use bin_PROGRAMS or bin_SCRIPTS. +# kde_libdir Where shared libraries should go to. Use lib_LTLIBRARIES. +# kde_moduledir Where modules (e.g. parts) should go to. Use kde_module_LTLIBRARIES. +# kde_styledir Where Qt/KDE widget styles should go to (new in KDE 3). +# kde_designerdir Where Qt Designer plugins should go to (new in KDE 3). + + +# make messages.po. Move this one to ../po/ and "make merge" in po +# the -x is for skipping messages already translated in kdelibs +messages: + LIST=`find . -name \*.h -o -name \*.hh -o -name \*.H -o -name \*.hxx -o -name \*.hpp -o -name \*.cpp -o -name \*.cc -o -name \*.cxx -o -name \*.ecpp -o -name \*.C`; \ + if test -n "$$LIST"; then \ + $(XGETTEXT) -C -ki18n -x $(kde_includes)/kde.pot $$LIST -o ../po/iso.pot; \ + fi + diff --git a/kioslave/iso/iso.cpp b/kioslave/iso/iso.cpp new file mode 100644 index 000000000..8b7ebe66a --- /dev/null +++ b/kioslave/iso/iso.cpp @@ -0,0 +1,525 @@ +/*************************************************************************** + iso.cpp + ------------------- + begin : Oct 25 2002 + copyright : (C) 2002 by Szombathelyi Gy�gy + email : gyurco@users.sourceforge.net + ***************************************************************************/ + +/*************************************************************************** + * * + * This program 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 file is heavily based on tar.cc from kdebase + * (c) David Faure <faure@kde.org> + */ + +#include <zlib.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <unistd.h> + +#include <klargefile.h> +#include <qfile.h> +#include <kurl.h> +#include <kdebug.h> +#include <kinstance.h> +#include <kiso.h> +#include <kmimemagic.h> + +#include <errno.h> // to be removed + +#include "libisofs/iso_fs.h" + +#include "kisofile.h" +#include "kisodirectory.h" +#include "iso.h" + +typedef struct { + char magic[8]; + char uncompressed_len[4]; + unsigned char header_size; + unsigned char block_size; + char reserved[2]; /* Reserved for future use, MBZ */ +} compressed_file_header; + +static const unsigned char zisofs_magic[8] = { + 0x37, 0xE4, 0x53, 0x96, 0xC9, 0xDB, 0xD6, 0x07 +}; + +using namespace KIO; + +extern "C" { int kdemain(int argc, char **argv); } + +int kdemain( int argc, char **argv ) +{ + KInstance instance( "kio_iso" ); + + kdDebug() << "Starting " << getpid() << endl; + + if (argc != 4) + { + fprintf(stderr, "Usage: kio_iso protocol domain-socket1 domain-socket2\n"); + exit(-1); + } + + kio_isoProtocol slave(argv[2], argv[3]); + slave.dispatchLoop(); + + kdDebug() << "Done" << endl; + return 0; +} + + +kio_isoProtocol::kio_isoProtocol( const QCString &pool, const QCString &app ) : SlaveBase( "iso", pool, app ) +{ + kdDebug() << "kio_isoProtocol::kio_isoProtocol" << endl; + m_isoFile = 0L; +} + +kio_isoProtocol::~kio_isoProtocol() +{ + delete m_isoFile; +} + +bool kio_isoProtocol::checkNewFile( QString fullPath, QString & path, int startsec ) +{ + kdDebug() << "kio_isoProtocol::checkNewFile " << fullPath << " startsec: " << + startsec << endl; + + // Are we already looking at that file ? + if ( m_isoFile && startsec == m_isoFile->startSec() && + m_isoFile->fileName() == fullPath.left(m_isoFile->fileName().length()) ) + { + // Has it changed ? + struct stat statbuf; + if ( ::stat( QFile::encodeName( m_isoFile->fileName() ), &statbuf ) == 0 ) + { + if ( m_mtime == statbuf.st_mtime ) + { + path = fullPath.mid( m_isoFile->fileName().length() ); + kdDebug() << "kio_isoProtocol::checkNewFile returning " << path << endl; + return true; + } + } + } + kdDebug() << "Need to open a new file" << endl; + + // Close previous file + if ( m_isoFile ) + { + m_isoFile->close(); + delete m_isoFile; + m_isoFile = 0L; + } + + // Find where the iso file is in the full path + int pos = 0; + QString isoFile; + path = QString::null; + + int len = fullPath.length(); + if ( len != 0 && fullPath[ len - 1 ] != '/' ) + fullPath += '/'; + + kdDebug() << "the full path is " << fullPath << endl; + while ( (pos=fullPath.find( '/', pos+1 )) != -1 ) + { + QString tryPath = fullPath.left( pos ); + kdDebug() << fullPath << " trying " << tryPath << endl; + + KDE_struct_stat statbuf; + if ( KDE_lstat( QFile::encodeName(tryPath), &statbuf ) == 0 && !S_ISDIR(statbuf.st_mode) ) + { + isoFile = tryPath; + m_mtime = statbuf.st_mtime; + m_mode = statbuf.st_mode; + path = fullPath.mid( pos + 1 ); + kdDebug() << "fullPath=" << fullPath << " path=" << path << endl; + len = path.length(); + if ( len > 1 ) + { + if ( path[ len - 1 ] == '/' ) + path.truncate( len - 1 ); + } + else + path = QString::fromLatin1("/"); + kdDebug() << "Found. isoFile=" << isoFile << " path=" << path << endl; + break; + } + } + if ( isoFile.isEmpty() ) + { + kdDebug() << "kio_isoProtocol::checkNewFile: not found" << endl; + return false; + } + + // Open new file + kdDebug() << "Opening KIso on " << isoFile << endl; + m_isoFile = new KIso( isoFile ); + m_isoFile->setStartSec(startsec); + if ( !m_isoFile->open( IO_ReadOnly ) ) + { + kdDebug() << "Opening " << isoFile << " failed." << endl; + delete m_isoFile; + m_isoFile = 0L; + return false; + } + + return true; +} + + +void kio_isoProtocol::createUDSEntry( const KArchiveEntry * isoEntry, UDSEntry & entry ) +{ + UDSAtom atom; + + entry.clear(); + atom.m_uds = UDS_NAME; + atom.m_str = isoEntry->name(); + entry.append(atom); + + atom.m_uds = UDS_FILE_TYPE; + atom.m_long = isoEntry->permissions() & S_IFMT; // keep file type only + entry.append( atom ); + + atom.m_uds = UDS_ACCESS; + atom.m_long = isoEntry->permissions() & 07777; // keep permissions only + entry.append( atom ); + + atom.m_uds = UDS_SIZE; + if (isoEntry->isFile()) { + atom.m_long = ((KIsoFile *)isoEntry)->realsize(); + if (!atom.m_long) atom.m_long = ((KIsoFile *)isoEntry)->size(); + } else { + atom.m_long = 0L; + } + entry.append( atom ); + + atom.m_uds = UDS_USER; + atom.m_str = isoEntry->user(); + entry.append( atom ); + + atom.m_uds = UDS_GROUP; + atom.m_str = isoEntry->group(); + entry.append( atom ); + + atom.m_uds = UDS_MODIFICATION_TIME; + atom.m_long = isoEntry->date(); + entry.append( atom ); + + atom.m_uds = UDS_ACCESS_TIME; + atom.m_long = isoEntry->isFile() ? ((KIsoFile *)isoEntry)->adate() : + ((KIsoDirectory *)isoEntry)->adate(); + entry.append( atom ); + + atom.m_uds = UDS_CREATION_TIME; + atom.m_long = isoEntry->isFile() ? ((KIsoFile *)isoEntry)->cdate() : + ((KIsoDirectory *)isoEntry)->cdate(); + entry.append( atom ); + + atom.m_uds = UDS_LINK_DEST; + atom.m_str = isoEntry->symlink(); + entry.append( atom ); +} + +void kio_isoProtocol::listDir( const KURL & url ) +{ + kdDebug() << "kio_isoProtocol::listDir " << url.url() << endl; + + QString path; + if ( !checkNewFile( url.path(), path, url.hasRef() ? url.htmlRef().toInt() : -1 ) ) + { + QCString _path( QFile::encodeName(url.path())); + kdDebug() << "Checking (stat) on " << _path << endl; + struct stat buff; + if ( ::stat( _path.data(), &buff ) == -1 || !S_ISDIR( buff.st_mode ) ) { + error( KIO::ERR_DOES_NOT_EXIST, url.path() ); + return; + } + // It's a real dir -> redirect + KURL redir; + redir.setPath( url.path() ); + if (url.hasRef()) redir.setRef(url.htmlRef()); + kdDebug() << "Ok, redirection to " << redir.url() << endl; + redirection( redir ); + finished(); + // And let go of the iso file - for people who want to unmount a cdrom after that + delete m_isoFile; + m_isoFile = 0L; + return; + } + + if ( path.isEmpty() ) + { + KURL redir( QString::fromLatin1( "iso:/") ); + kdDebug() << "url.path()==" << url.path() << endl; + if (url.hasRef()) redir.setRef(url.htmlRef()); + redir.setPath( url.path() + QString::fromLatin1("/") ); + kdDebug() << "kio_isoProtocol::listDir: redirection " << redir.url() << endl; + redirection( redir ); + finished(); + return; + } + + kdDebug() << "checkNewFile done" << endl; + const KArchiveDirectory* root = m_isoFile->directory(); + const KArchiveDirectory* dir; + if (!path.isEmpty() && path != "/") + { + kdDebug() << QString("Looking for entry %1").arg(path) << endl; + const KArchiveEntry* e = root->entry( path ); + if ( !e ) + { + error( KIO::ERR_DOES_NOT_EXIST, path ); + return; + } + if ( ! e->isDirectory() ) + { + error( KIO::ERR_IS_FILE, path ); + return; + } + dir = (KArchiveDirectory*)e; + } else { + dir = root; + } + + QStringList l = dir->entries(); + totalSize( l.count() ); + + UDSEntry entry; + QStringList::Iterator it = l.begin(); + for( ; it != l.end(); ++it ) + { + kdDebug() << (*it) << endl; + const KArchiveEntry* isoEntry = dir->entry( (*it) ); + + createUDSEntry( isoEntry, entry ); + + listEntry( entry, false ); + } + + listEntry( entry, true ); // ready + + finished(); + + kdDebug() << "kio_isoProtocol::listDir done" << endl; +} + +void kio_isoProtocol::stat( const KURL & url ) +{ + QString path; + UDSEntry entry; + + kdDebug() << "kio_isoProtocol::stat " << url.url() << endl; + if ( !checkNewFile( url.path(), path, url.hasRef() ? url.htmlRef().toInt() : -1 ) ) + { + // We may be looking at a real directory - this happens + // when pressing up after being in the root of an archive + QCString _path( QFile::encodeName(url.path())); + kdDebug() << "kio_isoProtocol::stat (stat) on " << _path << endl; + struct stat buff; + if ( ::stat( _path.data(), &buff ) == -1 || !S_ISDIR( buff.st_mode ) ) { + kdDebug() << "isdir=" << S_ISDIR( buff.st_mode ) << " errno=" << strerror(errno) << endl; + error( KIO::ERR_DOES_NOT_EXIST, url.path() ); + return; + } + // Real directory. Return just enough information for KRun to work + UDSAtom atom; + atom.m_uds = KIO::UDS_NAME; + atom.m_str = url.fileName(); + entry.append( atom ); + kdDebug() << "kio_isoProtocol::stat returning name=" << url.fileName() << endl; + + atom.m_uds = KIO::UDS_FILE_TYPE; + atom.m_long = buff.st_mode & S_IFMT; + entry.append( atom ); + + statEntry( entry ); + + finished(); + + // And let go of the iso file - for people who want to unmount a cdrom after that + delete m_isoFile; + m_isoFile = 0L; + return; + } + + const KArchiveDirectory* root = m_isoFile->directory(); + const KArchiveEntry* isoEntry; + if ( path.isEmpty() ) + { + path = QString::fromLatin1( "/" ); + isoEntry = root; + } else { + isoEntry = root->entry( path ); + } + if ( !isoEntry ) + { + error( KIO::ERR_DOES_NOT_EXIST, path ); + return; + } + createUDSEntry( isoEntry, entry ); + statEntry( entry ); + finished(); +} + +void kio_isoProtocol::getFile( const KIsoFile *isoFileEntry, const QString &path ) +{ + unsigned long long size, pos = 0; + bool mime=false,zlib=false; + QByteArray fileData, pointer_block, inbuf, outbuf; + char *pptr = 0; + compressed_file_header *hdr; + int block_shift; + unsigned long nblocks; + unsigned long fullsize = 0, block_size = 0, block_size2 = 0; + size_t ptrblock_bytes; + unsigned long cstart, cend, csize; + uLong bytes; + + size = isoFileEntry->realsize(); + if (size >= sizeof(sizeof(compressed_file_header))) zlib=true; + if (!size) size = isoFileEntry->size(); + totalSize( size ); + if (!size) mimeType("application/x-zerosize"); + + if (size && !m_isoFile->device()->isOpen()) m_isoFile->device()->open(IO_ReadOnly); + + if (zlib) { + fileData=isoFileEntry->data(0, sizeof(compressed_file_header)); + if ( fileData.size() == sizeof(compressed_file_header) && + !memcmp(fileData.data(), zisofs_magic, sizeof (zisofs_magic)) ) { + + hdr=(compressed_file_header*) fileData.data(); + block_shift = hdr->block_size; + block_size = 1UL << block_shift; + block_size2 = block_size << 1; + fullsize = isonum_731(hdr->uncompressed_len); + nblocks = (fullsize + block_size - 1) >> block_shift; + ptrblock_bytes = (nblocks+1) * 4; + pointer_block=isoFileEntry->data( hdr->header_size << 2, ptrblock_bytes ); + if (pointer_block.size() == ptrblock_bytes && + inbuf.resize(block_size2) && + outbuf.resize(block_size)) { + + pptr = pointer_block.data(); + } else { + error(KIO::ERR_COULD_NOT_READ, path); + return; + } + } else { + zlib=false; + } + } + + while (pos<size) { + if (zlib) { + cstart = isonum_731(pptr); + pptr += 4; + cend = isonum_731(pptr); + + csize = cend-cstart; + + if ( csize == 0 ) { + outbuf.fill(0, -1); + } else { + if ( csize > block_size2 ) { + //err = EX_DATAERR; + break; + } + + inbuf=isoFileEntry->data(cstart, csize); + if (inbuf.size() != csize) { + break; + } + + bytes = block_size; // Max output buffer size + if ( (uncompress((Bytef*) outbuf.data(), &bytes, (Bytef*) inbuf.data(), csize)) != Z_OK ) { + break; + } + } + + if ( ((fullsize > block_size) && (bytes != block_size)) + || ((fullsize <= block_size) && (bytes < fullsize)) ) { + + break; + } + + if ( bytes > fullsize ) + bytes = fullsize; + fileData.assign(outbuf); + fileData.resize(bytes); + fullsize -= bytes; + } else { + fileData=isoFileEntry->data(pos,65536); + if (fileData.size()==0) break; + } + if (!mime) { + KMimeMagicResult * result = KMimeMagic::self()->findBufferFileType( fileData, path ); + kdDebug() << "Emitting mimetype " << result->mimeType() << endl; + mimeType( result->mimeType() ); + mime=true; + } + data(fileData); + pos+=fileData.size(); + processedSize(pos); + } + + if (pos!=size) { + error(KIO::ERR_COULD_NOT_READ, path); + return; + } + + fileData.resize(0); + data(fileData); + processedSize(pos); + finished(); + +} + +void kio_isoProtocol::get( const KURL & url ) +{ + kdDebug() << "kio_isoProtocol::get" << url.url() << endl; + + QString path; + if ( !checkNewFile( url.path(), path, url.hasRef() ? url.htmlRef().toInt() : -1 ) ) + { + error( KIO::ERR_DOES_NOT_EXIST, url.path() ); + return; + } + + const KArchiveDirectory* root = m_isoFile->directory(); + const KArchiveEntry* isoEntry = root->entry( path ); + + if ( !isoEntry ) + { + error( KIO::ERR_DOES_NOT_EXIST, path ); + return; + } + if ( isoEntry->isDirectory() ) + { + error( KIO::ERR_IS_DIRECTORY, path ); + return; + } + + const KIsoFile* isoFileEntry = static_cast<const KIsoFile *>(isoEntry); + if ( !isoEntry->symlink().isEmpty() ) + { + kdDebug() << "Redirection to " << isoEntry->symlink() << endl; + KURL realURL( url, isoEntry->symlink() ); + kdDebug() << "realURL= " << realURL.url() << endl; + redirection( realURL.url() ); + finished(); + return; + } + getFile(isoFileEntry, path); + if (m_isoFile->device()->isOpen()) m_isoFile->device()->close(); +} diff --git a/kioslave/iso/iso.h b/kioslave/iso/iso.h new file mode 100644 index 000000000..079f68e6a --- /dev/null +++ b/kioslave/iso/iso.h @@ -0,0 +1,51 @@ +/*************************************************************************** + iso.h + ------------------- + begin : Oct 25 2002 + copyright : (C) 2002 by Szombathelyi György + email : gyurco@users.sourceforge.net + ***************************************************************************/ + +/*************************************************************************** + * * + * This program 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 file is heavily based on tar.h from kdebase + * (c) David Faure <faure@kde.org> + */ + +#ifndef _ISO_H +#define _ISO_H + +#include <kio/slavebase.h> +#include <sys/types.h> +#include "kisofile.h" + +class KIso; + +class kio_isoProtocol : public KIO::SlaveBase +{ +public: + kio_isoProtocol( const QCString &pool, const QCString &app ); + virtual ~kio_isoProtocol(); + + virtual void listDir( const KURL & url ); + virtual void stat( const KURL & url ); + virtual void get( const KURL & url ); + +protected: + void getFile( const KIsoFile *isoFileEntry, const QString &path ); + void createUDSEntry( const KArchiveEntry * isoEntry, KIO::UDSEntry & entry ); + bool checkNewFile( QString fullPath, QString & path, int startsec ); + + KIso * m_isoFile; + time_t m_mtime; + int m_mode; +}; + +#endif diff --git a/kioslave/iso/iso.protocol b/kioslave/iso/iso.protocol new file mode 100644 index 000000000..0e7d71b64 --- /dev/null +++ b/kioslave/iso/iso.protocol @@ -0,0 +1,11 @@ +[Protocol] +exec=kio_iso +protocol=iso +listing=Name,Type,Size,Date,AccessDate,CreationDate,Access,Owner,Group,Link +input=filesystem +output=filesystem +reading=true +source=true +Icon=cd +Description=A kioslave for ISO9660 filesystems +MimeType=application/x-iso diff --git a/kioslave/iso/isoservice.desktop b/kioslave/iso/isoservice.desktop new file mode 100644 index 000000000..00093709b --- /dev/null +++ b/kioslave/iso/isoservice.desktop @@ -0,0 +1,14 @@ +[Desktop Entry] +Encoding=UTF-8 +Actions=OpenISO +ServiceTypes=inode/blockdevice,application/x-iso + +[Desktop Action OpenISO] +Comment=ISO9660 View +Comment[hu]=ISO9660 Nézet +Comment[fr]=Lecteur ISO9660 +Icon=cd +Name=ISO9660 View +Name[hu]=ISO9660 Nézet +Name[fr]=Lecteur ISO9660 +Exec=kfmclient exec iso:%f diff --git a/kioslave/iso/kio_iso.desktop b/kioslave/iso/kio_iso.desktop new file mode 100644 index 000000000..658cbf31b --- /dev/null +++ b/kioslave/iso/kio_iso.desktop @@ -0,0 +1,13 @@ +[Desktop Entry] +Type=Application +Exec=konqueror iso:%f +Icon=cd +Terminal=false +MimeType=application/x-iso; +InitialPreference=10 +NoDisplay=true +Name=ISO9660 Image Viewer +Name[hu]=ISO9660 Nézet +Name[fr]=Lecteur ISO9660 +X-DCOP-ServiceType=None +Categories=Qt;KDE;System;
\ No newline at end of file diff --git a/kioslave/iso/kio_isorc b/kioslave/iso/kio_isorc new file mode 100644 index 000000000..3a874172e --- /dev/null +++ b/kioslave/iso/kio_isorc @@ -0,0 +1,2 @@ +showhidden=false +showrr=true diff --git a/kioslave/iso/kiso.cpp b/kioslave/iso/kiso.cpp new file mode 100644 index 000000000..6bc4241fe --- /dev/null +++ b/kioslave/iso/kiso.cpp @@ -0,0 +1,459 @@ +/*************************************************************************** + kiso.cpp + ------------------- + begin : Oct 25 2002 + copyright : (C) 2002 by Szombathelyi Gy�gy + email : gyurco@users.sourceforge.net + ***************************************************************************/ + +/*************************************************************************** + * * + * This program 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 file is heavily based on ktar.cpp from kdelibs (c) David Faure */ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> +#include <grp.h> +#include <pwd.h> +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <qcstring.h> +#include <qdir.h> +#include <qfile.h> +#include <kdebug.h> +#include <kurl.h> +#include <kmimetype.h> +#include <kconfig.h> +#include <kfilterdev.h> +#include <kfilterbase.h> + +#include "kiso.h" +#include "libisofs/isofs.h" +#include "qfilehack.h" + + +#ifdef __linux__ +#undef __STRICT_ANSI__ +#include <linux/cdrom.h> +#define __STRICT_ANSI__ +#include <sys/ioctl.h> +#include <fcntl.h> +#endif + +//////////////////////////////////////////////////////////////////////// +/////////////////////////// KIso /////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +/** + * puts the track layout of the device 'fname' into 'tracks' + * tracks structure: start sector, track number, ... + * tracks should be 100*2 entry long (this is the maximum in the CD-ROM standard) + * currently it's linux only, porters are welcome + */ +static int getTracks(const char *fname,int *tracks) { + int ret=0; + memset(tracks,0,200*sizeof(int)); + +#ifdef __linux__ + int fd,i; + struct cdrom_tochdr tochead; + struct cdrom_tocentry tocentry; + + kdDebug() << "getTracks open:" << fname << endl; + fd=open(fname, O_RDONLY | O_NONBLOCK); + if (fd > 0) { + if (ioctl(fd,CDROMREADTOCHDR,&tochead)!=-1) { + kdDebug() << "getTracks first track:" << tochead.cdth_trk0 + << " last track " << tochead.cdth_trk1 << endl; + for (i=tochead.cdth_trk0;i<=tochead.cdth_trk1;i++) { + if (ret>99) break; + memset(&tocentry,0,sizeof(struct cdrom_tocentry)); + tocentry.cdte_track=i; + tocentry.cdte_format=CDROM_LBA; + if (ioctl(fd,CDROMREADTOCENTRY,&tocentry)<0) break; + kdDebug() << "getTracks got track " << i << " starting at: " << + tocentry.cdte_addr.lba << endl; + if ((tocentry.cdte_ctrl & 0x4) == 0x4) { + tracks[ret<<1]=tocentry.cdte_addr.lba; + tracks[(ret<<1)+1]=i; + ret++; + } + } + } + close(fd); + } + +#endif + + return ret; +} + +class KIso::KIsoPrivate +{ +public: + KIsoPrivate() {} + QStringList dirList; +}; + +KIso::KIso( const QString& filename, const QString & _mimetype ) + : KArchive( 0L ) +{ + m_startsec = -1; + m_filename = filename; + d = new KIsoPrivate; + QString mimetype( _mimetype ); + bool forced = true; + if ( mimetype.isEmpty() ) + { + mimetype = KMimeType::findByFileContent( filename )->name(); + kdDebug() << "KIso::KIso mimetype=" << mimetype << endl; + + // Don't move to prepareDevice - the other constructor theoretically allows ANY filter + if ( mimetype == "application/x-tgz" || mimetype == "application/x-targz" || // the latter is deprecated but might still be around + mimetype == "application/x-webarchive" ) + // that's a gzipped tar file, so ask for gzip filter + mimetype = "application/x-gzip"; + else if ( mimetype == "application/x-tbz" ) // that's a bzipped2 tar file, so ask for bz2 filter + mimetype = "application/x-bzip2"; + else + { + // Something else. Check if it's not really gzip though (e.g. for KOffice docs) + QFile file( filename ); + if ( file.open( IO_ReadOnly ) ) + { + unsigned char firstByte = file.getch(); + unsigned char secondByte = file.getch(); + unsigned char thirdByte = file.getch(); + if ( firstByte == 0037 && secondByte == 0213 ) + mimetype = "application/x-gzip"; + else if ( firstByte == 'B' && secondByte == 'Z' && thirdByte == 'h' ) + mimetype = "application/x-bzip2"; + else if ( firstByte == 'P' && secondByte == 'K' && thirdByte == 3 ) + { + unsigned char fourthByte = file.getch(); + if ( fourthByte == 4 ) + mimetype = "application/x-zip"; + } + } + } + forced = false; + } + + prepareDevice( filename, mimetype, forced ); +} + +void KIso::prepareDevice( const QString & filename, + const QString & mimetype, bool forced ) +{ + /* 'hack' for Qt's false assumption that only S_ISREG is seekable */ + if( "inode/blockdevice" == mimetype ) + setDevice( new QFileHack( filename ) ); + else + { + if( "application/x-gzip" == mimetype + || "application/x-bzip2" == mimetype) + forced = true; + + QIODevice *dev = KFilterDev::deviceForFile( filename, mimetype, forced ); + if( dev ) + setDevice( dev ); + } + +} + +KIso::KIso( QIODevice * dev ) + : KArchive( dev ) +{ + d = new KIsoPrivate; +} + +KIso::~KIso() +{ + // mjarrett: Closes to prevent ~KArchive from aborting w/o device + if( isOpened() ) + close(); + if ( !m_filename.isEmpty() ) + delete device(); // we created it ourselves + delete d; +} + +/* callback function for libisofs */ +static int readf(char *buf, int start, int len,void *udata) { + + QIODevice* dev = ( static_cast<KIso*> (udata) )->device(); + + if (dev->at(start<<11)) { + if ((dev->readBlock(buf, len<<11)) != -1) return (len); + } + kdDebug() << "KIso::ReadRequest failed start: " << start << " len: " << len << endl; + + return -1; +} + +/* callback function for libisofs */ +static int mycallb(struct iso_directory_record *idr,void *udata) { + + KIso *iso = static_cast<KIso*> (udata); + QString path,user,group,symlink; + int i; + int access; + int time,cdate,adate; + rr_entry rr; + bool special=false; + KArchiveEntry *entry=NULL,*oldentry=NULL; + char z_algo[2],z_params[2]; + int z_size=0; + + if ((idr->flags[0] & 1) && !iso->showhidden) return 0; + if (iso->level) { + if (isonum_711(idr->name_len)==1) { + switch (idr->name[0]) { + case 0: + path+=("."); + special=true; + break; + case 1: + path+=(".."); + special=true; + break; + } + } + if (iso->showrr && ParseRR(idr,&rr)>0) { + if (!special) path=rr.name; + symlink=rr.sl; + access=rr.mode; + time=rr.t_mtime; + adate=rr.t_atime; + cdate=rr.t_ctime; + user.setNum(rr.uid); + group.setNum(rr.gid); + z_algo[0]=rr.z_algo[0];z_algo[1]=rr.z_algo[1]; + z_params[0]=rr.z_params[0];z_params[1]=rr.z_params[1]; + z_size=rr.z_size; + } else { + access=iso->dirent->permissions() & ~S_IFMT; + adate=cdate=time=isodate_915(idr->date,0); + user=iso->dirent->user(); + group=iso->dirent->group(); + if (idr->flags[0] & 2) access |= S_IFDIR; else access |= S_IFREG; + if (!special) { + if (iso->joliet) { + for (i=0;i<(isonum_711(idr->name_len)-1);i+=2) { + QChar ch( be2me_16(*((ushort*)&(idr->name[i]))) ); + if (ch==';') break; + path+=ch; + } + } else { + for (i=0;i<isonum_711(idr->name_len);i++) { + if (idr->name[i]==';') break; + if (idr->name[i]) path+=(idr->name[i]); + } + } + if (path.endsWith(".")) path.setLength(path.length()-1); + } + } + if (iso->showrr) FreeRR(&rr); + if (idr->flags[0] & 2) { + entry = new KIsoDirectory( iso, path, access | S_IFDIR, time, adate, cdate, + user, group, symlink ); + } else { + entry = new KIsoFile( iso, path, access, time, adate, cdate, + user, group, symlink, isonum_733(idr->extent)<<11,isonum_733(idr->size) ); + if (z_size) (static_cast <KIsoFile*> (entry))->setZF(z_algo,z_params,z_size); + + } + iso->dirent->addEntry(entry); + } + if ( (idr->flags[0] & 2) && (iso->level==0 || !special) ) { + if (iso->level) { + oldentry=iso->dirent; + iso->dirent=static_cast<KIsoDirectory*> (entry); + } + iso->level++; + ProcessDir(&readf,isonum_733(idr->extent),isonum_733(idr->size),&mycallb,udata); + iso->level--; + if (iso->level) iso->dirent=static_cast<KIsoDirectory*> (oldentry); + } + return 0; +} + +void KIso::addBoot(struct el_torito_boot_descriptor* bootdesc) { + + int i,size; + boot_head boot; + boot_entry *be; + QString path; + KIsoFile *entry; + + entry=new KIsoFile( this, "Catalog", dirent->permissions() & ~S_IFDIR, + dirent->date(), dirent->adate(), dirent->cdate(), + dirent->user(), dirent->group(), QString::null, + isonum_731(bootdesc->boot_catalog)<<11, 2048 ); + dirent->addEntry(entry); + if (!ReadBootTable(&readf,isonum_731(bootdesc->boot_catalog),&boot,this)) { + i=1; + be=boot.defentry; + while (be) { + size=BootImageSize( isonum_711(((struct default_entry*) be->data)->media), + isonum_721(((struct default_entry*) be->data)->seccount)); + path="Default Image"; + if (i>1) path += " (" + QString::number(i) + ")"; + entry=new KIsoFile( this, path, dirent->permissions() & ~S_IFDIR, + dirent->date(), dirent->adate(), dirent->cdate(), + dirent->user(), dirent->group(), QString::null, + isonum_731(((struct default_entry*) be->data)->start)<<11, size<<9 ); + dirent->addEntry(entry); + be=be->next; + i++; + } + + FreeBootTable(&boot); + } +} + +void KIso::readParams() +{ + KConfig *config; + + config = new KConfig("kio_isorc"); + + showhidden=config->readBoolEntry("showhidden",false); + showrr=config->readBoolEntry("showrr",true); + delete config; +} + +bool KIso::openArchive( int mode ) +{ + iso_vol_desc *desc; + QString path,tmp,uid,gid; + struct stat buf; + int tracks[2*100],trackno=0,i,access,c_b,c_i,c_j; + KArchiveDirectory *root; + struct iso_directory_record* idr; + struct el_torito_boot_descriptor* bootdesc; + + if ( mode == IO_WriteOnly ) + return false; + + readParams(); + d->dirList.clear(); + + tracks[0]=0; + if (m_startsec>0) tracks[0]=m_startsec; + kdDebug() << " m_startsec: " << m_startsec << endl; + /* We'll use the permission and user/group of the 'host' file except + * in Rock Ridge, where the permissions are stored on the file system + */ + if (::stat( m_filename.local8Bit(), &buf )<0) { + /* defaults, if stat fails */ + memset(&buf,0,sizeof(struct stat)); + buf.st_mode=0777; + } else { + /* If it's a block device, try to query the track layout (for multisession) */ + if (m_startsec == -1 && S_ISBLK(buf.st_mode)) + trackno=getTracks(m_filename.latin1(),(int*) &tracks); + } + uid.setNum(buf.st_uid); + gid.setNum(buf.st_gid); + access = buf.st_mode & ~S_IFMT; + + kdDebug() << "KIso::openArchive number of tracks: " << trackno << endl; + + if (trackno==0) trackno=1; + for (i=0;i<trackno;i++) { + + c_b=1;c_i=1;c_j=1; + root=rootDir(); + if (trackno>1) { + path=QString::null; + QTextOStream(&path) << "Track " << tracks[(i<<1)+1]; + root = new KIsoDirectory( this, path, access | S_IFDIR, + buf.st_mtime, buf.st_atime, buf.st_ctime, uid, gid, QString::null ); + rootDir()->addEntry(root); + } + + desc=ReadISO9660(&readf,tracks[i<<1],this); + if (!desc) { + kdDebug() << "KIso::openArchive no volume descriptors" << endl; + continue; + } + + while (desc) { + switch (isonum_711(desc->data.type)) { + case ISO_VD_BOOT: + + bootdesc=(struct el_torito_boot_descriptor*) &(desc->data); + if ( !memcmp(EL_TORITO_ID,bootdesc->system_id,ISODCL(8,39)) ) { + path="El Torito Boot"; + if (c_b>1) path += " (" + QString::number(c_b) + ")"; + + dirent = new KIsoDirectory( this, path, access | S_IFDIR, + buf.st_mtime, buf.st_atime, buf.st_ctime, uid, gid, QString::null ); + root->addEntry(dirent); + + addBoot(bootdesc); + c_b++; + } + break; + + case ISO_VD_PRIMARY: + case ISO_VD_SUPPLEMENTARY: + idr=(struct iso_directory_record*) &( ((struct iso_primary_descriptor*) &desc->data)->root_directory_record); + joliet = JolietLevel(&desc->data); + if (joliet) { + QTextOStream(&path) << "Joliet level " << joliet; + if (c_j>1) path += " (" + QString::number(c_j) + ")"; + } else { + path = "ISO9660"; + if (c_i>1) path += " (" + QString::number(c_i) + ")"; + } + dirent = new KIsoDirectory( this, path, access | S_IFDIR, + buf.st_mtime, buf.st_atime, buf.st_ctime, uid, gid, QString::null ); + root->addEntry(dirent); + level=0; + mycallb(idr, this ); + if (joliet) c_j++; else c_i++; + break; + } + desc=desc->next; + } + free(desc); + } + device()->close(); + return true; +} + +bool KIso::closeArchive() +{ + d->dirList.clear(); + return true; +} + +bool KIso::writeDir( const QString&, const QString&, const QString& ) +{ + return false; +} + +bool KIso::prepareWriting( const QString&, const QString&, const QString&, uint) +{ + return false; +} + +bool KIso::doneWriting( uint ) +{ + return false; +} + +void KIso::virtual_hook( int id, void* data ) +{ KArchive::virtual_hook( id, data ); } + diff --git a/kioslave/iso/kiso.h b/kioslave/iso/kiso.h new file mode 100644 index 000000000..ceddb4a0f --- /dev/null +++ b/kioslave/iso/kiso.h @@ -0,0 +1,112 @@ +/*************************************************************************** + kiso.h + ------------------- + begin : Oct 25 2002 + copyright : (C) 2002 by Szombathelyi Gy�gy + email : gyurco@users.sourceforge.net + ***************************************************************************/ + +/*************************************************************************** + * * + * This program 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 file is heavily based on ktar.h from kdelibs + * (c) Torben Weis <weis@kde.org>, David Faure <faure@kde.org> + */ + +#ifndef KISO_H +#define KISO_H + +#include <sys/stat.h> +#include <sys/types.h> + +#include <qdatetime.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qdict.h> + +#include "kisofile.h" +#include "kisodirectory.h" + +/** + * @short A class for reading (optionnally compressed) iso9660 files. + * @author Gy�gy Szombathelyi <gyurco@users.sourceforge.net>, + * Torben Weis <weis@kde.org>, David Faure <faure@kde.org> + */ +class KIso : public KArchive +{ +public: + /** + * Creates an instance that operates on the given filename. + * using the compression filter associated to given mimetype. + * + * @param filename is a local path (e.g. "/home/weis/myfile.tgz") + * @param mimetype "application/x-gzip" or "application/x-bzip2" + * Do not use application/x-tgz or so. Only the compression layer ! + * If the mimetype is ommitted, it will be determined from the filename. + */ + KIso( const QString& filename, const QString & mimetype = QString::null ); + + /** + * Creates an instance that operates on the given device. + * The device can be compressed (KFilterDev) or not (QFile, etc.). + * WARNING: don't assume that giving a QFile here will decompress the file, + * in case it's compressed! + */ + KIso( QIODevice * dev ); + + /** + * If the .iso is still opened, then it will be + * closed automatically by the destructor. + */ + virtual ~KIso(); + + /** + * The name of the os file, as passed to the constructor + * Null if you used the QIODevice constructor. + */ + QString fileName() { return m_filename; } + + bool writeDir( const QString& , const QString& , const QString& ); + bool prepareWriting( const QString& , const QString& , const QString& , uint ); + bool doneWriting( uint ); + + void setStartSec(int startsec) { m_startsec = startsec; } + int startSec() { return m_startsec; } + + bool showhidden,showrr; + int level,joliet; + KIsoDirectory *dirent; +protected: + /** + * Opens the archive for reading. + * Parses the directory listing of the archive + * and creates the KArchiveDirectory/KArchiveFile entries. + * + */ + void readParams(); + virtual bool openArchive( int mode ); + virtual bool closeArchive(); + +private: + /** + * @internal + */ + void addBoot(struct el_torito_boot_descriptor* bootdesc); + void prepareDevice( const QString & filename, const QString & mimetype, bool forced = false ); + int m_startsec; + + QString m_filename; +protected: + virtual void virtual_hook( int id, void* data ); +private: + class KIsoPrivate; + KIsoPrivate * d; +}; + +#endif diff --git a/kioslave/iso/kisodirectory.cpp b/kioslave/iso/kisodirectory.cpp new file mode 100644 index 000000000..f354383e1 --- /dev/null +++ b/kioslave/iso/kisodirectory.cpp @@ -0,0 +1,31 @@ +/*************************************************************************** + kisodirectory.cpp - description + ------------------- + begin : Wed Oct 30 2002 + copyright : (C) 2002 by Szombathelyi György + email : gyurco@users.sourceforge.net + ***************************************************************************/ + +/*************************************************************************** + * * + * This program 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. * + * * + ***************************************************************************/ + +#include "kisodirectory.h" + +KIsoDirectory::KIsoDirectory( KArchive* archive, const QString& name, int access, + int date, int adate, int cdate, const QString& user, const QString& group, + const QString& symlink) : + KArchiveDirectory(archive, name, access, date, user, group, symlink) { + + + m_adate=adate; + m_cdate=cdate; +} + +KIsoDirectory::~KIsoDirectory(){ +} diff --git a/kioslave/iso/kisodirectory.h b/kioslave/iso/kisodirectory.h new file mode 100644 index 000000000..0b59719d4 --- /dev/null +++ b/kioslave/iso/kisodirectory.h @@ -0,0 +1,40 @@ +/*************************************************************************** + kisodirectory.h - description + ------------------- + begin : Wed Oct 30 2002 + copyright : (C) 2002 by Szombathelyi György + email : gyurco@users.sourceforge.net + ***************************************************************************/ + +/*************************************************************************** + * * + * This program 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. * + * * + ***************************************************************************/ + +#ifndef KISODIRECTORY_H +#define KISODIRECTORY_H + +#include <qstring.h> +#include <karchive.h> + +/** + *@author Szombathelyi György + */ + +class KIsoDirectory : public KArchiveDirectory { +public: + KIsoDirectory( KArchive* archive, const QString& name, int access, int date, + int adate,int cdate, const QString& user, const QString& group, + const QString& symlink); + ~KIsoDirectory(); + int adate() const { return m_adate; } + int cdate() const { return m_cdate; } +private: + int m_adate, m_cdate; +}; + +#endif diff --git a/kioslave/iso/kisofile.cpp b/kioslave/iso/kisofile.cpp new file mode 100644 index 000000000..1d23b9c36 --- /dev/null +++ b/kioslave/iso/kisofile.cpp @@ -0,0 +1,53 @@ +/*************************************************************************** + kisofile.cpp - description + ------------------- + begin : Wed Oct 30 2002 + copyright : (C) 2002 by Szombathelyi Gy�gy + email : gyurco@users.sourceforge.net + ***************************************************************************/ + +/*************************************************************************** + * * + * This program 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. * + * * + ***************************************************************************/ + +#include "kisofile.h" +#include <kdebug.h> + +KIsoFile::KIsoFile( KArchive* archive, const QString& name, int access, + int date, int adate,int cdate, const QString& user, const QString& group, + const QString& symlink,int pos, int size) : + KArchiveFile(archive, name, access, date, user, group, symlink, pos, size) { + + + m_adate=adate; + m_cdate=cdate; + m_algo[0]=0;m_algo[1]=0;m_parms[0]=0;m_parms[1]=0;m_realsize=0; +} + +KIsoFile::~KIsoFile(){ +} + +void KIsoFile::setZF(char algo[2],char parms[2],int realsize) { + m_algo[0]=algo[0];m_algo[1]=algo[1]; + m_parms[0]=parms[0];m_parms[1]=parms[1]; + m_realsize=realsize; +} + +QByteArray KIsoFile::data(long long pos, int count) const { + QByteArray r; + int rlen; + + if ( archive()->device()->at(position()+pos) && + r.resize( ((pos+count) < size()) ? count : size()-pos) ) { + rlen=archive()->device()->readBlock( r.data(), r.size() ); + if (rlen ==- 1) r.resize(0); + else if (rlen != (int)r.size()) r.resize(rlen); + } + + return r; +} diff --git a/kioslave/iso/kisofile.h b/kioslave/iso/kisofile.h new file mode 100644 index 000000000..a30fc758c --- /dev/null +++ b/kioslave/iso/kisofile.h @@ -0,0 +1,49 @@ +/*************************************************************************** + kisofile.h - description + ------------------- + begin : Wed Oct 30 2002 + copyright : (C) 2002 by Szombathelyi Gy�gy + email : gyurco@users.sourceforge.net + ***************************************************************************/ + +/*************************************************************************** + * * + * This program 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. * + * * + ***************************************************************************/ + +#ifndef KISOFILE_H +#define KISOFILE_H + +#include <qstring.h> +#include <karchive.h> + +/** + *@author Szombathelyi Gy�gy + */ + +class KIsoFile : public KArchiveFile { +public: + KIsoFile( KArchive* archive, const QString& name, int access, int date, + int adate,int cdate, const QString& user, const QString& group, + const QString& symlink, int pos, int size); + ~KIsoFile(); + void setZF(char algo[2],char parms[2],int realsize); + int adate() const { return m_adate; } + int cdate() const { return m_cdate; } + long long realsize() const { return m_realsize; } + + virtual QByteArray data(long long pos, int count) const; +private: + /* hide this member function, it's broken by design, because the full + data often requires too much memory */ + char m_algo[2],m_parms[2]; + long long m_realsize; + int m_adate, m_cdate; + long long m_curpos; +}; + +#endif diff --git a/kioslave/iso/libisofs/COPYING b/kioslave/iso/libisofs/COPYING new file mode 100644 index 000000000..c7aea1896 --- /dev/null +++ b/kioslave/iso/libisofs/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/kioslave/iso/libisofs/ChangeLog b/kioslave/iso/libisofs/ChangeLog new file mode 100644 index 000000000..fb46b8056 --- /dev/null +++ b/kioslave/iso/libisofs/ChangeLog @@ -0,0 +1,6 @@ +0.1 -> 0.2 + +- Critical directory parsing bug fixed +- Call backs only if some sanity checks on the directory entry succeeds + (length checks to avoid buffer overrun if received corrupt data) +- Preliminary El Torito boot specification support (No multiple boot entries yet) diff --git a/kioslave/iso/libisofs/Makefile.am b/kioslave/iso/libisofs/Makefile.am new file mode 100644 index 000000000..a1278ff41 --- /dev/null +++ b/kioslave/iso/libisofs/Makefile.am @@ -0,0 +1,18 @@ +noinst_LTLIBRARIES = libisofs.la + + +INCLUDES = $(all_includes) + + +#LDFLAGS = + +libisofs_la_METASOURCES=AUTO + +libisofs_la_SOURCES = isofs.c +#libisofs_la_LIBADD = $(LIB_KIO) + +#libisofs_la_LDFLAGS = -module $(all_libraries) $(KDE_PLUGIN) + + + +noinst_HEADERS = bswap.h el_torito.h iso_fs.h isofs.h rock.h diff --git a/kioslave/iso/libisofs/README b/kioslave/iso/libisofs/README new file mode 100644 index 000000000..45d3bff04 --- /dev/null +++ b/kioslave/iso/libisofs/README @@ -0,0 +1,24 @@ +This is the 0.2 release of libisofs. For changes, see the ChangeLog. + +Libisofs implements the reading of the famous ISO-9660 (ECMA-119) file system, +found on CD-ROM media. It also supports the Rock Ridge Interchange Protocol and +Microsoft Joliet extensions. It allows user-mode programs to query the +filesystem volume descriptors and traverse through the directory structure. +Preliminary support for El-Torito boot CDs are added in version 0.2. + +To use it in your project, I recommend to copy bswap.h, isofs.h, iso_fs.h, +el_torito.h rock.h and isofs.c to your sources, and include isofs.h in the +appropriate places. + +Currently only the directory tables are parsed, the path tables are not. +(The path tables contain redundant information.) + +Also a sample program can be compiled with the supplied Makefile. Simply +execute 'make', it should create the executable file isofs. + +On big-endian systems, you need to define WORDS_BIGENDIAN (either in the +compiler command-line, or if you defined HAVE_CONFIG_H, in config.h) + + +György Szombathelyi <gyurco@users.sourceforge.net> +http://libcdrom.sourceforge.net/libisofs.html diff --git a/kioslave/iso/libisofs/bswap.h b/kioslave/iso/libisofs/bswap.h new file mode 100644 index 000000000..95520c6ef --- /dev/null +++ b/kioslave/iso/libisofs/bswap.h @@ -0,0 +1,94 @@ +/* From the mplayer project (www.mplayerhq.hu) */ + +#ifndef __BSWAP_H__ +#define __BSWAP_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_BYTESWAP_H +#include <byteswap.h> +#else + +#ifdef ARCH_X86 +inline static unsigned short ByteSwap16(unsigned short x) +{ + __asm("xchgb %b0,%h0" : + "=q" (x) : + "0" (x)); + return x; +} +#define bswap_16(x) ByteSwap16(x) + +inline static unsigned int ByteSwap32(unsigned int x) +{ +#if __CPU__ > 386 + __asm("bswap %0": + "=r" (x) : +#else + __asm("xchgb %b0,%h0\n" + " rorl $16,%0\n" + " xchgb %b0,%h0": + "=q" (x) : +#endif + "0" (x)); + return x; +} +#define bswap_32(x) ByteSwap32(x) + +inline static unsigned long long int ByteSwap64(unsigned long long int x) +{ + register union { __extension__ unsigned long long int __ll; + unsigned int __l[2]; } __x; + asm("xchgl %0,%1": + "=r"(__x.__l[0]),"=r"(__x.__l[1]): + "0"(bswap_32((unsigned long)x)),"1"(bswap_32((unsigned long)(x>>32)))); + return __x.__ll; +} +#define bswap_64(x) ByteSwap64(x) + +#else + +#define bswap_16(x) (((x) & 0x00ff) << 8 | ((x) & 0xff00) >> 8) + + +/* code from bits/byteswap.h (C) 1997, 1998 Free Software Foundation, Inc. */ +#define bswap_32(x) \ + ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) + +#define bswap_64(x) \ + (__extension__ \ + ({ union { __extension__ unsigned long long int __ll; \ + unsigned int __l[2]; } __w, __r; \ + __w.__ll = (x); \ + __r.__l[0] = bswap_32 (__w.__l[1]); \ + __r.__l[1] = bswap_32 (__w.__l[0]); \ + __r.__ll; })) +#endif /* !ARCH_X86 */ + +#endif /* !HAVE_BYTESWAP_H */ + +/* + be2me ... BigEndian to MachineEndian + le2me ... LittleEndian to MachineEndian +*/ + +#ifdef WORDS_BIGENDIAN +#define be2me_16(x) (x) +#define be2me_32(x) (x) +#define be2me_64(x) (x) +#define le2me_16(x) bswap_16(x) +#define le2me_32(x) bswap_32(x) +#define le2me_64(x) bswap_64(x) +#else +#define be2me_16(x) bswap_16(x) +#define be2me_32(x) bswap_32(x) +#define be2me_64(x) bswap_64(x) +#define le2me_16(x) (x) +#define le2me_32(x) (x) +#define le2me_64(x) (x) +#endif + +#endif diff --git a/kioslave/iso/libisofs/el_torito.h b/kioslave/iso/libisofs/el_torito.h new file mode 100644 index 000000000..cba83f785 --- /dev/null +++ b/kioslave/iso/libisofs/el_torito.h @@ -0,0 +1,63 @@ +#ifndef ELTORITO_H +#define ELTORITO_H 1 + +#include "iso_fs.h" + +#define EL_TORITO_ID "EL TORITO SPECIFICATION\0\0\0\0\0\0\0\0\0" + +struct el_torito_boot_descriptor { + char type [ISODCL ( 1, 1)]; /* 711 */ + char id [ISODCL ( 2, 6)]; + char version [ISODCL ( 7, 7)]; /* 711 */ + char system_id [ISODCL ( 8, 39)]; /* achars */ + char unused [ISODCL ( 40, 71)]; + char boot_catalog [ISODCL ( 72, 75)]; /* 731 */ +}; + +struct validation_entry { + char type [ISODCL ( 1, 1)]; /* 1 */ + char platform [ISODCL ( 2, 2)]; + char unused [ISODCL ( 3, 4)]; + char id [ISODCL ( 5, 28)]; + char cheksum [ISODCL ( 29, 30)]; + char key [ISODCL ( 31, 31)]; /* 0x55 */ + char key2 [ISODCL ( 32, 32)]; /* 0xaa */ +}; + +struct default_entry { + char bootid [ISODCL ( 1, 1)]; + char media [ISODCL ( 2, 2)]; + char loadseg [ISODCL ( 3, 4)]; + char systype [ISODCL ( 5, 5)]; + char unused [ISODCL ( 6, 6)]; + char seccount [ISODCL ( 7, 8)]; + char start [ISODCL ( 9, 12)]; + char unused2 [ISODCL ( 13, 32)]; +}; + +struct section_header { + char headerid [ISODCL ( 1, 1)]; + char platform [ISODCL ( 2, 2)]; + char entries [ISODCL ( 3, 4)]; + char id [ISODCL ( 5, 32)]; +}; + +struct section_entry { + char bootid [ISODCL ( 1, 1)]; + char media [ISODCL ( 2, 2)]; + char loadseg [ISODCL ( 3, 4)]; + char systype [ISODCL ( 5, 5)]; + char unused [ISODCL ( 6, 6)]; + char seccount [ISODCL ( 7, 8)]; + char start [ISODCL ( 9, 12)]; + char selcrit [ISODCL ( 13, 13)]; + char vendor_selcrit [ISODCL ( 14, 32)]; +}; + +struct section_entry_ext { + char extid [ISODCL ( 1, 1)]; + char extrec [ISODCL ( 2, 2)]; + char vendor_selcrit [ISODCL ( 3, 32)]; +}; + +#endif diff --git a/kioslave/iso/libisofs/iso_fs.h b/kioslave/iso/libisofs/iso_fs.h new file mode 100644 index 000000000..43353b0d9 --- /dev/null +++ b/kioslave/iso/libisofs/iso_fs.h @@ -0,0 +1,219 @@ +/* From the linux kernel */ + +#ifndef _ISO_FS_H +#define _ISO_FS_H 1 + +#include "bswap.h" + +/* + * The isofs filesystem constants/structures + */ + +/* This part borrowed from the bsd386 isofs */ +#define ISODCL(from, to) (to - from + 1) + +struct iso_volume_descriptor { + char type[ISODCL(1,1)]; /* 711 */ + char id[ISODCL(2,6)]; + char version[ISODCL(7,7)]; + char data[ISODCL(8,2048)]; +}; + +/* volume descriptor types */ +#define ISO_VD_BOOT 0 +#define ISO_VD_PRIMARY 1 +#define ISO_VD_SUPPLEMENTARY 2 +#define ISO_VD_END 255 + +#define ISO_STANDARD_ID "CD001" + +struct iso_primary_descriptor { + char type [ISODCL ( 1, 1)]; /* 711 */ + char id [ISODCL ( 2, 6)]; + char version [ISODCL ( 7, 7)]; /* 711 */ + char unused1 [ISODCL ( 8, 8)]; + char system_id [ISODCL ( 9, 40)]; /* achars */ + char volume_id [ISODCL ( 41, 72)]; /* dchars */ + char unused2 [ISODCL ( 73, 80)]; + char volume_space_size [ISODCL ( 81, 88)]; /* 733 */ + char unused3 [ISODCL ( 89, 120)]; + char volume_set_size [ISODCL (121, 124)]; /* 723 */ + char volume_sequence_number [ISODCL (125, 128)]; /* 723 */ + char logical_block_size [ISODCL (129, 132)]; /* 723 */ + char path_table_size [ISODCL (133, 140)]; /* 733 */ + char type_l_path_table [ISODCL (141, 144)]; /* 731 */ + char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */ + char type_m_path_table [ISODCL (149, 152)]; /* 732 */ + char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */ + char root_directory_record [ISODCL (157, 190)]; /* 9.1 */ + char volume_set_id [ISODCL (191, 318)]; /* dchars */ + char publisher_id [ISODCL (319, 446)]; /* achars */ + char preparer_id [ISODCL (447, 574)]; /* achars */ + char application_id [ISODCL (575, 702)]; /* achars */ + char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */ + char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */ + char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */ + char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */ + char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */ + char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */ + char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */ + char file_structure_version [ISODCL (882, 882)]; /* 711 */ + char unused4 [ISODCL (883, 883)]; + char application_data [ISODCL (884, 1395)]; + char unused5 [ISODCL (1396, 2048)]; +}; + +/* Almost the same as the primary descriptor but two fields are specified */ +struct iso_supplementary_descriptor { + char type [ISODCL ( 1, 1)]; /* 711 */ + char id [ISODCL ( 2, 6)]; + char version [ISODCL ( 7, 7)]; /* 711 */ + char flags [ISODCL ( 8, 8)]; /* 853 */ + char system_id [ISODCL ( 9, 40)]; /* achars */ + char volume_id [ISODCL ( 41, 72)]; /* dchars */ + char unused2 [ISODCL ( 73, 80)]; + char volume_space_size [ISODCL ( 81, 88)]; /* 733 */ + char escape [ISODCL ( 89, 120)]; /* 856 */ + char volume_set_size [ISODCL (121, 124)]; /* 723 */ + char volume_sequence_number [ISODCL (125, 128)]; /* 723 */ + char logical_block_size [ISODCL (129, 132)]; /* 723 */ + char path_table_size [ISODCL (133, 140)]; /* 733 */ + char type_l_path_table [ISODCL (141, 144)]; /* 731 */ + char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */ + char type_m_path_table [ISODCL (149, 152)]; /* 732 */ + char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */ + char root_directory_record [ISODCL (157, 190)]; /* 9.1 */ + char volume_set_id [ISODCL (191, 318)]; /* dchars */ + char publisher_id [ISODCL (319, 446)]; /* achars */ + char preparer_id [ISODCL (447, 574)]; /* achars */ + char application_id [ISODCL (575, 702)]; /* achars */ + char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */ + char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */ + char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */ + char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */ + char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */ + char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */ + char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */ + char file_structure_version [ISODCL (882, 882)]; /* 711 */ + char unused4 [ISODCL (883, 883)]; + char application_data [ISODCL (884, 1395)]; + char unused5 [ISODCL (1396, 2048)]; +}; + +#define HS_STANDARD_ID "CDROM" + +struct hs_volume_descriptor { + char foo [ISODCL ( 1, 8)]; /* 733 */ + char type [ISODCL ( 9, 9)]; /* 711 */ + char id [ISODCL ( 10, 14)]; + char version [ISODCL ( 15, 15)]; /* 711 */ + char data[ISODCL(16,2048)]; +}; + + +struct hs_primary_descriptor { + char foo [ISODCL ( 1, 8)]; /* 733 */ + char type [ISODCL ( 9, 9)]; /* 711 */ + char id [ISODCL ( 10, 14)]; + char version [ISODCL ( 15, 15)]; /* 711 */ + char unused1 [ISODCL ( 16, 16)]; /* 711 */ + char system_id [ISODCL ( 17, 48)]; /* achars */ + char volume_id [ISODCL ( 49, 80)]; /* dchars */ + char unused2 [ISODCL ( 81, 88)]; /* 733 */ + char volume_space_size [ISODCL ( 89, 96)]; /* 733 */ + char unused3 [ISODCL ( 97, 128)]; /* 733 */ + char volume_set_size [ISODCL (129, 132)]; /* 723 */ + char volume_sequence_number [ISODCL (133, 136)]; /* 723 */ + char logical_block_size [ISODCL (137, 140)]; /* 723 */ + char path_table_size [ISODCL (141, 148)]; /* 733 */ + char type_l_path_table [ISODCL (149, 152)]; /* 731 */ + char unused4 [ISODCL (153, 180)]; /* 733 */ + char root_directory_record [ISODCL (181, 214)]; /* 9.1 */ +}; + +/* We use this to help us look up the parent inode numbers. */ + +struct iso_path_table{ + char name_len[1]; /* 711 */ + char ext_attr_length[1]; /* 711 */ + char extent[4]; /* 731 */ + char parent[2]; /* 721 */ + char name[1]; +}; + +/* high sierra is identical to iso, except that the date is only 6 bytes, and + there is an extra reserved byte after the flags */ + +struct iso_directory_record { + char length [ISODCL (1, 1)]; /* 711 */ + char ext_attr_length [ISODCL (2, 2)]; /* 711 */ + char extent [ISODCL (3, 10)]; /* 733 */ + char size [ISODCL (11, 18)]; /* 733 */ + char date [ISODCL (19, 25)]; /* 7 by 711 */ + char flags [ISODCL (26, 26)]; + char file_unit_size [ISODCL (27, 27)]; /* 711 */ + char interleave [ISODCL (28, 28)]; /* 711 */ + char volume_sequence_number [ISODCL (29, 32)]; /* 723 */ + char name_len [ISODCL (33, 33)]; /* 711 */ + char name [1]; +}; + +/* 8 bit numbers */ +__inline unsigned char isonum_711(char *p); +__inline char isonum_712(char *p); + +/* 16 bit numbers */ +__inline unsigned short isonum_721(char *p); +__inline unsigned short isonum_722(char *p); +__inline unsigned short isonum_723(char *p); + +/* 32 bit numbers */ +__inline unsigned int isonum_731(char *p); +__inline unsigned int isonum_732(char *p); +__inline unsigned int isonum_733(char *p); + + +/* 8 bit numbers */ +__inline unsigned char isonum_711(char *p) +{ + return *(unsigned char *)p; +} +__inline char isonum_712(char *p) +{ + return *p; +} + +/* 16 bit numbers */ +__inline unsigned short isonum_721(char *p) +{ + return le2me_16(*(unsigned short *)p); +} +__inline unsigned short isonum_722(char *p) +{ + return be2me_16(*(unsigned short *)p); +} +__inline unsigned short isonum_723(char *p) +{ + /* Ignore bigendian datum due to broken mastering programs */ + return le2me_16(*(unsigned short *)p); +} + +/* 32 bit numbers */ +__inline unsigned int isonum_731(char *p) +{ + return le2me_32(*(unsigned int *)p); +} + +__inline unsigned int isonum_732(char *p) +{ + return be2me_32(*(unsigned int *)p); +} + +__inline unsigned int isonum_733(char *p) +{ + /* Ignore bigendian datum due to broken mastering programs */ + return le2me_32(*(unsigned int *)p); +} + +#endif /*_ISOFS_H*/ + diff --git a/kioslave/iso/libisofs/isofs.c b/kioslave/iso/libisofs/isofs.c new file mode 100644 index 000000000..ab13d9eb9 --- /dev/null +++ b/kioslave/iso/libisofs/isofs.c @@ -0,0 +1,876 @@ +/*************************************************************************** + isofs.c - libisofs + implementation + ------------------- + begin : Oct 25 2002 + copyright : (C) 2002 by Szombathelyi Gy�gy + email : gyurco@users.sourceforge.net + ***************************************************************************/ + +/*************************************************************************** + * * + * This program 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. * + * * + ***************************************************************************/ + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include "isofs.h" + +/**************************************************************/ + + +/* internal function from the linux kernel (isofs fs) */ +static time_t getisotime(int year,int month,int day,int hour, + int minute,int second,int tz) { + + int days, i; + time_t crtime; + + year-=1970; + + if (year < 0) { + crtime = 0; + } else { + int monlen[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; + + days = year * 365; + if (year > 2) + days += (year+1) / 4; + for (i = 1; i < month; i++) + days += monlen[i-1]; + if (((year+2) % 4) == 0 && month > 2) + days++; + days += day - 1; + crtime = ((((days * 24) + hour) * 60 + minute) * 60) + + second; + + /* sign extend */ + if (tz & 0x80) + tz |= (-1 << 8); + + /* + * The timezone offset is unreliable on some disks, + * so we make a sanity check. In no case is it ever + * more than 13 hours from GMT, which is 52*15min. + * The time is always stored in localtime with the + * timezone offset being what get added to GMT to + * get to localtime. Thus we need to subtract the offset + * to get to true GMT, which is what we store the time + * as internally. On the local system, the user may set + * their timezone any way they wish, of course, so GMT + * gets converted back to localtime on the receiving + * system. + * + * NOTE: mkisofs in versions prior to mkisofs-1.10 had + * the sign wrong on the timezone offset. This has now + * been corrected there too, but if you are getting screwy + * results this may be the explanation. If enough people + * complain, a user configuration option could be added + * to add the timezone offset in with the wrong sign + * for 'compatibility' with older discs, but I cannot see how + * it will matter that much. + * + * Thanks to kuhlmav@elec.canterbury.ac.nz (Volker Kuhlmann) + * for pointing out the sign error. + */ + if (-52 <= tz && tz <= 52) + crtime -= tz * 15 * 60; + } + return crtime; + +} + +/** + * Returns the Unix from the ISO9660 9.1.5 time format + */ +time_t isodate_915(char * p, int hs) { + + return getisotime(1900+p[0],p[1],p[2],p[3],p[4],p[5],hs==0 ? p[6] : 0); +} + +/** + * Returns the Unix from the ISO9660 8.4.26.1 time format + * BUG: hundredth of seconds are ignored, because Unix time_t has one second + * resolution (I think it's no problem at all) + */ +time_t isodate_84261(char * p, int hs) { + int year,month,day,hour,minute,second; + year=(p[0]-'0')*1000 + (p[1]-'0')*100 + (p[2]-'0')*10 + p[3]-'0'; + month=(p[4]-'0')*10 + (p[5]-'0'); + day=(p[6]-'0')*10 + (p[7]-'0'); + hour=(p[8]-'0')*10 + (p[9]-'0'); + minute=(p[10]-'0')*10 + (p[11]-'0'); + second=(p[12]-'0')*10 + (p[13]-'0'); + return getisotime(year,month,day,hour,minute,second,hs==0 ? p[16] : 0); +} + +void FreeBootTable(boot_head *boot) { + boot_entry *be,*next; + + be=boot->defentry; + while (be) { + next=be->next; + free(be); + be=next; + } + boot->defentry=NULL; +} + +int BootImageSize(int media,int len) { + int ret; + + switch(media & 0xf) { + case 0: + ret=len; /* No emulation */ + break; + case 1: + ret=80*2*15; /* 1.2 MB */ + break; + case 2: + ret=80*2*18; /* 1.44 MB */ + break; + case 3: + ret=80*2*36; /* 2.88 MB */ + break; + case 4: + /* FIXME!!! */ + ret=len; /* Hard Disk */ + break; + default: + ret=len; + } + return ret; +} + +static boot_entry *CreateBootEntry(char *be) { + boot_entry *entry; + + entry = (boot_entry*) malloc(sizeof(boot_entry)); + if (!entry) return NULL; + memset(entry, 0, sizeof(boot_entry)); + memcpy(entry->data,be,0x20); + return entry; +} + +int ReadBootTable(readfunc *read,int sector, boot_head *head, void *udata) { + + char buf[2048], *c, *be; + int i,end=0; + unsigned short sum; + boot_entry *defcur=NULL,*deflast=NULL; + register struct validation_entry *ventry=NULL; + + head->sections=NULL; + head->defentry=NULL; + while (1) { + be = (char*) &buf; + if ( read(be, sector, 1, udata) != 1 ) goto err; + + /* first entry needs to be a validation entry */ + if (!ventry) { + ventry=(struct validation_entry *) be; + if ( isonum_711(ventry->type) !=1 ) goto err; + sum=0; + c = (char*) ventry; + for (i=0;i<16;i++) { sum += isonum_721(c); c+=2; } + if (sum) goto err; + memcpy(&head->ventry,be,0x20); + be += 0x20; + } + + while (!end && (be < (char *)(&buf+1))) { + switch (isonum_711(be)) { + case 0x88: + defcur=CreateBootEntry(be); + if (!defcur) goto err; + if (deflast) + deflast->next=defcur; + else + head->defentry=defcur; + defcur->prev=deflast; + deflast=defcur; + break; + case 0x90: + case 0x91: + break; + default: + end=1; + break; + } + be += 0x20; + } + if (end) break; + + sector ++; + } + + return 0; + +err: + FreeBootTable(head); + return -1; +} + + +/** + * Creates the linked list of the volume descriptors + */ +iso_vol_desc *ReadISO9660(readfunc *read,int sector,void *udata) { + + int i; + struct iso_volume_descriptor buf; + iso_vol_desc *first=NULL,*current=NULL,*prev=NULL; + + for (i=0;i<100;i++) { + if (read( (char*) &buf, sector+i+16, 1, udata) != 1 ) { + FreeISO9660(first); + return NULL; + } + if (!memcmp(ISO_STANDARD_ID,&buf.id,5)) { + switch ( isonum_711(&buf.type[0]) ) { + + case ISO_VD_BOOT: + case ISO_VD_PRIMARY: + case ISO_VD_SUPPLEMENTARY: + current=(iso_vol_desc*) malloc(sizeof(iso_vol_desc)); + if (!current) { + FreeISO9660(first); + return NULL; + } + current->prev=prev; + current->next=NULL; + if (prev) prev->next=current; + memcpy(&(current->data),&buf,2048); + if (!first) first=current; + prev=current; + break; + + case ISO_VD_END: + return first; + break; + } + } else if (!memcmp(HS_STANDARD_ID,(struct hs_volume_descriptor*) &buf,5)) { + /* High Sierra format not supported (yet) */ + } + } + + return first; +} + +/** + * Frees the linked list of volume descriptors + */ +void FreeISO9660(iso_vol_desc *data) { + + iso_vol_desc *current; + + + while (data) { + current=data; + data=current->next; + free(current); + } +} + +/** + * Frees the strings in 'rrentry' + */ +void FreeRR(rr_entry *rrentry) { + if (rrentry->name) { + free(rrentry->name); + rrentry->name=NULL; + } + if (rrentry->sl) { + free(rrentry->sl); + rrentry->name=NULL; + } +} + +static int str_nappend(char **d,char *s,int n) { + int i=0; + char *c; + +/* i=strnlen(s,n)+1; */ + while (i<n && s[i]) i++; + i++; + if (*d) i+=(strlen(*d)+1); + c=(char*) malloc(i); + if (!c) return -ENOMEM; + if (*d) { + strcpy(c,*d); + strncat(c,s,n); + + free(*d); + } else + strncpy(c,s,n); + c[i-1]=0; + *d=c; + return 0; +} + +static int str_append(char **d,char *s) { + int i; + char *c; + + i=strlen(s)+1; + if (*d) i+=(strlen(*d)+1); + c=(char*) malloc(i); + if (!c) return -ENOMEM; + if (*d) { + strcpy(c,*d); + strcat(c,s); + free(*d); + } else + strcpy(c,s); + c[i-1]=0; + *d=c; + return 0; +} + +#define rrtlen(c) (((unsigned char) c & 0x80) ? 17 : 7) +#define rrctime(f,c) ((unsigned char) f & 0x80) ? isodate_84261(c,0) : isodate_915(c,0) +/** + * Parses the System Use area and fills rr_entry with values + */ +int ParseRR(struct iso_directory_record *idr, rr_entry *rrentry) { + + int suspoffs,susplen,i,f,ret=0; + char *r, *c; + struct rock_ridge *rr; + + suspoffs=33+isonum_711(idr->name_len); + if (!(isonum_711(idr->name_len) & 1)) suspoffs++; + susplen=isonum_711(idr->length)-suspoffs; + r= & (((char*) idr)[suspoffs]); + rr = (struct rock_ridge*) r; + + memset(rrentry,0,sizeof(rr_entry)); + rrentry->len = sizeof(rr_entry); + + while (susplen > 0) { + if (isonum_711(&rr->len) > susplen || rr->len == 0) break; + if (rr->signature[0]=='N' && rr->signature[1]=='M') { + if (!(rr->u.NM.flags & 0x26) && rr->len>5 && !rrentry->name) { + + if (str_nappend(&rrentry->name,rr->u.NM.name,isonum_711(&rr->len)-5)) { + FreeRR(rrentry); return -ENOMEM; + } + ret++; + } + } else if (rr->signature[0]=='P' && rr->signature[1]=='X' && + (isonum_711(&rr->len)==44 || isonum_711(&rr->len)==36)) { + rrentry->mode=isonum_733(rr->u.PX.mode); + rrentry->nlink=isonum_733(rr->u.PX.n_links); + rrentry->uid=isonum_733(rr->u.PX.uid); + rrentry->gid=isonum_733(rr->u.PX.gid); + if (isonum_711(&rr->len)==44) rrentry->serno=isonum_733(rr->u.PX.serno); + ret++; + } else if (rr->signature[0]=='P' && rr->signature[1]=='N' && + isonum_711(&rr->len)==20) { + rrentry->dev_major=isonum_733(rr->u.PN.dev_high); + rrentry->dev_minor=isonum_733(rr->u.PN.dev_low); + ret++; + } else if (rr->signature[0]=='P' && rr->signature[1]=='L' && + isonum_711(&rr->len)==12) { + rrentry->pl=isonum_733(rr->u.PL.location); + ret++; + } else if (rr->signature[0]=='C' && rr->signature[1]=='L' && + isonum_711(&rr->len)==12) { + rrentry->cl=isonum_733(rr->u.CL.location); + ret++; + } else if (rr->signature[0]=='R' && rr->signature[1]=='E' && + isonum_711(&rr->len)==4) { + rrentry->re=1; + ret++; + } else if (rr->signature[0]=='S' && rr->signature[1]=='L' && + isonum_711(&rr->len)>7) { + i = isonum_711(&rr->len)-5; + c = (char*) rr; + c += 5; + while (i>0) { + switch(c[0] & ~1) { + case 0x2: + if (str_append(&rrentry->sl,(char *)".")) { + FreeRR(rrentry); return -ENOMEM; + } + break; + case 0x4: + if (str_append(&rrentry->sl,(char *)"..")) { + FreeRR(rrentry); return -ENOMEM; + } + break; + } + if ( (c[0] & 0x08) == 0x08 || (c[1] && rrentry->sl && + strlen(rrentry->sl)>1) ) { + if (str_append(&rrentry->sl,(char *)"/")) { + FreeRR(rrentry); return -ENOMEM; + } + } + + if ((unsigned char)c[1]>0) { + if (str_nappend(&rrentry->sl,c+2,(unsigned char)c[1])) { + FreeRR(rrentry); return -ENOMEM; + } + } + i -= ((unsigned char)c[1] + 2); + c += ((unsigned char)c[1] + 2); + } + ret++; + } else if (rr->signature[0]=='T' && rr->signature[1]=='F' && + isonum_711(&rr->len)>5) { + + i = isonum_711(&rr->len)-5; + f = rr->u.TF.flags; + c = (char*) rr; + c += 5; + + while (i >= rrtlen(f)) { + if (f & 1) { + rrentry->t_creat=rrctime(f,c); + f &= ~1; + } else if (f & 2) { + rrentry->t_mtime=rrctime(f,c); + f &= ~2; + } else if (f & 4) { + rrentry->t_atime=rrctime(f,c); + f &= ~4; + } else if (f & 8) { + rrentry->t_ctime=rrctime(f,c); + f &= ~8; + } else if (f & 16) { + rrentry->t_backup=rrctime(f,c); + f &= ~16; + } else if (f & 32) { + rrentry->t_expire=rrctime(f,c); + f &= ~32; + } else if (f & 64) { + rrentry->t_effect=rrctime(f,c); + f &= ~64; + } + + i -= rrtlen(f); + c += rrtlen(f); + } + ret++; + + } else if (rr->signature[0]=='Z' && rr->signature[1]=='F' && + isonum_711(&rr->len)==16) { + /* Linux-specific extension: transparent decompression */ + rrentry->z_algo[0]=rr->u.ZF.algorithm[0]; + rrentry->z_algo[1]=rr->u.ZF.algorithm[1]; + rrentry->z_params[0]=rr->u.ZF.parms[0]; + rrentry->z_params[1]=rr->u.ZF.parms[1]; + rrentry->z_size=isonum_733(rr->u.ZF.real_size); + ret++; + } else { +/* printf("SUSP sign: %c%c\n",rr->signature[0],rr->signature[1]); */ + } + + susplen -= isonum_711(&rr->len); + r += isonum_711(&rr->len); + rr = (struct rock_ridge*) r; + } + + return ret; +} + +/** + * Iterates over the directory entries. The directory is in 'buf', + * the size of the directory is 'size'. 'callback' is called for each + * directory entry with the parameter 'udata'. + */ +int ProcessDir(readfunc *read,int extent,int size,dircallback *callback,void *udata) { + + int pos=0,ret=0,siz; + char *buf; + struct iso_directory_record *idr; + + if (size & 2047) { + siz=((size>>11)+1)<<11; + } else { + siz=size; + } + + buf=(char*) malloc(siz); + if (!buf) return -ENOMEM; + if (read(buf,extent,siz>>11,udata)!=siz>>11) { + free(buf); + return -EIO; + } + + while (size>0) { + idr=(struct iso_directory_record*) &buf[pos]; + if (isonum_711(idr->length)==0) { + + size-=(2048 - (pos & 0x7ff)); + if (size<=2) break; + pos+=0x800; + pos&=0xfffff800; + idr=(struct iso_directory_record*) &buf[pos]; + } + pos+=isonum_711(idr->length); + pos+=isonum_711(idr->ext_attr_length); + size-=isonum_711(idr->length); + size-=isonum_711(idr->ext_attr_length); + if (size<0) break; + + if (isonum_711(idr->length) +<33 || + isonum_711(idr->length)<33+isonum_711(idr->name_len)) { + /* Invalid directory entry */ + continue; + } + if ((ret=callback(idr,udata))) break; + } + + free(buf); + return ret; +} + +/** + * returns the joliet level from the volume descriptor + */ +int JolietLevel(struct iso_volume_descriptor *ivd) { + int ret=0; + register struct iso_supplementary_descriptor *isd; + + isd = (struct iso_supplementary_descriptor *) ivd; + + if (isonum_711(ivd->type)==ISO_VD_SUPPLEMENTARY) { + if (isd->escape[0]==0x25 && + isd->escape[1]==0x2f) { + + switch (isd->escape[2]) { + case 0x40: + ret=1; + break; + case 0x43: + ret=2; + break; + case 0x45: + ret=3; + break; + } + } + } + return ret; +} + +/********************************************************************/ +#ifdef ISOFS_MAIN + +#include <time.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <iconv.h> + +int level=0,joliet=0,dirs,files; +iconv_t iconv_d; +int fd; + +int readf(char *buf, int start, int len,void *udata) { + int ret; + + if ((ret=lseek(fd, start << 11, SEEK_SET))<0) return ret; + ret=read(fd, buf, len << 11); + if (ret<0) return ret; + return (ret >> 11); +} + +void dumpchars(char *c,int len) { + while (len>0) { + printf("%c",*c); + len--; + c++; + } +} + +void sp(int num) { + int i; + for (i=0;i<num*5;i++) { printf(" "); }; +} + +void dumpflags(char flags) { + if (flags & 1) printf("HIDDEN "); + if (flags & 2) printf("DIR "); + if (flags & 4) printf("ASF "); +} + +void dumpjoliet(char *c,int len) { + + char outbuf[255]; + size_t out; + int ret; + char *outptr; + + outptr=(char*) &outbuf; + out=255; + if ((iconv(iconv_d,&c,&len,&outptr,&out))<0) { + printf("conversion error=%d",errno); + return; + } + ret=255-out; + dumpchars((char*) &outbuf,ret); +} + +void dumpchardesc(char *c,int len) { + + if (joliet) + dumpjoliet(c,len); + else { + dumpchars(c,len); + } +} + +void dumpiso915time(char *t, int hs) { + + time_t time; + char *c; + + time=isodate_915(t,hs); + c=(char*) ctime(&time); + if (c && c[strlen(c)-1]==0x0a) c[strlen(c)-1]=0; + if (c) printf("%s",c); +} + +void dumpiso84261time(char *t, int hs) { + + time_t time; + char *c; + + time=isodate_84261(t,hs); + c=(char*) ctime(&time); + if (c && c[strlen(c)-1]==0x0a) c[strlen(c)-1]=0; + if (c) printf("%s",c); +} + +void dumpdirrec(struct iso_directory_record *dir) { + + if (isonum_711(dir->name_len)==1) { + switch (dir->name[0]) { + case 0: + printf("."); + break; + case 1: + printf(".."); + break; + default: + printf("%c",dir->name[0]); + break; + } + } + dumpchardesc(dir->name,isonum_711(dir->name_len)); + printf(" size=%d",isonum_733(dir->size)); + printf(" extent=%d ",isonum_733(dir->extent)); + dumpflags(isonum_711(dir->flags)); + dumpiso915time((char*) &(dir->date),0); +} + +void dumprrentry(rr_entry *rr) { + printf(" NM=[%s] uid=%d gid=%d nlink=%d mode=%o ", + rr->name,rr->uid,rr->gid,rr->nlink,rr->mode); + if (S_ISCHR(rr->mode) || S_ISBLK(rr->mode)) + printf("major=%d minor=%d ",rr->dev_major,rr->dev_minor); + if (rr->mode & S_IFLNK && rr->sl) printf("slink=%s ",rr->sl); +/* + printf("\n"); + if (rr->t_creat) printf("t_creat: %s",ctime(&rr->t_creat)); + if (rr->st_mtime) printf("st_mtime: %s",ctime(&rr->st_mtime)); + if (rr->st_atime) printf("st_atime: %s",ctime(&rr->st_atime)); + if (rr->st_ctime) printf("st_ctime: %s",ctime(&rr->st_ctime)); + if (rr->t_backup) printf("t_backup: %s",ctime(&rr->t_backup)); + if (rr->t_expire) printf("t_expire: %s",ctime(&rr->t_expire)); + if (rr->t_effect) printf("t_effect: %s",ctime(&rr->t_effect)); +*/ +} + +void dumpsusp(char *c, int len) { + dumpchars(c,len); +} + +void dumpboot(struct el_torito_boot_descriptor *ebd) { + printf("version: %d\n",isonum_711(ebd->version)); + printf("system id: ");dumpchars(ebd->system_id,ISODCL(8,39));printf("\n"); + printf("boot catalog start: %d\n",isonum_731(ebd->boot_catalog)); +} + +void dumpdefentry(struct default_entry *de) { + printf("Default entry: \n"); + printf(" bootid=%x\n",isonum_711(de->bootid)); + printf(" media emulation=%d (",isonum_711(de->media)); + switch(isonum_711(de->media) & 0xf) { + case 0: + printf("No emulation"); + break; + case 1: + printf("1.2 Mb floppy"); + break; + case 2: + printf("1.44 Mb floppy"); + break; + case 3: + printf("2.88 Mb floppy"); + break; + case 4: + printf("Hard Disk"); + break; + default: + printf("Unknown/Invalid"); + break; + } + printf(")\n"); + printf(" loadseg=%d\n",isonum_721(de->loadseg)); + printf(" systype=%d\n",isonum_711(de->systype)); + printf(" start lba=%d count=%d\n",isonum_731(de->start), + isonum_721(de->seccount)); +} + +void dumpbootcat(boot_head *bh) { + boot_entry *be; + + printf("System id: ");dumpchars(bh->ventry.id,ISODCL(28,5));printf("\n"); + be=bh->defentry; + while (be) { + dumpdefentry(be->data); + be=be->next; + } +} + +void dumpdesc(struct iso_primary_descriptor *ipd) { + + printf("system id: ");dumpchardesc(ipd->system_id,ISODCL(9,40));printf("\n"); + printf("volume id: ");dumpchardesc(ipd->volume_id,ISODCL(41,72));printf("\n"); + printf("volume space size: %d\n",isonum_733(ipd->volume_space_size)); + printf("volume set size: %d\n",isonum_723(ipd->volume_set_size)); + printf("volume seq num: %d\n",isonum_723(ipd->volume_set_size)); + printf("logical block size: %d\n",isonum_723(ipd->logical_block_size)); + printf("path table size: %d\n",isonum_733(ipd->path_table_size)); + printf("location of type_l path table: %d\n",isonum_731(ipd->type_l_path_table)); + printf("location of optional type_l path table: %d\n",isonum_731(ipd->opt_type_l_path_table)); + printf("location of type_m path table: %d\n",isonum_732(ipd->type_m_path_table)); + printf("location of optional type_m path table: %d\n",isonum_732(ipd->opt_type_m_path_table)); +/* + printf("Root dir record:\n");dumpdirrec((struct iso_directory_record*) &ipd->root_directory_record); +*/ + printf("Volume set id: ");dumpchardesc(ipd->volume_set_id,ISODCL(191,318));printf("\n"); + printf("Publisher id: ");dumpchardesc(ipd->publisher_id,ISODCL(319,446));printf("\n"); + printf("Preparer id: ");dumpchardesc(ipd->preparer_id,ISODCL(447,574));printf("\n"); + printf("Application id: ");dumpchardesc(ipd->application_id,ISODCL(575,702));printf("\n"); + printf("Copyright id: ");dumpchardesc(ipd->copyright_file_id,ISODCL(703,739));printf("\n"); + printf("Abstract file id: ");dumpchardesc(ipd->abstract_file_id,ISODCL(740,776));printf("\n"); + printf("Bibliographic file id: ");dumpchardesc(ipd->bibliographic_file_id,ISODCL(777,813));printf("\n"); + printf("Volume creation date: ");dumpiso84261time(ipd->creation_date,0);printf("\n"); + printf("Volume modification date: ");dumpiso84261time(ipd->modification_date,0);printf("\n"); + printf("Volume expiration date: ");dumpiso84261time(ipd->expiration_date,0);printf("\n"); + printf("Volume effective date: ");dumpiso84261time(ipd->effective_date,0);printf("\n"); + printf("File structure version: %d\n",isonum_711(ipd->file_structure_version)); +} + +int mycallb(struct iso_directory_record *idr,void *udata) { + rr_entry rrentry; + + sp(level);dumpdirrec(idr); + if (level==0) printf(" (Root directory) "); + printf("\n"); + + if (ParseRR(idr,&rrentry)>0) { + sp(level);printf(" ");dumprrentry(&rrentry);printf("\n"); + } + FreeRR(&rrentry); + if ( !(idr->flags[0] & 2) ) files++; + if ( (idr->flags[0] & 2) && (level==0 || isonum_711(idr->name_len)>1) ) { + level++; + dirs++; + ProcessDir(&readf,isonum_733(idr->extent),isonum_733(idr->size),&mycallb,udata); + level--; + } + return 0; +} + +/************************************************/ + +int main(int argc, char *argv[]) { + + int i=1,sector=0; + iso_vol_desc *desc; + boot_head boot; + + if (argc<2) { + fprintf(stderr,"\nUsage: %s iso-file-name or device [starting sector]\n\n",argv[0]); + return 0; + } + if (argc>=3) { + sector=atoi(argv[2]); + printf("Using starting sector number %d\n",sector); + } + fd=open(argv[1],O_RDONLY); + if (fd<0) { + fprintf(stderr,"open error\n"); + return -1; + } + iconv_d=iconv_open("ISO8859-2","UTF16BE"); + if (iconv_d==0) { + fprintf(stderr,"iconv open error\n"); + return -1; + } + + desc=ReadISO9660(&readf,sector,NULL); + if (!desc) { + printf("No volume descriptors\n"); + return -1; + } + while (desc) { + + printf("\n\n--------------- Volume descriptor (%d.) type %d: ---------------\n\n", + i,isonum_711(desc->data.type)); + switch (isonum_711(desc->data.type)) { + case ISO_VD_BOOT: { + + struct el_torito_boot_descriptor* bootdesc; + bootdesc=&(desc->data); + dumpboot(bootdesc); + if ( !memcmp(EL_TORITO_ID,bootdesc->system_id,ISODCL(8,39)) ) { + + if (ReadBootTable(&readf,isonum_731(bootdesc->boot_catalog),&boot,NULL)) { + printf("Boot Catalog Error\n"); + } else { + dumpbootcat(&boot); + FreeBootTable(&boot); + } + } + } + break; + + case ISO_VD_PRIMARY: + case ISO_VD_SUPPLEMENTARY: + joliet=0; + joliet = JolietLevel(&desc->data); + printf("Joliet level: %d\n",joliet); + dumpdesc((struct iso_primary_descriptor*) &desc->data); + printf("\n\n--------------- Directory structure: -------------------\n\n"); + dirs=0;files=0; + mycallb( &( ((struct iso_primary_descriptor*) &desc->data)->root_directory_record), NULL ); + printf("\nnumber of directories: %d\n",dirs); + printf("\nnumber of files: %d\n",files); + break; + + } + desc=desc->next; + i++; + } + iconv_close(iconv_d); + close(fd); + FreeISO9660(desc); + return 0; +} + +#endif /* ISOFS_MAIN */ diff --git a/kioslave/iso/libisofs/isofs.h b/kioslave/iso/libisofs/isofs.h new file mode 100644 index 000000000..52190e673 --- /dev/null +++ b/kioslave/iso/libisofs/isofs.h @@ -0,0 +1,161 @@ +/*************************************************************************** + isofs.h - include this file to use libisofs + ------------------- + begin : Oct 25 2002 + copyright : (C) 2002 by Szombathelyi Gy�gy + email : gyurco@users.sourceforge.net + ***************************************************************************/ + +/*************************************************************************** + * * + * This program 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. * + * * + ***************************************************************************/ + +#ifndef ISOFS_H +#define ISOFS_H + +#include <sys/time.h> +#ifdef __cplusplus +extern "C" { +#endif + +#include "iso_fs.h" +#include "el_torito.h" +#include "rock.h" + +typedef struct _rr_entry { + int len; /* length of structure */ + char *name; /* Name from 'NM' */ + char *sl; /* symbolic link data */ + time_t t_creat; + time_t t_mtime; + time_t t_atime; + time_t t_ctime; + time_t t_backup; + time_t t_expire; + time_t t_effect; + int mode; /* POSIX file modes */ + int nlink; + int uid; + int gid; + int serno; + int dev_major; + int dev_minor; + int pl; /* parent location */ + int cl; /* child location */ + int re; /* relocated */ + char z_algo[2]; /* zizofs algorithm */ + char z_params[2]; /* zizofs parameters */ + int z_size; /* zizofs real_size */ +} rr_entry; + +typedef struct _iso_vol_desc { + struct _iso_vol_desc *next; + struct _iso_vol_desc *prev; + struct iso_volume_descriptor data; +} iso_vol_desc; + +typedef struct _boot_entry { + struct _boot_entry *next; + struct _boot_entry *prev; + struct _boot_entry *parent; + struct _boot_entry *child; + char data[32]; +} + boot_entry; + +typedef struct _boot_head { + struct validation_entry ventry; + struct _boot_entry *defentry; + struct _boot_entry *sections; +} + boot_head; + +/** + * this callback function needs to read 'len' sectors from 'start' into 'buf' + */ +typedef int readfunc(char *buf,int start, int len,void *); + +/** + * ProcessDir uses this callback + */ +typedef int dircallback(struct iso_directory_record *,void *); + +/** + * Returns the Unix from the ISO9660 9.1.5 (7 bytes) time format + * This function is from the linux kernel. + * Set 'hs' to non-zero if it's a HighSierra volume + */ +time_t isodate_915(char * p, int hs); + +/** + * Returns the Unix time from the ISO9660 8.4.26.1 (17 bytes) time format + * BUG: hundredth of seconds are ignored, because time_t has one second + * resolution (I think it's no problem at all) + * Set 'hs' to non-zero if it's a HighSierra volume + */ +time_t isodate_84261(char * p, int hs); + +/** + * Creates the linked list of the volume descriptors + * 'sector' is the starting sector number of where the filesystem start + * (starting sector of a session on a CD-ROM) + * If the function fails, returns NULL + * Don't forget to call FreeISO9660 after using the volume descriptor list! + */ +iso_vol_desc *ReadISO9660(readfunc *read,int sector,void *udata); + +/** + * Frees the linked list of volume descriptors +. + */ +void FreeISO9660(iso_vol_desc *data); + +/** + * Iterates over the directory entries. The directory is in 'buf', + * the size of the directory is 'size'. 'callback' is called for each + * directory entry with the parameter 'udata'. + */ +int ProcessDir(readfunc *read,int extent,int size,dircallback *callback,void *udata); + +/** + * Parses the System Use area and fills rr_entry with values + */ +int ParseRR(struct iso_directory_record *idr, rr_entry *rrentry); + +/** + * Frees the strings in 'rrentry' + */ +void FreeRR(rr_entry *rrentry); + +/** + * returns the joliet level from the volume descriptor + */ +int JolietLevel(struct iso_volume_descriptor *ivd); + +/** + * Returns the size of the boot image (in 512 byte sectors) + */ +int BootImageSize(int media,int len); + +/** + * Frees the boot catalog entries in 'boot'. If you ever called ReadBootTable, + * then don't forget to call FreeBootTable! + */ +void FreeBootTable(boot_head *boot); + +/** + * Reads the boot catalog into 'head'. Don't forget to call FreeBootTable! + */ +int ReadBootTable(readfunc *read,int sector, boot_head *head, void *udata); + +#ifdef __cplusplus +} //extern "C" +#endif + +#endif + diff --git a/kioslave/iso/libisofs/rock.h b/kioslave/iso/libisofs/rock.h new file mode 100644 index 000000000..e85919261 --- /dev/null +++ b/kioslave/iso/libisofs/rock.h @@ -0,0 +1,127 @@ +/* this header is from the linux kernel */ + +#ifndef ROCK_H +#define ROCK_H 1 + +/* These structs are used by the system-use-sharing protocol, in which the + Rock Ridge extensions are embedded. It is quite possible that other + extensions are present on the disk, and this is fine as long as they + all use SUSP */ + +struct SU_SP{ + unsigned char magic[2]; + unsigned char skip; +}; + +struct SU_CE{ + char extent[8]; + char offset[8]; + char size[8]; +}; + +struct SU_ER{ + unsigned char len_id; + unsigned char len_des; + unsigned char len_src; + unsigned char ext_ver; + char data[1]; +}; + +struct RR_RR{ + char flags[1]; +}; + +struct RR_PX{ + char mode[8]; + char n_links[8]; + char uid[8]; + char gid[8]; + char serno[8]; +}; + +struct RR_PN{ + char dev_high[8]; + char dev_low[8]; +}; + + +struct SL_component{ + unsigned char flags; + unsigned char len; + char text[1]; +}; + +struct RR_SL{ + unsigned char flags; + struct SL_component link; +}; + +struct RR_NM{ + unsigned char flags; + char name[1]; +}; + +struct RR_CL{ + char location[8]; +}; + +struct RR_PL{ + char location[8]; +}; + +struct stamp{ + char time[7]; +}; + +struct RR_TF{ + char flags; + struct stamp times[1]; /* Variable number of these beasts */ +}; + +/* Linux-specific extension for transparent decompression */ +struct RR_ZF{ + char algorithm[2]; + char parms[2]; + char real_size[8]; +}; + +/* These are the bits and their meanings for flags in the TF structure. */ +#define TF_CREATE 1 +#define TF_MODIFY 2 +#define TF_ACCESS 4 +#define TF_ATTRIBUTES 8 +#define TF_BACKUP 16 +#define TF_EXPIRATION 32 +#define TF_EFFECTIVE 64 +#define TF_LONG_FORM 128 + +struct rock_ridge{ + char signature[2]; + char len; /* 711 */ + char version; /* 711 */ + union{ + struct SU_SP SP; + struct SU_CE CE; + struct SU_ER ER; + struct RR_RR RR; + struct RR_PX PX; + struct RR_PN PN; + struct RR_SL SL; + struct RR_NM NM; + struct RR_CL CL; + struct RR_PL PL; + struct RR_TF TF; + struct RR_ZF ZF; + } u; +}; + +#define RR_PX 1 /* POSIX attributes */ +#define RR_PN 2 /* POSIX devices */ +#define RR_SL 4 /* Symbolic link */ +#define RR_NM 8 /* Alternate Name */ +#define RR_CL 16 /* Child link */ +#define RR_PL 32 /* Parent link */ +#define RR_RE 64 /* Relocation directory */ +#define RR_TF 128 /* Timestamps */ + +#endif /* ROCK_H */ diff --git a/kioslave/iso/qfilehack.cpp b/kioslave/iso/qfilehack.cpp new file mode 100644 index 000000000..6f0b99d4a --- /dev/null +++ b/kioslave/iso/qfilehack.cpp @@ -0,0 +1,40 @@ +/*************************************************************************** + qfilehack.cpp - description + ------------------- + begin : Tue Oct 29 2002 + copyright : (C) 2002 by Szombathelyi György + email : gyurco@users.sourceforge.net + ***************************************************************************/ + +/*************************************************************************** + * * + * This program 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. * + * * + ***************************************************************************/ + +#include "qfilehack.h" + +QFileHack::QFileHack(){ +} + +QFileHack::QFileHack( const QString & name ) : QFile(name) { +} + +QFileHack::~QFileHack(){ +} + +bool QFileHack::open ( int m ) { + bool ret; + +#ifdef __linux__ + m |= IO_Async; //On linux, set O_NONBLOCK, opens CD-ROMs faster +#endif + ret=QFile::open(m); + if (ret && isSequentialAccess() ) { + setType(IO_Direct); + } + return ret; +} diff --git a/kioslave/iso/qfilehack.h b/kioslave/iso/qfilehack.h new file mode 100644 index 000000000..5e9e247d0 --- /dev/null +++ b/kioslave/iso/qfilehack.h @@ -0,0 +1,38 @@ +/*************************************************************************** + qfilehack.h - description + ------------------- + begin : Tue Oct 29 2002 + copyright : (C) 2002 by Szombathelyi György + email : gyurco@users.sourceforge.net + ***************************************************************************/ + +/*************************************************************************** + * * + * This program 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. * + * * + ***************************************************************************/ + +#ifndef QFILEHACK_H +#define QFILEHACK_H + +#include <qfile.h> +#include <qstring.h> + +/** + *@author Szombathelyi György + * Qt thinks if a file is not S_IFREG, you cannot seek in it. It's false (what about + * block devices for example? + */ + +class QFileHack : public QFile { +public: + QFileHack(); + QFileHack( const QString & name ); + ~QFileHack(); + virtual bool open ( int m ); +}; + +#endif |