portalfsとFUSEで独自ファイルシステムを実装しよう

以下のテキストは、執筆時当時の情報を元に書いたものであり、 現在の情勢にそぐわないことを含む場合があるので注意されたい。 また、テキストは最終提出原稿で校正を経る前のものなので、実際にOSM 本誌に記載されたものとは異なる。誤字脱字等そのままである。

致命的な誤り以外は加筆修正等は行なわないので情報の鮮度に気をつけつつ 利用して欲しい。

目次


======================================================================
Part4: portalfs��FUSE����������������������������������
======================================================================


��
����������������������������������
��

������������������������������������������������������������������������
������������������������������������������������������������������������
��������������������������������������������������������������������
Part4 portalfs �� FUSE��������������������������������������������������
������������������������������������������������������������������������
��������������������������������������3����������������������������������
������������������ kernel hacker ����������������������:-)

	* ��������(portalfs+����������������)
	  ������������������portalfs������������������������������������
	  ��������������������������������������������������������������
	  ������

	* ��������(portalfs+C��������+Ruby����������)
	  portalfs������������������������������������������������������
	  ��������������������������������������������������������������
	  ����C������������������������������������

	* ��������(FUSE+Ruby����������)
	  FUSE����������������������������������������������������������
	  ����������(f)open()��readdir()��(f)stat()����������������������
	  ��������������������������������������������������������

��
���������� - portalfs+����������������������
��

��������������������������������������������

Web��������HTML������������������������������������HTML����������������
��������������������������������������������������������CGI��SSI��PHP��
������������������������������������Web��������������������������������
����������������������Web����������������������������������������������
������������������������������������������FTP��������������������������
������

portalfs������������������������������������������������CGI��������������
��������������Web��������������������������������������������������������
��������������������������������������������������������������������������
����������������������������FreeBSD/NetBSD���������������� portalfs ����
��������������������������������

FreeBSD�������� /usr/share/examples/portal ����NetBSD��������
/usr/share/examples/mount_portal ������������ portal.conf ��������������
��������������portalfs�� /p ������������������

	# cp /usr/share/examples/*portal/portal.conf /etc
	# mount_portalfs /etc/portal.conf /p

������������������������������������������������

������������������������������������������������������������������������
����������������������������������������������������������
��������������
http://www.ageun.com/daily/furtune.html
���������������������������������������������������������������������� ������
---[�� ��]------------------------------------------------------------
��������������Web������������������������������������
/usr/games/foretune ����������������������
----------------------------------------------------------------------

������������������12������������������01��12����������id��������������
CGI����������������������������

������ http://www.ageun.com/cgi-bin/dairy2/index.cgi?id=01
������ http://www.ageun.com/cgi-bin/dairy2/index.cgi?id=02
	:
	:
����   http://www.ageun.com/cgi-bin/dairy2/index.cgi?id=12

������URL������������������������������������������Web������������������
������������w3m������������ ��������������

---[�� ��]------------------------------------------------------------
http://w3m.sourceforge.net/index.ja.html
FreeBSD ports ����/usr/ports/www/w3m-m17n-img
NetBSD pkgsrc ����/usr/pkgsrc/www/w3m-m17n �� make install ������
������������������������������
----------------------------------------------------------------------

������������������������������������������������������������������������
����������������portalfs����PATH��������������

������������������������

w3m��-dump������������������������������������������ ������������������
������������ /usr/local/bin/getzodf ������������������������������������
��������������

---[������ ��]--------------------------------------------------------
[ /usr/local/bin/getzodf ]

#!/bin/sh
PATH=/usr/local/bin:/usr/pkg/bin:$PATH
CGI=http://www.ageun.com/cgi-bin/dairy2/index.cgi
id=01
case "$1" in
  oh*|ar*)	id=01 ;;
  ou*|ta*)	id=02 ;;
  fu*|ge*)	id=03 ;;
  ka*|can*)	id=04 ;;
  sh*|si*|le*)	id=05 ;;
  ot*|v*)	id=06 ;;
  te*|li*)	id=07 ;;
  sas*|sc*)	id=08 ;;
  i*|sag*)	id=09 ;;
  y*|cap*)	id=10 ;;
  m*|aq*)	id=11 ;;
  u*|p*)	id=12 ;;
  [1-9]|[12][0-9]) id=$1 ;;
