Beispiel #1
0
/**
 * Opens a file from inside a tar archive.
 * @param entry The entry to open.
 * @param filesize [out] If not \c NULL, size of the opened file.
 * @return File handle of the opened file, or \c NULL if the file is not available.
 * @note The file is read from within the tar file, and may not return \c EOF after reading the whole file.
 */

        public static FileStream FioFOpenFileTar(TarFileListEntry entry, out long filesize)
        {
            filesize = 0;
            try
            {
                var f = new FileStream(entry.tar_filename, FileMode.Open);
                if (f.Seek(entry.position, SeekOrigin.Begin) < 0)
                {
                    f.Close();
                    return(null);
                }

                filesize = entry.size;
                return(f);
            }
            catch (IOException e)
            {
                Log.Error(e);
                return(null);
            }
        }
Beispiel #2
0
        public override bool AddFile(string filename, string tar_filename = null)
        {
            /* No tar within tar. */
            Debug.Assert(tar_filename == null);

            /* The TAR-header, repeated for every file */


            /* Check if we already seen this file */
            if (FileIO._tar_list[(int)this.subdir].TryGetValue(filename, out var it) == false)
            {
                return(false);
            }

            var links = new Dictionary <string, string>();

            try
            {
                using (var f = new FileInfo(filename).OpenRead())
                {
                    FileIO._tar_list[(int)this.subdir][filename].filename = filename;
                    FileIO._tar_list[(int)this.subdir][filename].dirname  = null;
                    var dupped_filename = filename;
                    /// Temporary list to collect links

                    string name = null; //char[sizeof(th.prefix) + 1 + sizeof(th.name) + 1];
                    string link = null; //char link[sizeof(th.linkname) + 1];
                    string dest = null;
                    //char dest[sizeof(th.prefix) + 1 + sizeof(th.name) + 1 + 1 + sizeof(th.linkname) + 1];
                    var num = 0;
                    var pos = 0;


                    var buffer = new byte[TarHeader.HeaderSize];
                    for (;;)
                    {
                        // Note: feof() always returns 'false' after 'fseek()'. Cool, isn't it?
                        var num_bytes_read = f.Read(buffer, 1, TarHeader.HeaderSize);
                        if (num_bytes_read != TarHeader.HeaderSize)
                        {
                            break;
                        }
                        pos += num_bytes_read;

                        var th = new TarHeader(buffer);

                        /* Check if we have the new tar-format (ustar) or the old one (a lot of zeros after 'link' field) */
                        if (th.magic != "ustar" && th.magic != "")
                        {
                            /* If we have only zeros in the block, it can be an end-of-file indicator */
                            if (buffer.Any(b => b != 0))
                            {
                                continue;
                            }

                            Log.Debug($"The file '{filename}' isn't a valid tar-file");
                            f.Close();
                            return(false);
                        }

                        name = null;

                        /* The prefix contains the directory-name */
                        if (th.prefix != "")
                        {
                            name = th.prefix + Path.PathSeparator;
                        }

                        /* Copy the name of the file in a safe way at the end of 'name' */
                        name += th.name;

                        switch (th.typeflag)
                        {
                        case '\0':
                        case '0':
                        {
                            // regular file
                            /* Ignore empty files */
                            if (th.size == 0)
                            {
                                break;
                            }

                            if (name.Length == 0)
                            {
                                break;
                            }

                            /* Store this entry in the list */
                            var entry = new TarFileListEntry()
                            {
                                tar_filename = dupped_filename,
                                size         = th.size,
                                position     = pos
                            };

                            /* Convert to lowercase and our PATHSEPCHAR */
                            name = FileIO.SimplifyFileName(name);

                            Log.Debug($"Found file in tar: ${name} ({th.size} bytes, {pos} offset)");
                            if (FileIO._tar_filelist[(int)this.subdir].ContainsKey(name) == false)
                            {
                                FileIO._tar_filelist[(int)this.subdir].Add(name, entry);
                                num++;
                            }

                            break;
                        }

                        case '1':     // hard links
                        case '2':
                        {
                            // symbolic links
                            /* Copy the destination of the link in a safe way at the end of 'linkname' */
                            link = th.linkname;

                            if (name.Length == 0 || link.Length == 0)
                            {
                                break;
                            }

                            /* Convert to lowercase and our PATHSEPCHAR */
                            name = FileIO.SimplifyFileName(name);
                            link = FileIO.SimplifyFileName(link);

                            /* Only allow relative links */
                            if (link[0] == Path.PathSeparator)
                            {
                                Log.Debug($"Ignoring absolute link in tar: {name} . {link}");
                                break;
                            }

                            /* Process relative path.
                             * Note: The destination of links must not contain any directory-links. */
                            dest = name;
                            //var destIndex = dest.LastIndexOf(Path.PathSeparator);
                            var destpos = dest;
                            //if (destIndex >= 0)
                            //{
                            //    destpos = dest.Substring(destIndex + 1);
                            //}

                            //TODO THIS MAKES NO SENSE
                            var linkParts = link.Split(Path.PathSeparator);
                            foreach (var linkPart in linkParts)
                            {
                                if (linkPart == ".")
                                {
                                    /* Skip '.' (current dir) */
                                }
                                else if (linkPart == "..")
                                {
                                    /* level up */
                                    if (dest == "")
                                    {
                                        Log.Debug(
                                            $"Ignoring link pointing outside of data directory: {name} . {link}");
                                        break;
                                    }

                                    /* Truncate 'dest' after last PATHSEPCHAR.
                                     * This assumes that the truncated part is a real directory and not a link. */
                                    destpos = linkParts.Last();
                                    break;
                                }
                                else
                                {
                                    /* Append at end of 'dest' */
                                    if (destpos.Any())
                                    {
                                        destpos += Path.PathSeparator;
                                    }
                                    destpos = dest;
                                }

                                //if (destpos >= lastof(dest)) {
                                //	Log.Debug("The length of a link in tar-file '{filename}' is too large (malformed?)");
                                //	f.Close();
                                //	return false;
                                //}
                            }

                            /* Store links in temporary list */
                            Log.Debug($"Found link in tar: {name} . {dest}");
                            links.Add(name, dest);

                            break;
                        }

                        case '5':     // directory
                            /* Convert to lowercase and our PATHSEPCHAR */
                            name = FileIO.SimplifyFileName(name);

                            /* Store the first directory name we detect */
                            Log.Debug($"Found dir in tar: {name}");
                            if (FileIO._tar_list[(int)this.subdir][filename].dirname == null)
                            {
                                FileIO._tar_list[(int)this.subdir][filename].dirname = name;
                            }
                            break;

                        default:
                            /* Ignore other types */
                            break;
                        }

                        /* Skip to the next block.. */
                        //var skip = Align(th.size, 512);
                        if (f.Seek(th.size, SeekOrigin.Current) < 0)
                        {
                            Log.Debug($"The file '{filename}' can't be read as a valid tar-file");
                            f.Close();
                            return(false);
                        }
                        pos += th.size;
                    }

                    Log.Debug($"Found tar '{filename}' with {num} new files");
                    f.Close();
                }
            }
            catch (IOException ex)
            {
                /* Although the file has been found there can be
                 * a number of reasons we cannot open the file.
                 * Most common case is when we simply have not
                 * been given read access. */
                Log.Error(ex);
                return(false);
            }



            /* Resolve file links and store directory links.
             * We restrict usage of links to two cases:
             *  1) Links to directories:
             *      Both the source path and the destination path must NOT contain any further links.
             *      When resolving files at most one directory link is resolved.
             *  2) Links to files:
             *      The destination path must NOT contain any links.
             *      The source path may contain one directory link.
             */
            foreach (var link in links)
            {
                var src  = link.Key;
                var dest = link.Value;
                FileIO.TarAddLink(src, dest, this.subdir);
            }

            return(true);
        }