拡張子gzを付けないとgzip(gunzip)コマンドで解凍できない


testファイルを作成して、gzipコマンドで圧縮すると、test.gzが作成されます。  
このtest.gzを拡張子を外した名前(test)に変更すると、gzipコマンドやgunzipコマンドで  
解凍することができないのですが、なぜでしょうか。

gunzip -S .gz test




ソースコード上では以下の様になっていて、gzip によって圧縮されたファイルに所定の拡張子(`".gz", ".z", ".taz", ".tgz",
"-gz", "-z", "_z"` のいずれか)が付いていない場合は復元処理を行いません。

**gzip-1.6/gzip.c**

[code]

    /* ========================================================================
     * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
     * Sets save_orig_name to true if the file name has been truncated.
     */
    local int make_ofname()
    {
        char *suff;            /* ofname z suffix */
    
        strcpy(ofname, ifname);
        /* strip a version number if any and get the gzip suffix if present: */
        suff = get_suffix(ofname);
    
        if (decompress) {
            if (suff == NULL) {
                /* With -t or -l, try all files (even without .gz suffix)
                 * except with -r (behave as with just -dr).
                 */
                if (!recursive && (list || test)) return OK;
    
                /* Avoid annoying messages with -r */
                if (verbose || (!recursive && !quiet)) {
                    WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
                          program_name, ifname));
                }
                return WARNING;
            }
    
[/code]

一方で、gzip の ChangeLog に以下の様な記述があります。

> Mon Jun 14 10:03:24 1993 Jean-loup Gailly (jloup@chorus.fr)
>
> * version 1.2  
>  Allow gunzip --suffix "" to attempt decompression on any file regardless of
> its extension if an original name is present.
>
> 2010-02-22 Jim Meyering
>
> gzip: fix a data-loss bug when decompressing with --suffix=''  
>  * gzip.c (main): Disallow an empty --suffix=S also with -d. Otherwise,
> "gzip -d -S '' F.gz" would ask if it's ok to remove the existing file,
> "F.gz"; if you reply "yes", you'd lose all of that data. Use of an empty
> suffix was already rejected in compression mode.

つまり、gzip 1.4 までは、

[code]

    $ gzip -d -S '' test
    
[/code]

とすれば復元処理を行うのですが、その前に対象ファイルを削除してしまう、という事です。実際に gzip 1.4 をコンパイルして試してみます。

[code]

    $ echo 'Hello World' > test
    $ gzip-1.4 test
    $ mv test.gz test
    $ ls -l test
    -rw-r--r-- 1 nemo nemo 37 Nov 28 24:00 test
    $ gzip-1.4 -d -S '' test
    gzip: test already exists; do you wish to overwrite (y or n)? 
    
[/code]

ここで `y` を入力してしまうと、確かにファイル `test` は消失してしまいます。

[code]

    $ ls -l test
    ls: cannot access test: No such file or directory
    
[/code]

ところで、名前(パス)が異なれば問題はないはずです。

[code]

    $ echo 'Hello World' > test
    $ gzip-1.4 test
    $ mv test.gz test2
    $ ls -l test*
    -rw-r--r-- 1 nemo nemo 37 Nov 28 24:00 test2
    $ gzip-1.4 -N -d -S '' test2
    $ ls -l test*
    -rw-r--r-- 1 nemo nemo 37 Nov 28 24:00 test
    $ cat test
    Hello World
    
[/code]

もっとも、これでは意味がないですし、gzip 1.6 ではエラーになってしまいますので、やはり拡張子は付けるべきという事なのでしょう。

番外編として、[moreutils](https://joeyh.name/code/moreutils/) に含まれる `sponge` コマンドを使った
in place な復元方法を紹介しておきます。

[code]

    $ echo 'Hello World' > test
    $ gzip test
    $ mv test.gz test
    $ gunzip -c test | sponge test
    $ cat test
    Hello World
    
[/code]

`sponge` という名前から、何をしているのか分かるかと思います。




ソースコード上では以下の様になっていて、gzip によって圧縮されたファイルに所定の拡張子(`".gz", ".z", ".taz", ".tgz",
"-gz", "-z", "_z"` のいずれか)が付いていない場合は復元処理を行いません。

**gzip-1.6/gzip.c**

[code]

    /* ========================================================================
     * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
     * Sets save_orig_name to true if the file name has been truncated.
     */
    local int make_ofname()
    {
        char *suff;            /* ofname z suffix */
    
        strcpy(ofname, ifname);
        /* strip a version number if any and get the gzip suffix if present: */
        suff = get_suffix(ofname);
    
        if (decompress) {
            if (suff == NULL) {
                /* With -t or -l, try all files (even without .gz suffix)
                 * except with -r (behave as with just -dr).
                 */
                if (!recursive && (list || test)) return OK;
    
                /* Avoid annoying messages with -r */
                if (verbose || (!recursive && !quiet)) {
                    WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
                          program_name, ifname));
                }
                return WARNING;
            }
    
[/code]

一方で、gzip の ChangeLog に以下の様な記述があります。

> Mon Jun 14 10:03:24 1993 Jean-loup Gailly (jloup@chorus.fr)
>
> * version 1.2  
>  Allow gunzip --suffix "" to attempt decompression on any file regardless of
> its extension if an original name is present.
>
> 2010-02-22 Jim Meyering
>
> gzip: fix a data-loss bug when decompressing with --suffix=''  
>  * gzip.c (main): Disallow an empty --suffix=S also with -d. Otherwise,
> "gzip -d -S '' F.gz" would ask if it's ok to remove the existing file,
> "F.gz"; if you reply "yes", you'd lose all of that data. Use of an empty
> suffix was already rejected in compression mode.

つまり、gzip 1.4 までは、

[code]

    $ gzip -d -S '' test
    
[/code]

とすれば復元処理を行うのですが、その前に対象ファイルを削除してしまう、という事です。実際に gzip 1.4 をコンパイルして試してみます。

[code]

    $ echo 'Hello World' > test
    $ gzip-1.4 test
    $ mv test.gz test
    $ ls -l test
    -rw-r--r-- 1 nemo nemo 37 Nov 28 24:00 test
    $ gzip-1.4 -d -S '' test
    gzip: test already exists; do you wish to overwrite (y or n)? 
    
[/code]

ここで `y` を入力してしまうと、確かにファイル `test` は消失してしまいます。

[code]

    $ ls -l test
    ls: cannot access test: No such file or directory
    
[/code]

ところで、名前(パス)が異なれば問題はないはずです。

[code]

    $ echo 'Hello World' > test
    $ gzip-1.4 test
    $ mv test.gz test2
    $ ls -l test*
    -rw-r--r-- 1 nemo nemo 37 Nov 28 24:00 test2
    $ gzip-1.4 -N -d -S '' test2
    $ ls -l test*
    -rw-r--r-- 1 nemo nemo 37 Nov 28 24:00 test
    $ cat test
    Hello World
    
[/code]

もっとも、これでは意味がないですし、gzip 1.6 ではエラーになってしまいますので、やはり拡張子は付けるべきという事なのでしょう。

番外編として、[moreutils](https://joeyh.name/code/moreutils/) に含まれる `sponge` コマンドを使った
in place な復元方法を紹介しておきます。

[code]

    $ echo 'Hello World' > test
    $ gzip test
    $ mv test.gz test
    $ gunzip -c test | sponge test
    $ cat test
    Hello World
    
[/code]

`sponge` という名前から、何をしているのか分かるかと思います。