esac
w3m -dump "$CGI?id=$id" | colrm 1 14
----------------------------------------------------------------------

��������������������������1��������������������������������������������
����������������������������������������������������

��:	% getzodf uoza			# ����������

  * FreeBSD portalfs pipe ����������������

    pipe������������������������������������������������������������������
    ����������������������������������������
    /p/pipe"/usr/local/bin/getzodf uoza"
    ��������������������������������������������������������������������
    ����

	% ln -s /p/pipe"/usr/local/bin/getzodf uoza" .uoza

    ����������������������������

  * NetBSD portalfs rfilter ����������������

    rfilter��������������������portal.conf������������������������������
    ������FreeBSD��pipe��������������������������������������������������
    ������������������������������������������������������
    /etc/portal.conf ����������������������

	/zodiac		rfilter /zodiac /usr/local/bin/getzodf %s

    �������� portal.conf �� /p ������������������

	# umount /p
	# mount_portal /etc/portal.conf /p

    ��������������������������(��������getzodf����������)��������������
    ��������������������������

	% cat /p/zodiac/uo

������������

������������������������������������������������������������������������
������������������������������������������������������������������������
����������������������������������������������������������������������

��������������������JPG��������������������������������������������������
��������������������������������������portalfs��������������������������
������������������������������������������������������������������������
����������������������������������������������(signature)����������������
������������������������������������������������������������������������
����������������������������portalfs������������������������������������
������������������������

������������������������������������������������������������������������
����


��
���������� portalfs����������
��

��������FreeBSD��mount_potalfs����������������������

-----------------------------------------------------------------��������
# cd /usr/src/usr.sbin/mount_portalfs
# ls -l *.[ch]
-rw-r--r--  1 root  wheel  4911 May 11  2005 activate.c
-rw-r--r--  1 root  wheel  7259 Aug  7  2004 conf.c
-rw-r--r--  1 root  wheel  2543 Mar 11  2005 cred.c
-rw-r--r--  1 root  wheel  6440 Mar 11  2005 mount_portalfs.c
-rw-r--r--  1 root  wheel  1935 Aug  7  2004 pathnames.h
-rw-r--r--  1 root  wheel  3149 Mar 11  2005 portald.h
-rw-r--r--  1 root  wheel  2111 Mar 11  2005 pt_conf.c
-rw-r--r--  1 root  wheel  2081 Aug  7  2004 pt_exec.c
-rw-r--r--  1 root  wheel  2950 May 20  2005 pt_file.c
-rw-r--r--  1 root  wheel  5777 Mar 11  2005 pt_pipe.c
-rw-r--r--  1 root  wheel  4226 Aug  7  2004 pt_tcp.c
-rw-r--r--  1 root  wheel  6816 Aug  7  2004 pt_tcplisten.c
-----------------------------------------------------------------��������
(��NetBSD�������� /usr/src/sbin/mount_portal)

portal.conf������������������(fs, pipe, tcp, tcplisten)������������������
��������C������������������������������������������������������5000����
������������������������������������������������������������������������
����������������TCP����������������������������������������������������
����������������������������������������TCP����������������������������
����������������

	FILE *fp;
	fp = fopen("file", "r");

��������������������������������������������������������������������������
��������������������������������

	* FreeBSD��portalfs��������������������
	* ������������������������������������
	  NetBSD����������rfilter������(pt_filter.c)��������������
	* rfilter������������������������������������������������������
	  ��������(rfilter��wfilter��������)

��������������������

	* ������������������������������������������������������������������
	* ������������������������������������������������������

����������������������ftp������������������������������������WebDAV������
RDB��������������������������������������������������������������������
���������������������������������������������������������� ������

---[�� ��]------------------------------------------------------------
����������������������������read/write����������(stat����)����������������
��������������������������������������
----------------------------------------------------------------------

��������������������������������������

	1. NetBSD�� pt_filter.c ��FreeBSD��������������������������
	2. rfilter����������������������(wfilter������������������)
	3. FreeBSD�� pt_conf.c �� rfilter ������������������
	4. ����������������������������������������������

