[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: untar.m on Solaris with non-GNU tar
From: |
Bill Denney |
Subject: |
Re: untar.m on Solaris with non-GNU tar |
Date: |
Fri, 20 Oct 2006 18:39:32 -0400 |
User-agent: |
Thunderbird 1.5.0.7 (Windows/20060909) |
John Swensen wrote:
I was trying to install octave-forge packages on a Solaris machine and
kept getting a "tar: tape read error" and after digging found out that
it is because the Solaris provided tar executable does not include the
capability to gunzip *and* untar from a single 'tar' call. Would it
be possible to split the gunzip and tar process into 2 calls to
accomodate?
OK, here is the code that can do it. This can unpack any of these
extensions: .gz, .Z, .bz2, .bz, .tar, .tar.gz, .tgz, .tar.bz2, .tbz2,
.tbz, or .zip. For full functionality, you'll need the attached patch
that makes movefile.m and copyfile.m work with cellstrs as the first
input (it also protects the filenames so that they spaces won't cause
problems).
If everyone likes it, I'll add wrapper functions to make gunzip, untar,
unzip, and bunzip2 work with this.
Bill
scripts/Changelog:
2006-10-20 Bill Denney <address@hidden>
* miscellaneous/movefile.m, miscellaneous/copyfile.m: accept cell
input and protect the filenames.
* miscellaneous/unpack.m: new file, unpack most archive types.
## Copyright (C) 2006 Bill Denney
##
## This file is part of Octave.
##
## Octave 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, or (at your option)
## any later version.
##
## Octave is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Octave; see the file COPYING. If not, write to the Free
## Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
## 02110-1301, USA.
## -*- texinfo -*-
## @deftypefn {Function File} address@hidden =} unpack (@var{file}, @var{dir})
## @deftypefnx {Function File} address@hidden =} unpack (@var{file}, @var{dir},
@var{filetype})
## Unpack the archive @var{file} based on its extension to the directory
## @var{dir}. If @var{file} is a cellstr, then all files will be
## handled individually. If @var{dir} is not specified, it defaults to
## the current directory. It returns a list of @var{files}
## unpacked. If a directory is in the file list, then the
## @var{filetype} to unpack must also be specified.
##
## The @var{files} includes the entire path to the output files.
## @seealso{tar, untar, gzip, gunzip, zip, unzip}
## @end deftypefn
## Author: Bill Denney <address@hidden>
function varargout = unpack (file, directory, filetype)
if (nargin < 1 || nargin > 3)
print_usage ();
endif
if (nargin < 2)
directory = ".";
endif
if (nargin < 3)
filetype = "";
endif
if ischar (file)
if isdir (file)
if isempty (filetype)
error ("unpack: filetype must be given for a directory");
elseif ~ any (strcmpi (filetype, "gunzip"))
error ("unpack: filetype must be gunzip for a directory");
endif
else
[pathstr, name, ext] = fileparts (file);
## check to see if it's .tar.gz, .tar.Z, or .tar.bz2
if strcmp (ext, ".gz") || strcmp (ext, ".Z") || strcmp (ext, ".bz2")
[tmppathstr, tmpname, tmpext] = fileparts (name);
if strcmp(tmpext, ".tar")
name = tmpname;
ext = [tmpext ext];
endif
endif
## if the file is a url, download it and then work with that
## file
if ~ isempty (strfind (file, "://"))
## FIXME: the above is not a perfect test for a url
urlfile = file;
## FIXME: should we name the file that we download with the
## same file name as the url requests?
tmpfile = [tmpnam() ext];
[file, success, msg] = urlwrite (urlfile, tmpfile);
if (~ success)
error ("unpack: could not get \"%s\": %s", urlfile, msg);
endif
endif
endif
## canonicalize_file_name returns empty if the file isn't found, so
## use that to check for existence
cfile = canonicalize_file_name (file);
if isempty (cfile)
error ("unpack: file \"%s\" not found.", file)
else
file = cfile;
endif
elseif iscellstr (file)
files = {};
for i = 1:numel (file)
tmpfiles = unpack (file{i}, directory);
files = {files{:} tmpfiles{:}};
endfor
else
error ("unpack: invalid input file class, %s", class(file));
endif
## Instructions on what to do for any extension.
##
## The first field names are the file extension without periods.
## The .cmd part is what is executed to unpack an archive.
## The .parser is the function to execute on output to get the files list.
## The .move part indicates if the files may need to be manually moved
## (i.e. tar and unzip decompress into the current directory while
## bzip2 and gzip decompress the file at its location).
commandlist.gz.cmd = "gunzip -v -r \"%s\"";
commandlist.gz.parser = @__parse_gzip__;
commandlist.gz.move = true;
commandlist.z = commandlist.gz;
commandlist.bz2.cmd = "bunzip2 -v \"%s\"";
commandlist.bz2.parser = @__parse_bzip2__;
commandlist.bz2.move = true;
commandlist.bz = commandlist.bz2;
commandlist.tar.cmd = "tar -x -v -f \"%s\"";
commandlist.tar.parser = @__parse_tar__;
commandlist.tar.move = false;
commandlist.targz.cmd = "gunzip -c \"%s\" | tar -x -v";
commandlist.targz.parser = @__parse_tar__;
commandlist.targz.move = false;
commandlist.tgz = commandlist.targz;
commandlist.tarbz2.cmd = "bunzip2 -c \"%s\" | tar -x -v";
commandlist.tarbz2.parser = @__parse_tar__;
commandlist.tarbz2.move = false;
commandlist.tbz2 = commandlist.tarbz2;
commandlist.tbz = commandlist.tarbz2;
commandlist.zip.cmd = "unzip \"%s\"";
commandlist.zip.parser = @__parse_zip__;
commandlist.zip.move = false;
nodotext = ext(~ ismember (ext, "."));
origdir = pwd ();
if isfield (commandlist, nodotext)
command = commandlist.(nodotext).cmd;
parser = commandlist.(nodotext).parser;
cstartdir = canonicalize_file_name (origdir);
cenddir = canonicalize_file_name (directory);
needmove = commandlist.(nodotext).move && ...
(~ strcmp(cstartdir, cenddir));
else
warning ("unpack:filetype", "unrecognised file type, %s", ext);
files = file;
return;
endif
## create the directory if necessary
s = stat (directory);
if (isempty (s))
[status, msg] = mkdir (directory);
if (! status)
error ("unpack: mkdir failed to create %s: %s", directory, msg);
endif
elseif (! S_ISDIR (s.mode))
error ("unpack: %s: not a directory", directory);
endif
unwind_protect
cd (directory);
[status, output] = system (sprintf ([command " 2>&1"], file));
cd (origdir);
unwind_protect_cleanup
cd (origdir);
end_unwind_protect
if status
error ("unpack: unarchiving program exited with status: %d\n%s", ...
status, output);
endif
## trim the last cr if needed
## FIXME: will this need to change to a check for "\r\n" for windows?
if (output(length (output)) == "\n")
output(length (output)) = [];
endif
files = parser (cellstr (split (output, "\n")))';
## move files if necessary
if needmove
[st, msg, msgid] = movefile (files, directory);
if ~ st
error ("unpack: unable to move files to \"%s\": %s", ...
directory, msg);
endif
## fix the names for the files since they were moved.
for i = 1:numel (files)
files{i} = strrep (files{i}, cstartdir, cenddir);
endfor
endif
## return output if requested
if (nargout > 0)
varargout{1} = files;
endif
endfunction
function files = __parse_zip__ (output)
## parse the output from zip and unzip
for i = 1:length (output)
files{i} = output{i}(14:length(output{i}));
endfor
endfunction
## this is a noop, but it makes things simpler for other cases
function output = __parse_tar__ (output)
endfunction
function files = __parse_gzip__ (output)
## parse the output from gzip and gunzip returning the files
## commpressed (or decompressed)
files = {};
## the middle ": " should indicate a good place to start looking for
## the filename
for i = 1:length (output)
colons = strfind(output{i}, ":");
if isempty (colons)
warning ("unpack:parsing", "Unable to parse line (gzip missing
colon):\n%s", output{i})
else
midcolon = colons(ceil (length (colons)/2));
thisstr = output{i}(midcolon+2:length(output{i}));
idx = index (thisstr, "with") + 5;
if isempty (idx)
warning ("unpack:parsing", "Unable to parse line (gzip missing
with):\n%s", output{i});
else
files{i} = thisstr(idx:length (thisstr));
endif
endif
endfor
endfunction
function files = __parse_bzip2__ (output)
## parse the output from bzip2 and bunzip2 returning the files
## commpressed (or decompressed)
files = {};
for i = 1:length (output)
## the -5 is to remove the ".bz2:"
endoffilename = rindex (output{i}, ": ") - 5;
if isempty(endoffilename)
warning("unpack:parsing", "Unable to parse line:\n%s", output{i});
else
files{i} = output{i}(3:endoffilename);
endif
endfor
endfunction
Index: copyfile.m
===================================================================
RCS file: /cvs/octave/scripts/miscellaneous/copyfile.m,v
retrieving revision 1.1
diff -u -r1.1 copyfile.m
--- copyfile.m 10 Oct 2006 19:13:49 -0000 1.1
+++ copyfile.m 20 Oct 2006 22:34:48 -0000
@@ -42,7 +42,15 @@
else
cmd = "/bin/cp -r";
endif
- [err, msg] = system (sprintf ("%s %s %s", cmd, f1, f2));
+
+ ## allow cell input and protect the file name(s)
+ if iscellstr(f1)
+ f1 = sprintf("\"%s\" ", f1{:});
+ else
+ f1 = sprintf("\"%s\" ", f1);
+ endif
+
+ [err, msg] = system (sprintf ("%s %s \"%s\"", cmd, f1, f2));
if (err < 0)
status = false;
msgid = "copyfile";
Index: movefile.m
===================================================================
RCS file: /cvs/octave/scripts/miscellaneous/movefile.m,v
retrieving revision 1.1
diff -u -r1.1 movefile.m
--- movefile.m 10 Oct 2006 19:13:49 -0000 1.1
+++ movefile.m 20 Oct 2006 22:34:48 -0000
@@ -42,7 +42,15 @@
else
cmd = "/bin/mv";
endif
- [err, msg] = system (sprintf ("%s %s %s", cmd, f1, f2));
+
+ ## allow cell input and protect the file name(s)
+ if iscellstr(f1)
+ f1 = sprintf("\"%s\" ", f1{:});
+ else
+ f1 = sprintf("\"%s\" ", f1);
+ endif
+
+ [err, msg] = system (sprintf ("%s %s \"%s\"", cmd, f1, f2));
if (err < 0)
status = false;
msgid = "movefile";
- untar.m on Solaris with non-GNU tar, John Swensen, 2006/10/20
- Re: untar.m on Solaris with non-GNU tar,
Bill Denney <=
- Re: untar.m on Solaris with non-GNU tar, John W. Eaton, 2006/10/20
- Re: untar.m on Solaris with non-GNU tar, Bill Denney, 2006/10/20
- Re: untar.m on Solaris with non-GNU tar, Bill Denney, 2006/10/20
- Re: untar.m on Solaris with non-GNU tar, John W. Eaton, 2006/10/20
- Re: untar.m on Solaris with non-GNU tar, Bill Denney, 2006/10/20
- Re: untar.m on Solaris with non-GNU tar, John W. Eaton, 2006/10/24
- Re: untar.m on Solaris with non-GNU tar, Bill Denney, 2006/10/24
- Re: untar.m on Solaris with non-GNU tar, John W. Eaton, 2006/10/24