������������������������������������

��1��FreeBSD����������NetBSD��pt_filter.c��������

����FreeBSD���������� /usr/src ���������������������������������� ������
������������������������������������������������������������NetBSD��
mount_portal ����������������������

---[�� ��]------------------------------------------------------------
sysinstall����Configure �� Distributions �� src(Sources for everything)
��������������������������
----------------------------------------------------------------------

% cvs -d :pserver:anoncvs@sup.jp.netbsd.org:/cvs/cvsroot login
(�������������� anoncvs ������)

% cvs -d :pserver:anoncvs@sup.jp.netbsd.org:/cvs/cvsroot \
	co -r netbsd-3 src/sbin/mount_portal

% cd src/sbin/mount_portal

������������pt_filter.c ��FreeBSD��������
/usr/src/usr.sbin/mount_portalfs ��������������

% su		(��������������������)
# cp -i pt_filter.c /usr/src/usr.sbin/mount_portalfs

��2��rfilter��������������wfilter������

���������� NetBSD��pt_filter.c ��������������rfilter��������wfilter������
��������������������������������������������������������������wfilter����
������������ portal_wfilter() ���������������� ��������������

---[�� ��]------------------------------------------------------------
�������� wfilter ������������������������������������������������������
����������������
----------------------------------------------------------------------

��������������������������������������������������������������

# cd /usr/src/usr.sbin/mount_portalfs
# vi +/portal_wfilter/-1 pt_filter.c

  (int portal_wfilter����������������������������������������
   ���������� dG ������������������������������)

������������������������������������������������������rfilter����������
������������rwfilter������������������vi����������������������

	:%s/rfilter/rwfilter/w [Return]

������������������

������������������������������������������������������������������
��/popen[Return]��������������popen������������������������������������

	fp = popen(cmd, "r");

���������������������� "r" ������������������������ "w+" ����������

	fp = popen(cmd, "w+");

���������������� :wq [Return] ����������������

��3��pt_conf.c �� rfilter ������������������

pt_conf.c ������������������������ ������������������������������������
������������
---[������ ��]--------------------------------------------------------
provider providers[] = {
        { "exec",       portal_exec },
        { "file",       portal_file },
        { "pipe",       portal_pipe },
        { "tcp",        portal_tcp },
        { "tcplisten",  portal_tcplisten },
        { 0, 0 }
};
----------------------------------------------------------------------

tcplisten������������������rwfilter �������������������� ������

---[������ ��]--------------------------------------------------------
��pt_conf.c ����������������


provider providers[] = {
        { "exec",       portal_exec },
        { "file",       portal_file },
        { "pipe",       portal_pipe },
        { "tcp",        portal_tcp },
        { "tcplisten",  portal_tcplisten },
        { "rwfilter",   portal_rwfilter },
        { 0, 0 }
};
----------------------------------------------------------------------

������������������������������������������������������������ portald.h
�������������� portal_rwfilter() ��������������������������������������
tcplisten������������������������������������ ������

---[������ ��]--------------------------------------------------------
��portald.h����������

extern int portal_rwfilter(struct portal_cred *,
                                char *key, char **v, int so, int *fdp);
----------------------------------------------------------------------

��4������������������������������������������������

Makefile�� pt_filter.c �������������� ������������������������������

---[������ ��]--------------------------------------------------------
��Makfile����������

SRCS=   mount_portalfs.c activate.c conf.c cred.c getmntopts.c pt_conf.c \
        pt_exec.c pt_file.c pt_pipe.c pt_tcp.c pt_tcplisten.c pt_filter.c
		  	    	      	       		     ------------
							������������
----------------------------------------------------------------------

��������������������������������������������

----------------------------------------------------------------------��������
pt_filter.o(.text+0x10): In function `portal_rwfilter':
: undefined reference to `lose_credentials'
*** Error code 1

Stop in /usr/src/usr.sbin/mount_portalfs.
----------------------------------------------------------------------��������

������������������������������������������ user_credential ��������
NetBSD��FreeBSD����������������FreeBSD������ pt_pipe.c ������������������
����������������������������������������������������������������������
�������� ����������������������������(��������������������������CD-ROM��
����������)��

---[������ ��]--------------------------------------------------------
--- pt_filter.c.orig    Sat Aug 12 19:38:48 2006
+++ pt_filter.c Sat Aug 12 19:47:26 2006
@@ -91,13 +91,14 @@
        char   *path;
        FILE   *fp;
        int     error = 0;
+       struct portal_cred save_area;
 
        /* We don't use this parameter. */
        (void) kso;
 
-       error = lose_credentials(pcr);
-       if (error != 0)
-               return error;
+       /* Swap priviledges. */
+       if (set_user_credentials(pcr, &save_area) < 0)
+               return (errno);
 
 #ifdef DEBUG
        fprintf(stderr, "rwfilter:  Got key %s\n", key);
@@ -162,6 +163,9 @@
                        }
                }
        }
+       /* Re-establish our priviledges. */
+       if (restore_credentials(&save_area) < 0)
+               error = errno;
        if (error == 0)
                fdp[0] = fileno(fp);
        return (errno);
----------------------------------------------------------------------


������������������make ��������������������������������portalfs��������
������������

# make all install

������rwfilter��ZIP����������������������������������������

Windows XP����ZIP��������������������������������������������������������
������������������������������������ZIP����������������������������������
����������(����������������)����������������������������������rwfilter��
����������������������������������������������

����������

	/p/zip/foo/bar.zip/baz
	��������������open����������������������������������
	/foo/bar.zip ���������������� baz ��������������������

	������������open��������������������������������
	/foo/bar.zip ���������������� baz ������������������

��������������������������������������������/etc/portal.conf ����������
����������������������������

	zip/	rwfilter zip/	������������������ %s

��������������������������������������������������������������������������
�������������������� /p/zip/ ������������������������������������
/p/zip/foo/bar.zip/baz �������������������� foo/bar.zip/baz ������������
������������������������������

����������������������������������������

	��������������������������������(dirname)��ZIP��������������������
	��������������(basename)������������������������������������������
	����������������������������������������������������������������
	��������������

������������������������������������������������������������Ruby��������
������������������ ������������

---[������ ��]--------------------------------------------------------
��/usr/local/bin/pzipio.rb��

#!/usr/local/bin/ruby

exit if Process.euid == 0	# root��������������:)
target="/"+ARGV[0]		# ������/������
zipname=File.dirname(target)
filename=File.basename(target)
ENV["PATH"] = "/bin:/usr/bin:/usr/local/bin"
TMPDIR=ENV["TMPDIR"] || "/tmp"
trial=10

r = IO.select([STDIN], [STDIN], nil, nil)
if r[0][0]		# STDIN����������������������
  tmpdir=nil		# ������������
  while trial > 0
    f=sprintf("%s/%s.%s.%d", TMPDIR, "pzipio", $$, trial-=1)
    begin		# ������������������������
      Dir.mkdir(f, 0700)# raise ERROR if exists
      tmpdir=f
      break
    rescue
      next
    end
  end
  if tmpdir && test(?d, tmpdir) && test(?w, tmpdir)
    Dir.chdir(tmpdir){|dir|
      open(filename, "w") do |out| # STDIN������������������
	out.print STDIN.readlines  # ����������������������
      end
      system("zip #{zipname} #{filename} > /dev/null")
    }
    File.unlink(tmpdir+"/"+filename)
    Dir.rmdir(tmpdir)	# ����������������������������������
  end
else			# ZIP������������������������
  if filename == ".list"	# .list ����������������������
    system("unzip -v #{zipname}")
  else				# ����������������������������
    system("unzip -cqq #{zipname} #{filename}")
  end
end
----------------------------------------------------------------------

���������������� /usr/local/bin/pzipio.rb ��������������������
�������������������� /etc/portal.conf ������������������������������


---[������ ��]--------------------------------------------------------
��/etc/portal.conf����������1����

	zip/	rwfilter zip/	/usr/local/bin/portal.conf %s
----------------------------------------------------------------------

/p ������������������

# umount /p
# mount_portalfs /etc/portal.conf /p


��rwfilter/ZIP��������������������������������

ZIP���������������������������� portalfs ��������������������������������
������������������������������������������������������������������������
������������������������������������ZIP��������������������������

----------------------------------------------------------------------��������
% mkdir /tmp/ziptest
% cd /tmp/ziptest
% jcal
      2006�� ���� 9��       
 ��  ��  ��  ��  ��  ��  �� 
                      1   2 
( 3)  4   5   6   7   8   9 
(10) 11  12  13  14 (15) 16 
(17) 18  19  20  21  22 (23)
(24) 25  26  27  28  29  30 

% jcal > ca
% ls -lF
total 1
-rw-r--r--  1 yuuji  wheel  135 Aug 13 15:18 ca
% zip -m a.zip ca		# (-m��������������������������������)
  adding: ca (deflated 42%)
% ls -lF
total 1
-rw-r--r--  1 yuuji  wheel  271 Aug 13 15:18 a.zip
% unzip -v a
Archive:  a.zip
 Length   Method    Size  Ratio   Date   Time   CRC-32    Name
--------  ------  ------- -----   ----   ----   ------    ----
     232  Defl:N      135  42%  08-13-06 15:18  75f95a44  ca
--------          -------  ---                            -------
     232              135  42%                            1 file
----------------------------------------------------------------------��������

��/tmp/ziptest/a.zip ���� ca ��������������������portalfs��������
/p/zip/tmp/ziptest/a.zip/ca ������������������������������������������������

----------------------------------------------------------------------��������
% cat /p/zip/tmp/ziptest/a.zip/ca
      2006�� ���� 9��       
 ��  ��  ��  ��  ��  ��  �� 
                      1   2 
( 3)  4   5   6   7  =8=  9 
(10) 11  12  13  14 (15) 16 
(17) 18  19  20  21  22 (23)
(24) 25  26  27  28  29  30 
----------------------------------------------------------------------��������

��������������������ca��������������������������������

----------------------------------------------------------------------��������
% uname -a > /p/zip/tmp/ziptest/a.zip/ca
(����������������������������������)
% unzip -cqq a.zip ca
FreeBSD lead.yk.gentei.org 6.1-STABLE FreeBSD 6.1-STABLE #2: Tue Aug  1 14:56:51 JST 2006
yuuji@lead.yk.gentei.org:/usr/src/sys/i386/compile/VMWARE  i386
----------------------------------------------------------------------��������

��������������������������

������������ rzipio.rb ��������������������������������������������������
������������������������������������������������������������������������
������������������������������������������������������������������������
�������������������������������� pt_filter.c ����������������������������
������������������������������������������portalfs����������������������
������������������������������������������������������������������������
������������FUSE������������������������������


��
���������� FUSE����������������������(Linux)
��

FUSE������������������(fuse-2.5.3.tar.gz)������example/ ������������������
������������������������������������C���������������������� hello.c ����

	* ���������������������� hello ������������������������������
	* ����������������������Hello World!��

��������������������������������������������FUSE������������������������
�������������������������������������������� struct fuse_operations ����
����FUSE��API����������������������������������������������������������
��������������fuse.h �� fuse_operations ��������������������������������
��������������������������������

����������C��������������������������������������������������������������
������������������������������������������������������������������C������
������������������FUSE��Ruby��������������������������������������������
��������������Ruby������������������������������������������������������
����������������������Ruby��������������������������Ruby 1.8��������������
��������Ruby����������������������������1.8.4��������������������������

---[�� ��]------------------------------------------------------------
���������������������������������� ruby ������������ruby-devel ��������
���������� fuse-devel ����������������������������������
----------------------------------------------------------------------

FUSE��Ruby����������������
http://rubyforge.org/projects/fusefs
������������������������������������������������������
fusefs-0.6.0.tar.gz ����������������������������������������������������
��������������


% tar fusefs-0.6.0.tar.gz
% cd fusefs-0.6.0
% ruby setup.rb config
% ruby setup.rb setup
% sudo ruby setup.rb install

��������FUSEFS������������Ruby������������������������������������������
������������������������������������ruby setup.rb setup������������������
�������������������������������������������������� libfuse.so ����������
������������������������������������������������������ruby setup.rb
config������������ ext/Makefile ������������������������

	% vi "+/^LIBS" Makefile
--------------------------------------------------------------��������������
LIBS =  -lfuse  -ldl -lcrypt -lm   -lc -Wl,-R/usr/local/lib -L/usr/local/lib
     		     	     	      --------------------------------------
				������������
--------------------------------------------------------------��������������

���������� libfuse.so �� /usr/local/lib ��������������������������������
������������������������������������������������������������������������

��������������������������������������������������sample/ ��������������
����Ruby����������������������

----------------------------------------------------------------------��������
% cd sample
% mkdir hellotest
% ruby hello.rb hellotest &
% ls -lF hellotest
���� 0
-r--r--r--    1 yuuji    yuuji           0 Aug 13 08:18 hello.txt
% cat hellotest/hello.txt
Hello, World!
----------------------------------------------------------------------��������

�������������� hello.rb ������������������������

--------------------------------------------------------------��������
% kill %ruby
--------------------------------------------------------------��������

��Ruby/fusefs ��������������������������������

	!!!����!!!
	Ruby/fusefs ������API.txt��������������������������fusefs��������
	������FUSE����������������������������������������������FUSE������
	������������������������ruby������������ kill -KILL ��������������
	������ fusermount -u ����������������������������������


������������������������������������������������������������������������
������������������������������������FUSE������hello.c��������������������
������������������������������������������������������������������������
��������������������������������������������������������������

	* ��������������������������������
	* �������������������������������� Sunday, Monday, ...,
	   Saturday ��7��
	* ��������������������������������������������������������

��������������������������������
----------------------------------------------------------------------��������
% weekfs.rb ~/week &
% ls week
Friday  Monday  Saturday  Sunday  Thursday  Tuesday  Wednesday
% cat week/Friday
������
----------------------------------------------------------------------��������

Ruby/fusefs ������������������������������������������������������������
Ruby/fusefs �������������������� sample/hello.rb �� API.txt ����������������
����������

	* ���������������������������������������� contents ��������
	* ���������������������������������������� file? ��������
	* ������������������������ read_file ��������

����������������

* contents��������
  Friday Monday Saturday Sunday Thursday Tuesday Wednesday
  ��7������������������������������������������
  def contents(path)
    %w(Friday Monday Saturday Sunday Thursday Tuesday Wednesday)
  end
  ��������

* file?��������
  file?����������������������������������������������������������������
  ��������������Sunday���������������������� "/Sunday" ����������������
  ����������������������(/)����������������7����������������������������
  ��������������������
  def file?(path)
    path = path[1..-1]  # ������1��������������
    %w(Friday Monday Saturday Sunday Thursday Tuesday Wednesday).index(path)
  end
  ��������������index��������������������������������������������������
  ����������������������������������������������nil������������������

* read_file��������
  ��������7������������������������������������������������������������
  def read_file(path)
    jwday = %w(������ ������ ������ ������ ������ ������ ������)
    ix = file?(path)	# ��������������������������
    jwday[ix] if ix	# ��������������������������������
  end

������������������7����������������������������������������������������
������Ruby���������������������������������������������� initialize ����
������������������������������������������������ ������������

---[������ ��]--------------------------------------------------------
#!/usr/bin/env ruby
# EUC������������

require 'fusefs'

class WeekDir
  def initialize
    # 7��������������������������
    @wday = %w(Sunday Monday Tuesday Wednesday Thursday Friday Saturday)
    @jwday = %w(������ ������ ������ ������ ������ ������ ������)
  end
  def contents(path)
    @wday
  end

  def file?(path)
    path = path[1..-1]
    @wday.index(path)
  end

  def read_file(path)
    ix = file?(path)
    @jwday[ix] if ix
  end

  def size(path)
    c = read_file(path)
    c ? c.length : 0
  end
end

weekdir = WeekDir.new
FuseFS.set_root( weekdir )

# Mount under a directory given on the command line.
FuseFS.mount_under ARGV.shift
FuseFS.run
----------------------------------------------------------------------


������������������

portalfs������������������������������������������������������������������
��������������������������������FUSE������������������������������������
������������������������������������ls����������������������������������
������������FUSE������������������������������������������������������
����������������unpackfs��http://www.nongnu.org/unpackfs/ ��������������
������������������������������������������������������������������������
������������������������������������������������������������������������
��������������������������������������������������������������������������
����

��������������FUSE-API��������������������������������������������������
��������������������������������������acvfs����Ruby/fusefs����������������
Ruby��������������������������������������������������������������������
������������������������������������������������������������������������
���������������������������������������������� ����������(����CD-ROM����
����)��

---[�� ��]------------------------------------------------------------
#!/usr/bin/env ruby
#
# acvfs.rb: Archive FileSystem Based on FUSE/Ruby
# (C)2006 by HIROSE, Yuuji [yuuji@yatex.org]
#
# Usage: acvfs.rb mountpoint
#
# This file system provides zip/tar.gz/tar.bz2 auto inspection.
#
# Requirements:
# http://fuse.sourceforge.net/ - Filesystem in Userspace
# http://rubyforge.org/projects/fusefs - Ruby binding of FUSE-FS
#
# Todo:
#  Support other archivers than arc, arj, rar, ... and so on.
#  But it might be easy.  Try it by yourself.
#
require 'fusefs'

class ArchiveDir
  def initialize
    @cachedacv = Hash.new
  end
  def zip?(path)
    /\.zip/i =~ path
  end
  def targz?(path)
    /\.(tar\.gz|tgz)/i =~ path
  end
  def tarbz2?(path)
    /\.(tar\.bz2|tbz)/i =~ path
  end
  def acv?(path)  # path is archived file or within it, or not
    zip?(path) || targz?(path) || tarbz2(path)
  end
  def acvfile?(path) # path IS archived file, or not
    /\.(zip|tar\.(gz|bz2))$/i =~ path
  end
  def listcmd(arc)
    # Return the array of [ListingCmd, Regexp, [$size, $name], EndRattern]
    if zip?(arc)
      ["| unzip -v \"#{arc}\" | tail +4",
        /(\d+) +(\d+)% +(\d+)-(\d+)-(\d+) +(\d\d):(\d\d) .* (\S+)$/,
        [1, 8],
        /^---/]
    elsif targz?(arc)||tarbz2?(arc)
      c = targz?(arc) ? "z" : "j"
      ["| tar v#{c}tf \"#{arc}\"",
        /(\d+) +(\d{4})-(\d+)-(\d+) +(\d\d):(\d\d):(\d\d) +(\S+)$/,
        [1, 8],
        /^$/]
    end
  end

  # cache all filenames, sizes and whether they are directory
  def acvinfo(acv)
    %r,(.*\.(zip|tar\.(gz|bz2)))(/(.*))?, =~ acv
    dir = $1
    prefix = $5
    if !@cachedacv[acv]
      @cachedacv[acv] = Hash.new
      listinfo = listcmd(dir)
      open(listinfo[0], "r") do |zls|
        while line = zls.gets
          case line
          when listinfo[3]
            break
          when listinfo[1]
            md = Regexp.last_match
            dirp = nil          # is_directory flag
            name = md[listinfo[2][1]]
            if prefix
              next unless name.index(prefix) == 0
              next if name == prefix
              name.sub!(prefix+"/", "") # strip prefix directory
            end
            next if name == ""     # skip prefix dir itself
            next if %r,/., =~ name # skip files in subdirectory
            if %r,/$, =~ name
              name.chop!
              dirp = true
            end
            @cachedacv[acv][name] = Hash.new
            @cachedacv[acv][name]['dir'] = dirp
            @cachedacv[acv][name]['size'] = md[listinfo[2][0]].to_i
            # p ["set", acv, name, dir, md[listinfo[2][0]].to_i, dirp]
          end
        end
      end
    end
    @cachedacv[acv]
  end
  # Return the list of files in directory: path
  def contents(path)
    mntpt=ARGV[0].gsub(%r|/+|, "/")
    if test(?d, path)
      Dir.entries(path).select{|f|
        n = (path+"/"+f).gsub(%r|/+|, "/")
        next if ARGV[0] == n
        test(?d, n) || test(?f, n) && acvfile?(f)
      }
    elsif acv?(path)
      acvinfo(path).keys
    end
  end

  def file?(path)
    test(?f, path) ||
      if acv?(path)
        acv = File.dirname(path)
        file = File.basename(path)
        acvinfo(acv).has_key?(file) && !acvinfo(acv)[file]['dir']
      end

  end
  def executable?(path)
    test(?d, path) ? test(x, path) : false # shoud be safer
  end
  def directory?(path)
    test(?d, path) || acvfile?(path) ||
      if acv?(path)
        acv = File.dirname(path)
        file = File.basename(path)
        acvinfo(acv)[file]['dir']
      end
  end
  def can_write?(path)
    false
  end

  def read_file(path)
    %r,(.*\.(tar\.(gz|bz2)|zip))(/(.*))?, =~ path
    acv, file = $1, $5
    if acv && file
      cmd = if zip?(acv)
              "unzip -cqq \"#{acv}\" \"#{file}\""
            elsif targz?(acv)
              "tar zxOf \"#{acv}\" \"#{file}\""
            elsif tarbz2?(acv)
              "tar jxOf \"#{acv}\" \"#{file}\""
            end
      IO.popen(cmd, "r").read
    else
      "Not an archived file\n"
    end
  end

  def size(path)
    acv = File.dirname(path)
    file = File.basename(path)
    if acv?(acv)
      acvinfo(acv)[file]['size']
    else
      test(?s, path)
    end
  end
end

adir = ArchiveDir.new
FuseFS.set_root( adir )

# Mount under a directory given on the command line.
FuseFS.mount_under ARGV[0]
FuseFS.run
----------------------------------------------------------------------

acvfs.rb ����������������������������������������������������������������
������������������

	* ����������������������
	* ��������������������������������������
	* zip��tar.gz������������������������������������
	  ��������������������������������������������������������������
	  ��������

������������������������������acvfs.rb�� on demand ��zip��tar����������
����������������������������������

acvfs.rb ������������/z ������������������������������������������������
����FedoraCore 5��������������������

----------------------------------------------------------------------��������
cb1{yuuji}% sudo mkdir /z
cb1{yuuji}% sudo chown yuuji /z
cb1{yuuji}% ./acvfs.rb /z &		(����������������������)

cb1{yuuji}% mount -t fuse
/dev/fuse on /z type fuse (rw,nosuid,nodev,user=yuuji)
cb1{yuuji}% ls -F /z
bin/   etc/   lost+found/  misc/  opt/   sbin/     sys/  var/
boot/  home/  media/       mnt/   proc/  selinux/  tmp/
dev/   lib/   memory/      net/   root/  srv/      usr/

(���� / ������������������)

cb1{yuuji}% ls -F /z/home/yuuji/make
fusefs-0.6.0/  fusefs-0.6.0.tar.gz/  gmail/  python/

(fusefs-0.6.0.tar.gz ����������������������������)

cb1{yuuji}% ls -F /home/yuuji/make
acvfs.rb*  fusefs-0.6.0/  fusefs-0.6.0.tar.gz  gmail/  python/
(������ ~/make ����������������3����������������2��������)

cb1{yuuji}% ls -F /z/home/yuuji/make/fusefs-0.6.0.tar.gz
fusefs-0.6.0/

cb1{yuuji}% ls -F /z/home/yuuji/make/fusefs-0.6.0.tar.gz/fusefs-0.6.0
API.txt    Changes.txt  README.txt  ext/      lib/     setup.rb
COPYRIGHT  Makefile     TODO        foo.yaml  sample/
----------------------------------------------------------------------��������

����������������������������������������������

---[�� ��]------------------------------------------------------------
%image acvfs-onFC5.png
----------------------------------------------------------------------
fusefs-0.6.0.tar.gz ����������������������������������


��
��������
��

OS����������������������������������������������������������������������
��������������������������������������������������������������������������
��������������������������������������������������������������������������
������������������������������������������������������������������������
��������������������������������������������������������������

---[�� ��]------------------------------------------------------------
----------------------------------------------------------------------


yuuji@example.org
Fingerprint16 = FF F9 FF CC E0 FE 5C F7 19 97 28 24 EC 5D 39 BA
HIROSE Yuuji - ASTROLOGY / BIKE / EPO / GUEST BOOK / YaTeX
[Tweet]