1999-01-18 02:10:53 +03:00
/* Directory cache support -- so that you do not have copy of this in
1998-10-23 12:26:25 +04:00
* each and every filesystem .
*
* Written at 1998 by Pavel Machek < pavel @ ucw . cz > , distribute under LGPL .
*
1999-12-16 15:55:16 +03:00
* $ Id $
*
1998-12-09 23:22:53 +03:00
* Very loosely based on tar . c from midnight and archives . [ ch ] from
* avfs by Miklos Szeredi ( mszeredi @ inf . bme . hu )
1998-11-21 22:36:01 +03:00
*
* Unfortunately , I was unable to keep all filesystems
* uniform . tar - like filesystems use tree structure where each
* directory has pointers to its subdirectories . We can do this
* because we have full information about our archive .
*
* At ftp - like filesystems , situation is a little bit different . When
* you cd / usr / src / linux / drivers / char , you do _not_ want / usr ,
* / usr / src , / usr / src / linux and / usr / src / linux / drivers to be
* listed . That means that we do not have complete information , and if
* / usr is symlink to / 4 , we will not know . Also we have to time out
* entries and things would get messy with tree - like approach . So we
* do different trick : root directory is completely special and
* completely fake , it contains entries such as ' usr ' , ' usr / src ' , . . . ,
* and we ' ll try to use custom find_entry function .
*
* Paths here do _not_ begin with ' / ' , so root directory of
* archive / site is simply " " . Beware . */
static volatile int total_inodes = 0 , total_entries = 0 ;
1998-10-23 12:26:25 +04:00
1999-01-21 01:01:11 +03:00
# include "utilvfs.h"
1998-10-24 00:18:48 +04:00
# include "xdirentry.h"
1999-02-14 00:39:18 +03:00
# include "../src/tty.h"
1998-10-23 12:26:25 +04:00
# define CALL(x) if (MEDATA->x) MEDATA->x
1999-01-18 02:10:05 +03:00
vfs_s_inode *
vfs_s_new_inode ( vfs * me , vfs_s_super * super , struct stat * initstat )
1998-10-23 12:26:25 +04:00
{
vfs_s_inode * ino ;
2000-04-28 11:43:13 +04:00
ino = g_new0 ( vfs_s_inode , 1 ) ;
1999-01-11 03:48:23 +03:00
if ( ! ino )
return NULL ;
1998-10-23 12:26:25 +04:00
if ( initstat )
ino - > st = * initstat ;
1998-11-21 22:36:01 +03:00
ino - > super = super ;
1998-12-28 13:27:07 +03:00
ino - > st . st_ino = MEDATA - > inode_counter + + ;
ino - > st . st_dev = MEDATA - > rdev ;
1998-10-23 12:26:25 +04:00
1998-12-31 18:54:49 +03:00
super - > ino_usage + + ;
1998-11-21 22:36:01 +03:00
total_inodes + + ;
1999-01-18 02:10:05 +03:00
CALL ( init_inode ) ( me , ino ) ;
1998-10-23 12:26:25 +04:00
return ino ;
}
1999-01-18 02:10:05 +03:00
vfs_s_entry *
vfs_s_new_entry ( vfs * me , char * name , vfs_s_inode * inode )
1998-10-23 12:26:25 +04:00
{
vfs_s_entry * entry ;
2000-04-28 11:43:13 +04:00
entry = g_new0 ( struct vfs_s_entry , 1 ) ;
1998-11-21 22:36:01 +03:00
total_entries + + ;
1998-10-23 12:26:25 +04:00
1998-11-21 22:36:01 +03:00
if ( name )
1999-01-21 01:01:11 +03:00
entry - > name = g_strdup ( name ) ;
2000-04-28 11:43:13 +04:00
1998-10-23 12:26:25 +04:00
entry - > ino = inode ;
1998-11-21 22:36:01 +03:00
entry - > ino - > ent = entry ;
1999-01-18 02:10:05 +03:00
CALL ( init_entry ) ( me , entry ) ;
1998-10-23 12:26:25 +04:00
return entry ;
}
1999-01-18 02:10:05 +03:00
void
vfs_s_free_inode ( vfs * me , vfs_s_inode * ino )
1998-10-23 12:26:25 +04:00
{
1999-01-11 03:48:23 +03:00
if ( ! ino )
vfs_die ( " Don't pass NULL to me " ) ;
1998-10-23 12:26:25 +04:00
1998-11-21 22:36:01 +03:00
/* ==0 can happen if freshly created entry is deleted */
1999-01-18 02:10:05 +03:00
if ( ino - > st . st_nlink < = 1 ) {
while ( ino - > subdir ) {
1998-11-21 22:36:01 +03:00
vfs_s_entry * ent ;
ent = ino - > subdir ;
1999-01-18 02:10:05 +03:00
vfs_s_free_entry ( me , ent ) ;
1998-11-21 22:36:01 +03:00
}
1998-10-23 12:26:25 +04:00
1999-01-18 02:10:05 +03:00
CALL ( free_inode ) ( me , ino ) ;
ifree ( ino - > linkname ) ;
if ( ino - > localname ) {
unlink ( ino - > localname ) ;
1999-01-21 01:01:11 +03:00
g_free ( ino - > localname ) ;
1998-11-21 22:36:01 +03:00
}
total_inodes - - ;
1998-12-31 18:54:49 +03:00
ino - > super - > ino_usage - - ;
1999-01-21 01:01:11 +03:00
g_free ( ino ) ;
1998-11-21 22:36:01 +03:00
} else ino - > st . st_nlink - - ;
1998-10-23 12:26:25 +04:00
}
1999-01-18 02:10:05 +03:00
void
vfs_s_free_entry ( vfs * me , vfs_s_entry * ent )
1998-10-23 12:26:25 +04:00
{
1998-11-21 22:36:01 +03:00
int is_dot = 0 ;
1999-01-18 02:10:05 +03:00
if ( ent - > prevp ) { /* It is possible that we are deleting freshly created entry */
1998-11-21 22:36:01 +03:00
* ent - > prevp = ent - > next ;
1999-01-11 03:48:23 +03:00
if ( ent - > next )
ent - > next - > prevp = ent - > prevp ;
1998-11-21 22:36:01 +03:00
}
1998-10-23 12:26:25 +04:00
1999-01-18 02:10:05 +03:00
if ( ent - > name ) {
is_dot = ( ! strcmp ( ent - > name , " . " ) ) | | ( ! strcmp ( ent - > name , " .. " ) ) ;
1999-01-21 01:01:11 +03:00
g_free ( ent - > name ) ;
1998-11-21 22:36:01 +03:00
ent - > name = NULL ;
}
1999-01-18 02:10:05 +03:00
if ( ! is_dot & & ent - > ino ) {
1998-11-21 22:36:01 +03:00
ent - > ino - > ent = NULL ;
vfs_s_free_inode ( me , ent - > ino ) ;
ent - > ino = NULL ;
1998-10-23 12:26:25 +04:00
}
1998-11-21 22:36:01 +03:00
total_entries - - ;
1999-01-21 01:01:11 +03:00
g_free ( ent ) ;
1998-10-23 12:26:25 +04:00
}
1999-11-03 17:51:22 +03:00
void
vfs_s_insert_entry ( vfs * me , vfs_s_inode * dir , vfs_s_entry * ent )
1998-10-23 12:26:25 +04:00
{
vfs_s_entry * * ep ;
1999-01-11 03:48:23 +03:00
for ( ep = & dir - > subdir ; * ep ! = NULL ; ep = & ( ( * ep ) - > next ) )
;
1998-10-23 12:26:25 +04:00
ent - > prevp = ep ;
ent - > next = NULL ;
ent - > dir = dir ;
* ep = ent ;
ent - > ino - > st . st_nlink + + ;
}
1999-11-03 17:51:22 +03:00
struct stat *
vfs_s_default_stat ( vfs * me , mode_t mode )
1998-10-23 12:26:25 +04:00
{
static struct stat st ;
int myumask ;
myumask = umask ( 022 ) ;
umask ( myumask ) ;
mode & = ~ myumask ;
st . st_mode = mode ;
1998-12-28 13:27:07 +03:00
st . st_ino = 0 ;
st . st_dev = 0 ;
1998-10-23 12:26:25 +04:00
st . st_rdev = 0 ;
st . st_uid = getuid ( ) ;
st . st_gid = getgid ( ) ;
st . st_size = 0 ;
st . st_mtime = st . st_atime = st . st_ctime = time ( NULL ) ;
return & st ;
}
1999-01-18 02:10:05 +03:00
void
vfs_s_add_dots ( vfs * me , vfs_s_inode * dir , vfs_s_inode * parent )
1998-10-23 12:26:25 +04:00
{
struct vfs_s_entry * dot , * dotdot ;
if ( ! parent )
parent = dir ;
dot = vfs_s_new_entry ( me , " . " , dir ) ;
dotdot = vfs_s_new_entry ( me , " .. " , parent ) ;
1999-01-18 02:10:05 +03:00
vfs_s_insert_entry ( me , dir , dot ) ;
vfs_s_insert_entry ( me , dir , dotdot ) ;
dir - > st . st_nlink - - ;
1999-01-21 01:01:11 +03:00
parent - > st . st_nlink - - ; /* We do not count "." and ".." into nlinks */
1998-10-23 12:26:25 +04:00
}
1999-01-18 02:10:05 +03:00
struct vfs_s_entry *
vfs_s_generate_entry ( vfs * me , char * name , struct vfs_s_inode * parent , mode_t mode )
1998-10-23 12:26:25 +04:00
{
struct vfs_s_inode * inode ;
struct stat * st ;
st = vfs_s_default_stat ( me , mode ) ;
1998-11-21 22:36:01 +03:00
inode = vfs_s_new_inode ( me , parent - > super , st ) ;
1998-10-23 12:26:25 +04:00
if ( S_ISDIR ( mode ) )
vfs_s_add_dots ( me , inode , parent ) ;
2000-01-31 16:48:00 +03:00
return vfs_s_new_entry ( me , name , inode ) ;
1998-10-23 12:26:25 +04:00
}
1998-11-21 22:36:01 +03:00
/* We were asked to create entries automagically */
1999-01-18 02:10:05 +03:00
vfs_s_entry *
vfs_s_automake ( vfs * me , vfs_s_inode * dir , char * path , int flags )
1998-10-23 12:26:25 +04:00
{
struct vfs_s_entry * res ;
1999-01-18 02:10:05 +03:00
char * sep = strchr ( path , PATH_SEP ) ;
if ( sep )
* sep = 0 ;
res = vfs_s_generate_entry ( me , path , dir , flags & FL_MKDIR ? ( 0777 | S_IFDIR ) : 0777 ) ;
vfs_s_insert_entry ( me , dir , res ) ;
if ( sep )
* sep = PATH_SEP ;
1998-10-23 12:26:25 +04:00
return res ;
}
1999-01-18 02:10:05 +03:00
/*
* Follow > 0 : follow links , serves as loop protect ,
* = = - 1 : do not follow links
*/
vfs_s_entry *
vfs_s_find_entry_tree ( vfs * me , vfs_s_inode * root , char * path , int follow , int flags )
1998-10-23 12:26:25 +04:00
{
unsigned int pseg ;
1999-01-17 14:46:42 +03:00
vfs_s_entry * ent = NULL ;
1999-01-17 15:33:45 +03:00
char p [ MC_MAXPATHLEN ] = " " ;
1998-10-23 12:26:25 +04:00
2000-04-28 11:43:13 +04:00
while ( root ) {
1999-01-17 15:33:45 +03:00
int t ;
1999-01-18 02:10:05 +03:00
2000-04-28 11:43:13 +04:00
while ( * path = = PATH_SEP ) /* Strip leading '/' */
path + + ;
if ( ! path [ 0 ] )
1999-01-17 13:07:37 +03:00
return ent ;
1998-10-23 12:26:25 +04:00
1999-01-18 02:10:05 +03:00
for ( pseg = 0 ; path [ pseg ] & & path [ pseg ] ! = PATH_SEP ; pseg + + )
;
1998-10-23 12:26:25 +04:00
1999-01-18 02:10:05 +03:00
strcat ( p , PATH_SEP_STR ) ;
strncpy ( p + ( t = strlen ( p ) ) , path , pseg ) ;
1999-01-17 15:33:45 +03:00
p [ t + pseg ] = ' \0 ' ;
1999-01-18 02:10:05 +03:00
for ( ent = root - > subdir ; ent ! = NULL ; ent = ent - > next )
if ( strlen ( ent - > name ) = = pseg & & ( ! strncmp ( ent - > name , path , pseg ) ) )
1998-10-23 12:26:25 +04:00
/* FOUND! */
break ;
if ( ! ent & & ( flags & ( FL_MKFILE | FL_MKDIR ) ) )
1999-01-18 02:10:05 +03:00
ent = vfs_s_automake ( me , root , path , flags ) ;
1998-10-23 12:26:25 +04:00
if ( ! ent ) ERRNOR ( ENOENT , NULL ) ;
path + = pseg ;
1999-01-17 15:33:45 +03:00
/* here we must follow leading directories always; only the actual file is optional */
1999-01-18 02:10:05 +03:00
if ( ! ( ent = vfs_s_resolve_symlink ( me , ent , p , strchr ( path , PATH_SEP ) ? LINK_FOLLOW : follow ) ) )
1999-01-17 13:07:37 +03:00
return NULL ;
1998-10-23 12:26:25 +04:00
root = ent - > ino ;
}
2000-04-28 11:43:13 +04:00
return NULL ;
1998-10-23 12:26:25 +04:00
}
1999-01-18 02:10:05 +03:00
static void
split_dir_name ( vfs * me , char * path , char * * dir , char * * name , char * * save )
1998-11-21 22:36:01 +03:00
{
char * s ;
1999-01-18 02:10:05 +03:00
s = strrchr ( path , PATH_SEP ) ;
if ( ! s ) {
1998-11-21 22:36:01 +03:00
* save = NULL ;
* name = path ;
* dir = " " ;
} else {
* save = s ;
* dir = path ;
* s + + = 0 ;
2000-04-28 11:43:13 +04:00
* name = s ;
1998-11-21 22:36:01 +03:00
}
}
1999-01-18 02:10:05 +03:00
vfs_s_entry *
vfs_s_find_entry_linear ( vfs * me , vfs_s_inode * root , char * path , int follow , int flags )
1998-11-21 22:36:01 +03:00
{
vfs_s_entry * ent = NULL ;
1999-11-03 17:51:22 +03:00
if ( root - > super - > root ! = root )
vfs_die ( " We have to use _real_ root. Always. Sorry. " ) ;
1999-01-18 02:10:05 +03:00
if ( ! ( flags & FL_DIR ) ) {
1998-11-21 22:36:01 +03:00
char * dirname , * name , * save ;
vfs_s_inode * ino ;
1999-01-18 02:10:05 +03:00
split_dir_name ( me , path , & dirname , & name , & save ) ;
ino = vfs_s_find_inode ( me , root , dirname , follow , flags | FL_DIR ) ;
1998-11-21 22:36:01 +03:00
if ( save )
1999-01-18 02:10:05 +03:00
* save = PATH_SEP ;
2000-01-31 16:48:00 +03:00
return vfs_s_find_entry_tree ( me , ino , name , follow , flags ) ;
1998-11-21 22:36:01 +03:00
}
1999-01-18 02:10:05 +03:00
for ( ent = root - > subdir ; ent ! = NULL ; ent = ent - > next )
if ( ! strcmp ( ent - > name , path ) )
1998-11-21 22:36:01 +03:00
break ;
1999-01-18 02:10:05 +03:00
if ( ent & & ( ! ( MEDATA - > dir_uptodate ) ( me , ent - > ino ) ) ) {
1998-12-09 23:22:53 +03:00
# if 1
1999-12-16 15:55:16 +03:00
print_vfs_message ( _ ( " Dir cache expired for %s " ) , path ) ;
1998-11-21 22:36:01 +03:00
# endif
vfs_s_free_entry ( me , ent ) ;
1999-11-03 17:51:22 +03:00
ent = NULL ;
1998-11-21 22:36:01 +03:00
}
1999-01-18 02:10:05 +03:00
if ( ! ent ) {
1998-11-21 22:36:01 +03:00
vfs_s_inode * ino ;
1999-01-18 02:10:05 +03:00
ino = vfs_s_new_inode ( me , root - > super , vfs_s_default_stat ( me , S_IFDIR | 0755 ) ) ;
ent = vfs_s_new_entry ( me , path , ino ) ;
if ( ( MEDATA - > dir_load ) ( me , ino , path ) = = - 1 ) {
vfs_s_free_entry ( me , ent ) ;
1998-11-21 22:36:01 +03:00
return NULL ;
}
1999-01-18 02:10:05 +03:00
vfs_s_insert_entry ( me , root , ent ) ;
1998-11-21 22:36:01 +03:00
1999-01-18 02:10:05 +03:00
for ( ent = root - > subdir ; ent ! = NULL ; ent = ent - > next )
if ( ! strcmp ( ent - > name , path ) )
1998-11-21 22:36:01 +03:00
break ;
}
if ( ! ent )
1999-01-18 02:10:05 +03:00
vfs_die ( " find_linear: success but directory is not there \n " ) ;
1998-11-21 22:36:01 +03:00
#if 0
1999-01-18 02:10:05 +03:00
if ( ! vfs_s_resolve_symlink ( me , ent , follow ) ) return NULL ;
1998-11-21 22:36:01 +03:00
# endif
return ent ;
}
1999-01-18 02:10:05 +03:00
vfs_s_inode *
vfs_s_find_inode ( vfs * me , vfs_s_inode * root , char * path , int follow , int flags )
1998-10-23 12:26:25 +04:00
{
vfs_s_entry * ent ;
1998-11-21 22:36:01 +03:00
if ( ( MEDATA - > find_entry = = vfs_s_find_entry_tree ) & & ( ! * path ) )
1998-10-23 12:26:25 +04:00
return root ;
1998-11-21 22:36:01 +03:00
ent = ( MEDATA - > find_entry ) ( me , root , path , follow , flags ) ;
1998-10-23 12:26:25 +04:00
if ( ! ent )
return NULL ;
return ent - > ino ;
}
1999-11-03 17:51:22 +03:00
/* Ouch - vfs_s_resolve symlink does not work for filesystems like ftp & fish:
you may not lookup with some other root ! */
1999-01-18 02:10:05 +03:00
vfs_s_entry *
vfs_s_resolve_symlink ( vfs * me , vfs_s_entry * entry , char * path , int follow )
1998-10-23 12:26:25 +04:00
{
1999-11-03 17:51:22 +03:00
char buf [ MC_MAXPATHLEN ] , * linkname ;
1998-12-02 16:17:24 +03:00
if ( follow = = LINK_NO_FOLLOW )
1998-10-23 12:26:25 +04:00
return entry ;
if ( follow = = 0 )
ERRNOR ( ELOOP , NULL ) ;
if ( ! entry )
ERRNOR ( ENOENT , NULL ) ;
1999-01-18 02:10:05 +03:00
if ( ! S_ISLNK ( entry - > ino - > st . st_mode ) )
1998-10-23 12:26:25 +04:00
return entry ;
1999-11-03 17:51:22 +03:00
linkname = entry - > ino - > linkname ;
2000-01-31 16:48:00 +03:00
if ( linkname = = NULL )
ERRNOR ( EFAULT , NULL ) ;
1999-11-03 17:51:22 +03:00
if ( MEDATA - > find_entry = = vfs_s_find_entry_linear ) {
if ( * linkname = = PATH_SEP )
return ( MEDATA - > find_entry ) ( me , entry - > dir - > super - > root , linkname , follow - 1 , 0 ) ;
else { /* FIXME: this does not work */
2000-04-05 17:08:42 +04:00
char * fullpath = vfs_s_fullpath ( me , entry - > dir ) ;
sprintf ( buf , " %s/%s " , fullpath , linkname ) ;
g_free ( fullpath ) ;
1999-11-03 17:51:22 +03:00
return ( MEDATA - > find_entry ) ( me , entry - > dir - > super - > root , buf , follow - 1 , 0 ) ;
}
}
/* Convert absolute paths to relative ones */
if ( * linkname = = PATH_SEP ) {
char * p , * q ;
1999-01-17 15:33:45 +03:00
for ( p = path , q = entry - > ino - > linkname ; * p = = * q ; p + + , q + + ) ;
1999-01-18 02:10:05 +03:00
while ( * ( - - q ) ! = PATH_SEP ) ;
1999-01-17 13:07:37 +03:00
q + + ;
1999-01-18 02:10:05 +03:00
for ( ; ; p + + ) {
p = strchr ( p , PATH_SEP ) ;
if ( ! p ) {
1999-11-03 17:51:22 +03:00
strcat ( buf , q ) ;
1999-01-17 13:07:37 +03:00
break ;
}
1999-11-03 17:51:22 +03:00
strcat ( buf , " .. " ) ;
strcat ( buf , PATH_SEP_STR ) ;
1999-01-17 13:07:37 +03:00
}
1999-11-03 17:51:22 +03:00
linkname = buf ;
1999-01-17 13:07:37 +03:00
}
1999-11-03 17:51:22 +03:00
return ( MEDATA - > find_entry ) ( me , entry - > dir , linkname , follow - 1 , 0 ) ;
1998-10-23 12:26:25 +04:00
}
/* Ook, these were functions around direcory entries / inodes */
/* -------------------------------- superblock games -------------------------- */
1999-01-18 02:10:05 +03:00
vfs_s_super *
vfs_s_new_super ( vfs * me )
1998-10-23 12:26:25 +04:00
{
vfs_s_super * super ;
1999-01-21 01:01:11 +03:00
super = g_new0 ( struct vfs_s_super , 1 ) ;
1998-10-23 12:26:25 +04:00
super - > me = me ;
1998-12-02 08:11:48 +03:00
return super ;
1998-11-21 22:36:01 +03:00
}
1998-10-23 12:26:25 +04:00
1999-01-18 02:10:05 +03:00
void
vfs_s_insert_super ( vfs * me , vfs_s_super * super )
1998-11-21 22:36:01 +03:00
{
1998-10-23 12:26:25 +04:00
super - > next = MEDATA - > supers ;
super - > prevp = & MEDATA - > supers ;
1999-01-18 02:10:05 +03:00
if ( MEDATA - > supers ! = NULL )
MEDATA - > supers - > prevp = & super - > next ;
1998-10-23 12:26:25 +04:00
MEDATA - > supers = super ;
}
1999-01-18 02:10:05 +03:00
void
vfs_s_free_super ( vfs * me , vfs_s_super * super )
1998-10-23 12:26:25 +04:00
{
1999-01-18 02:10:05 +03:00
if ( super - > root ) {
1998-11-21 22:36:01 +03:00
vfs_s_free_inode ( me , super - > root ) ;
super - > root = NULL ;
}
1998-10-23 12:26:25 +04:00
1999-12-08 14:39:14 +03:00
#if 0
1999-12-16 15:55:16 +03:00
/* FIXME: We currently leak small ammount of memory, sometimes. Fix it if you can. */
1998-12-31 18:54:49 +03:00
if ( super - > ino_usage )
1999-12-16 15:55:16 +03:00
message_1s1d ( 1 , _ ( " Direntry warning " ) , _ ( " Super ino_usage is %d, memory leak " ) , super - > ino_usage ) ;
1998-12-09 23:22:53 +03:00
if ( super - > want_stale )
1999-12-16 15:55:16 +03:00
message_1s ( 1 , _ ( " Direntry warning " ) , _ ( " Super has want_stale set " ) ) ;
1998-11-21 22:36:01 +03:00
# endif
1999-01-18 02:10:05 +03:00
if ( super - > prevp ) {
1998-11-21 22:36:01 +03:00
* super - > prevp = super - > next ;
1999-01-18 02:10:05 +03:00
if ( super - > next )
super - > next - > prevp = super - > prevp ;
1998-11-21 22:36:01 +03:00
}
1998-10-23 12:26:25 +04:00
1999-01-18 02:10:05 +03:00
CALL ( free_archive ) ( me , super ) ;
ifree ( super - > name ) ;
1998-11-21 22:36:01 +03:00
super - > name = NULL ;
1999-01-21 01:01:11 +03:00
g_free ( super ) ;
1998-10-23 12:26:25 +04:00
}
1998-11-21 22:36:01 +03:00
/* ------------------------------------------------------------------------= */
1998-10-23 12:26:25 +04:00
1999-01-18 02:10:05 +03:00
static void
vfs_s_stamp_me ( vfs * me , struct vfs_s_super * psup , char * fs_name )
1998-10-23 12:26:25 +04:00
{
struct vfs_stamping * parent ;
vfs * v ;
v = vfs_type ( fs_name ) ;
1999-01-18 02:10:05 +03:00
if ( v = = & vfs_local_ops ) {
1998-10-23 12:26:25 +04:00
parent = NULL ;
} else {
1999-01-21 01:01:11 +03:00
parent = g_new ( struct vfs_stamping , 1 ) ;
1998-10-23 12:26:25 +04:00
parent - > v = v ;
parent - > next = 0 ;
parent - > id = ( * v - > getid ) ( v , fs_name , & ( parent - > parent ) ) ;
}
1999-11-03 17:51:22 +03:00
vfs_add_noncurrent_stamps ( me , ( vfsid ) psup , parent ) ;
1998-10-23 12:26:25 +04:00
vfs_rm_parents ( parent ) ;
}
1999-01-18 02:10:05 +03:00
char *
vfs_s_get_path_mangle ( vfs * me , char * inname , struct vfs_s_super * * archive , int flags )
1998-10-23 12:26:25 +04:00
{
char * local , * op , * archive_name ;
int result = - 1 ;
1998-11-21 22:36:01 +03:00
struct vfs_s_super * super ;
2000-04-28 11:43:13 +04:00
void * cookie = NULL ;
1998-10-23 12:26:25 +04:00
archive_name = inname ;
1999-01-18 02:10:05 +03:00
vfs_split ( inname , & local , & op ) ;
1998-10-23 12:26:25 +04:00
if ( ! local )
local = " " ;
1998-11-21 22:36:01 +03:00
if ( MEDATA - > archive_check )
if ( ! ( cookie = MEDATA - > archive_check ( me , archive_name , op ) ) )
return NULL ;
1998-10-23 12:26:25 +04:00
1999-01-18 02:10:05 +03:00
for ( super = MEDATA - > supers ; super ! = NULL ; super = super - > next ) {
1998-10-23 12:26:25 +04:00
int i ; /* 0 == other, 1 == same, return it, 2 == other but stop scanning */
1999-01-18 02:10:05 +03:00
if ( ( i = MEDATA - > archive_same ( me , super , archive_name , op , cookie ) ) ) {
1998-10-23 12:26:25 +04:00
if ( i = = 1 ) goto return_success ;
else break ;
}
}
1999-01-11 03:48:23 +03:00
if ( flags & FL_NO_OPEN )
ERRNOR ( EIO , NULL ) ;
1998-10-23 12:26:25 +04:00
1998-11-21 22:36:01 +03:00
super = vfs_s_new_super ( me ) ;
result = MEDATA - > open_archive ( me , super , archive_name , op ) ;
1999-01-18 02:10:05 +03:00
if ( result = = - 1 ) {
1998-11-21 22:36:01 +03:00
vfs_s_free_super ( me , super ) ;
1998-10-23 12:26:25 +04:00
ERRNOR ( EIO , NULL ) ;
}
1998-11-21 22:36:01 +03:00
if ( ! super - > name )
1999-01-18 02:10:05 +03:00
vfs_die ( " You have to fill name \n " ) ;
1998-11-21 22:36:01 +03:00
if ( ! super - > root )
1999-01-18 02:10:05 +03:00
vfs_die ( " You have to fill root inode \n " ) ;
1998-10-23 12:26:25 +04:00
1998-11-21 22:36:01 +03:00
vfs_s_insert_super ( me , super ) ;
vfs_s_stamp_me ( me , super , archive_name ) ;
1998-10-23 12:26:25 +04:00
return_success :
1998-11-21 22:36:01 +03:00
* archive = super ;
1998-10-23 12:26:25 +04:00
return local ;
}
1999-01-18 02:10:05 +03:00
char *
vfs_s_get_path ( vfs * me , char * inname , struct vfs_s_super * * archive , int flags )
1998-10-23 12:26:25 +04:00
{
1999-01-21 01:01:11 +03:00
char * buf = g_strdup ( inname ) ;
1999-01-18 02:10:05 +03:00
char * res = vfs_s_get_path_mangle ( me , buf , archive , flags ) ;
1998-10-23 12:26:25 +04:00
if ( res )
2000-01-31 16:48:00 +03:00
res = g_strdup ( res ) ;
1999-01-21 01:01:11 +03:00
g_free ( buf ) ;
2000-01-31 16:48:00 +03:00
return res ;
1998-10-23 12:26:25 +04:00
}
1999-01-18 02:10:05 +03:00
void
vfs_s_invalidate ( vfs * me , vfs_s_super * super )
1998-11-21 22:36:01 +03:00
{
1999-01-18 02:10:05 +03:00
if ( ! super - > want_stale ) {
vfs_s_free_inode ( me , super - > root ) ;
super - > root = vfs_s_new_inode ( me , super , vfs_s_default_stat ( me , S_IFDIR | 0755 ) ) ;
1998-11-21 22:36:01 +03:00
}
}
1999-01-18 02:10:05 +03:00
char *
vfs_s_fullpath ( vfs * me , vfs_s_inode * ino )
{
/* For now, usable only on filesystems with _linear structure */
1998-11-21 22:36:01 +03:00
if ( MEDATA - > find_entry ! = vfs_s_find_entry_linear )
1999-01-18 02:10:05 +03:00
vfs_die ( " Implement me! " ) ;
1999-11-03 17:51:22 +03:00
if ( ! ino - > ent ) /* That must be directory... */
1999-01-18 02:10:05 +03:00
ERRNOR ( EAGAIN , NULL ) ;
1999-11-03 17:51:22 +03:00
if ( ( ! ino - > ent - > dir ) | | ( ! ino - > ent - > dir - > ent ) ) /* It must be directory */
2000-04-05 17:08:42 +04:00
return g_strdup ( ino - > ent - > name ) ;
1999-11-03 17:51:22 +03:00
1999-01-27 03:49:11 +03:00
return g_strconcat ( ino - > ent - > dir - > ent - > name , PATH_SEP_STR ,
1999-01-21 01:01:11 +03:00
ino - > ent - > name , NULL ) ;
1998-11-21 22:36:01 +03:00
}
1998-10-23 12:26:25 +04:00
/* Support of archives */
1998-11-21 22:36:01 +03:00
/* ------------------------ readdir & friends ----------------------------- */
vfs_s_super * vfs_s_super_from_path ( vfs * me , char * name )
{
struct vfs_s_super * super ;
if ( ! vfs_s_get_path_mangle ( me , name , & super , 0 ) )
return NULL ;
return super ;
}
1998-10-23 12:26:25 +04:00
1999-01-18 02:10:05 +03:00
vfs_s_inode *
vfs_s_inode_from_path ( vfs * me , char * name , int flags )
1998-10-23 12:26:25 +04:00
{
struct vfs_s_super * super ;
1998-11-21 22:36:01 +03:00
char * q ;
1998-10-23 12:26:25 +04:00
if ( ! ( q = vfs_s_get_path_mangle ( me , name , & super , 0 ) ) )
return NULL ;
1999-12-16 15:55:16 +03:00
return vfs_s_find_inode ( me , super - > root , q , flags & FL_FOLLOW ? LINK_FOLLOW : LINK_NO_FOLLOW , flags & ~ FL_FOLLOW ) ;
1998-10-23 12:26:25 +04:00
}
1998-11-21 22:36:01 +03:00
struct dirhandle {
vfs_s_entry * cur ;
vfs_s_inode * dir ;
} ;
1999-01-18 02:10:05 +03:00
void *
1999-11-03 17:51:22 +03:00
vfs_s_opendir ( vfs * me , char * dirname )
1998-10-23 12:26:25 +04:00
{
1998-11-21 22:36:01 +03:00
struct vfs_s_inode * dir ;
struct dirhandle * info ;
1998-10-23 12:26:25 +04:00
1998-11-21 22:36:01 +03:00
dir = vfs_s_inode_from_path ( me , dirname , FL_DIR | FL_FOLLOW ) ;
1999-01-11 03:48:23 +03:00
if ( ! dir )
return NULL ;
if ( ! S_ISDIR ( dir - > st . st_mode ) )
ERRNOR ( ENOTDIR , NULL ) ;
1998-10-23 12:26:25 +04:00
1998-11-21 22:36:01 +03:00
dir - > st . st_nlink + + ;
#if 0
if ( ! dir - > subdir ) /* This can actually happen if we allow empty directories */
1999-01-18 02:10:05 +03:00
ERRNOR ( EAGAIN , NULL ) ;
1998-11-21 22:36:01 +03:00
# endif
1999-01-21 01:01:11 +03:00
info = g_new ( struct dirhandle , 1 ) ;
1998-11-21 22:36:01 +03:00
info - > cur = dir - > subdir ;
info - > dir = dir ;
1998-10-23 12:26:25 +04:00
return info ;
}
1999-01-18 02:10:05 +03:00
void *
vfs_s_readdir ( void * data )
1998-10-23 12:26:25 +04:00
{
static struct {
struct dirent dir ;
# ifdef NEED_EXTRA_DIRENT_BUFFER
char extra_buffer [ MC_MAXPATHLEN ] ;
# endif
} dir ;
1998-11-21 22:36:01 +03:00
struct dirhandle * info = ( struct dirhandle * ) data ;
1998-10-23 12:26:25 +04:00
1998-11-21 22:36:01 +03:00
if ( ! ( info - > cur ) )
1998-10-23 12:26:25 +04:00
return NULL ;
1998-11-21 22:36:01 +03:00
if ( info - > cur - > name )
strcpy ( & ( dir . dir . d_name [ 0 ] ) , info - > cur - > name ) ;
else
1999-01-18 02:10:05 +03:00
vfs_die ( " Null in structure-can not happen " ) ;
1999-01-11 03:48:23 +03:00
1998-10-23 12:26:25 +04:00
# ifndef DIRENT_LENGTH_COMPUTED
dir . d_namlen = strlen ( dir . dir . d_name ) ;
# endif
1998-11-21 22:36:01 +03:00
info - > cur = info - > cur - > next ;
1998-10-23 12:26:25 +04:00
return ( void * ) & dir ;
}
1999-01-18 02:10:05 +03:00
int
vfs_s_telldir ( void * data )
1998-10-23 12:26:25 +04:00
{
1998-11-21 22:36:01 +03:00
struct dirhandle * info = ( struct dirhandle * ) data ;
1998-10-23 12:26:25 +04:00
struct vfs_s_entry * cur ;
int num = 0 ;
1998-11-21 22:36:01 +03:00
cur = info - > dir - > subdir ;
1999-01-18 02:10:05 +03:00
while ( cur ! = NULL ) {
1999-01-11 03:48:23 +03:00
if ( cur = = info - > cur )
return num ;
1998-10-23 12:26:25 +04:00
num + + ;
cur = cur - > next ;
}
return - 1 ;
}
1999-01-18 02:10:05 +03:00
void
vfs_s_seekdir ( void * data , int offset )
1998-10-23 12:26:25 +04:00
{
1998-11-21 22:36:01 +03:00
struct dirhandle * info = ( struct dirhandle * ) data ;
1998-10-23 12:26:25 +04:00
int i ;
1998-11-21 22:36:01 +03:00
info - > cur = info - > dir - > subdir ;
1998-10-23 12:26:25 +04:00
for ( i = 0 ; i < offset ; i + + )
1999-01-18 02:10:05 +03:00
vfs_s_readdir ( data ) ;
1998-10-23 12:26:25 +04:00
}
1999-01-18 02:10:05 +03:00
int
vfs_s_closedir ( void * data )
1998-10-23 12:26:25 +04:00
{
1998-11-21 22:36:01 +03:00
struct dirhandle * info = ( struct dirhandle * ) data ;
struct vfs_s_inode * dir = info - > dir ;
1999-01-18 02:10:05 +03:00
vfs_s_free_inode ( dir - > super - > me , dir ) ;
1999-01-21 01:01:11 +03:00
g_free ( data ) ;
1998-10-23 12:26:25 +04:00
return 0 ;
}
1999-01-18 02:10:05 +03:00
int
vfs_s_chdir ( vfs * me , char * path )
1998-10-23 12:26:25 +04:00
{
void * data ;
1999-01-18 02:10:05 +03:00
if ( ! ( data = vfs_s_opendir ( me , path ) ) )
1998-10-23 12:26:25 +04:00
return - 1 ;
1999-01-18 02:10:05 +03:00
vfs_s_closedir ( data ) ;
1998-10-23 12:26:25 +04:00
return 0 ;
}
1998-11-21 22:36:01 +03:00
/* --------------------------- stat and friends ---------------------------- */
1998-10-23 12:26:25 +04:00
1999-01-18 02:10:05 +03:00
static int
vfs_s_internal_stat ( vfs * me , char * path , struct stat * buf , int flag )
1998-10-23 12:26:25 +04:00
{
2000-04-16 23:13:00 +04:00
char * path2 ;
1998-10-23 12:26:25 +04:00
struct vfs_s_inode * ino ;
2000-04-16 23:13:00 +04:00
path2 = g_strdup ( path ) ;
if ( ! ( ino = vfs_s_inode_from_path ( me , path2 , flag ) ) ) {
2000-04-28 11:56:30 +04:00
if ( ( ! path ) | | ( * path ) | | ! ( ino = vfs_s_inode_from_path ( me , path , flag | FL_DIR ) ) ) { /* Seems we have problem: vfs_s_inode_from_path on directories always succeeds. This is *hack* to make / directory of ftp archive statable */
2000-04-16 23:13:00 +04:00
g_free ( path2 ) ;
return - 1 ;
}
}
1998-10-23 12:26:25 +04:00
* buf = ino - > st ;
2000-04-16 23:13:00 +04:00
g_free ( path2 ) ;
1998-10-23 12:26:25 +04:00
return 0 ;
}
1999-01-18 02:10:05 +03:00
int
vfs_s_stat ( vfs * me , char * path , struct stat * buf )
1998-10-23 12:26:25 +04:00
{
return vfs_s_internal_stat ( me , path , buf , FL_FOLLOW ) ;
}
1999-01-18 02:10:05 +03:00
int
vfs_s_lstat ( vfs * me , char * path , struct stat * buf )
1998-10-23 12:26:25 +04:00
{
return vfs_s_internal_stat ( me , path , buf , FL_NONE ) ;
}
1999-01-18 02:10:05 +03:00
int
vfs_s_fstat ( void * fh , struct stat * buf )
1998-10-23 12:26:25 +04:00
{
* buf = FH - > ino - > st ;
return 0 ;
}
1999-01-18 02:10:05 +03:00
int
vfs_s_readlink ( vfs * me , char * path , char * buf , int size )
1998-10-23 12:26:25 +04:00
{
struct vfs_s_inode * ino ;
1999-01-18 02:10:05 +03:00
ino = vfs_s_inode_from_path ( me , path , 0 ) ;
1999-01-11 03:48:23 +03:00
if ( ! ino )
return - 1 ;
1998-10-23 12:26:25 +04:00
1999-01-11 03:48:23 +03:00
if ( ! S_ISLNK ( ino - > st . st_mode ) )
ERRNOR ( EINVAL , - 1 ) ;
2000-01-31 16:48:00 +03:00
if ( ino - > linkname = = NULL )
ERRNOR ( EFAULT , - 1 ) ;
1998-10-23 12:26:25 +04:00
strncpy ( buf , ino - > linkname , size ) ;
* ( buf + size - 1 ) = 0 ;
1999-01-18 02:10:05 +03:00
return strlen ( buf ) ;
1998-10-23 12:26:25 +04:00
}
1999-01-18 02:10:05 +03:00
void *
vfs_s_open ( vfs * me , char * file , int flags , int mode )
1998-10-23 12:26:25 +04:00
{
1998-11-21 22:36:01 +03:00
int was_changed = 0 ;
1998-10-23 12:26:25 +04:00
struct vfs_s_fh * fh ;
vfs_s_super * super ;
char * q ;
struct vfs_s_inode * ino ;
if ( ( q = vfs_s_get_path_mangle ( me , file , & super , 0 ) ) = = NULL )
return NULL ;
1998-12-02 16:17:24 +03:00
ino = vfs_s_find_inode ( me , super - > root , q , LINK_FOLLOW , FL_NONE ) ;
1998-11-21 22:36:01 +03:00
if ( ino & & ( ( flags & ( O_CREAT | O_EXCL ) ) = = ( O_CREAT | O_EXCL ) ) )
ERRNOR ( EEXIST , NULL ) ;
1999-01-18 02:10:05 +03:00
if ( ! ino ) {
1998-11-21 22:36:01 +03:00
char * dirname , * name , * save ;
vfs_s_entry * ent ;
vfs_s_inode * dir ;
if ( ! ( flags & O_CREAT ) )
return NULL ;
1999-01-18 02:10:05 +03:00
split_dir_name ( me , q , & dirname , & name , & save ) ;
1998-12-09 23:22:53 +03:00
/* FIXME: if vfs_s_find_inode returns NULL, this will do rather bad
things . */
1999-01-18 02:10:05 +03:00
dir = vfs_s_find_inode ( me , super - > root , dirname , LINK_FOLLOW , FL_DIR ) ;
1998-11-21 22:36:01 +03:00
if ( save )
1999-01-18 02:10:05 +03:00
* save = PATH_SEP ;
1998-11-21 22:36:01 +03:00
ent = vfs_s_generate_entry ( me , name , dir , 0755 ) ;
ino = ent - > ino ;
1999-01-18 02:10:05 +03:00
vfs_s_insert_entry ( me , dir , ent ) ;
1998-11-21 22:36:01 +03:00
ino - > localname = tempnam ( NULL , me - > name ) ;
was_changed = 1 ;
}
1999-01-11 03:48:23 +03:00
if ( S_ISDIR ( ino - > st . st_mode ) )
ERRNOR ( EISDIR , NULL ) ;
1998-10-23 12:26:25 +04:00
1999-01-21 01:01:11 +03:00
fh = g_new ( struct vfs_s_fh , 1 ) ;
1998-10-23 12:26:25 +04:00
fh - > pos = 0 ;
fh - > ino = ino ;
fh - > handle = - 1 ;
1998-11-21 22:36:01 +03:00
fh - > changed = was_changed ;
fh - > linear = 0 ;
1999-11-03 17:51:22 +03:00
if ( IS_LINEAR ( flags ) ) {
fh - > linear = LS_LINEAR_CLOSED ;
} else if ( ( MEDATA - > fh_open ) & & ( MEDATA - > fh_open ( me , fh , flags , mode ) ) ) {
1999-01-21 01:01:11 +03:00
g_free ( fh ) ;
1998-10-23 12:26:25 +04:00
return NULL ;
}
1999-01-18 02:10:05 +03:00
if ( fh - > ino - > localname ) {
fh - > handle = open ( fh - > ino - > localname , flags , mode ) ;
if ( fh - > handle = = - 1 ) {
1999-01-21 01:01:11 +03:00
g_free ( fh ) ;
1999-01-18 02:10:05 +03:00
ERRNOR ( errno , NULL ) ;
1998-11-21 22:36:01 +03:00
}
}
1998-10-23 12:26:25 +04:00
/* i.e. we had no open files and now we have one */
1999-11-03 17:51:22 +03:00
vfs_rmstamp ( me , ( vfsid ) super , 1 ) ;
1998-10-23 12:26:25 +04:00
super - > fd_usage + + ;
1998-11-21 22:36:01 +03:00
fh - > ino - > st . st_nlink + + ;
1998-10-23 12:26:25 +04:00
return fh ;
}
1999-01-18 02:10:05 +03:00
int
vfs_s_read ( void * fh , char * buffer , int count )
1998-11-21 22:36:01 +03:00
{
int n ;
vfs * me = FH_SUPER - > me ;
1999-01-18 02:10:05 +03:00
if ( FH - > linear = = LS_LINEAR_CLOSED ) {
1999-12-16 15:55:16 +03:00
print_vfs_message ( _ ( " Starting linear transfer... " ) ) ;
1998-11-21 22:36:01 +03:00
if ( ! MEDATA - > linear_start ( me , FH , 0 ) )
return - 1 ;
}
if ( FH - > linear = = LS_LINEAR_CLOSED )
vfs_die ( " linear_start() did not set linear_state! " ) ;
if ( FH - > linear = = LS_LINEAR_OPEN )
return MEDATA - > linear_read ( me , FH , buffer , count ) ;
1999-01-18 02:10:05 +03:00
if ( FH - > handle ) {
1998-11-21 22:36:01 +03:00
n = read ( FH - > handle , buffer , count ) ;
if ( n < 0 )
me - > verrno = errno ;
return n ;
}
1999-01-18 02:10:05 +03:00
vfs_die ( " vfs_s_read: This should not happen \n " ) ;
1999-01-02 10:46:20 +03:00
return - 1 ;
1998-11-21 22:36:01 +03:00
}
1999-01-18 02:10:05 +03:00
int
vfs_s_write ( void * fh , char * buffer , int count )
1998-11-21 22:36:01 +03:00
{
int n ;
vfs * me = FH_SUPER - > me ;
if ( FH - > linear )
1999-01-18 02:10:05 +03:00
vfs_die ( " no writing to linear files, please " ) ;
1998-11-21 22:36:01 +03:00
FH - > changed = 1 ;
1999-01-18 02:10:05 +03:00
if ( FH - > handle ) {
1998-11-21 22:36:01 +03:00
n = write ( FH - > handle , buffer , count ) ;
if ( n < 0 )
me - > verrno = errno ;
return n ;
}
1999-01-18 02:10:05 +03:00
vfs_die ( " vfs_s_write: This should not happen \n " ) ;
1999-01-02 10:46:20 +03:00
return 0 ;
1998-11-21 22:36:01 +03:00
}
1999-01-18 02:10:05 +03:00
int
vfs_s_lseek ( void * fh , off_t offset , int whence )
1998-10-23 12:26:25 +04:00
{
off_t size = FH - > ino - > st . st_size ;
1998-11-21 22:36:01 +03:00
1999-01-18 02:10:05 +03:00
if ( FH - > handle ! = - 1 ) { /* If we have local file opened, we want to work with it */
int retval = lseek ( FH - > handle , offset , whence ) ;
1998-11-21 22:36:01 +03:00
if ( retval = = - 1 )
FH - > ino - > super - > me - > verrno = errno ;
return retval ;
}
1999-01-18 02:10:05 +03:00
switch ( whence ) {
1998-10-23 12:26:25 +04:00
case SEEK_CUR :
offset + = FH - > pos ; break ;
case SEEK_END :
offset + = size ; break ;
}
if ( offset < 0 )
FH - > pos = 0 ;
else if ( offset < size )
FH - > pos = offset ;
else
FH - > pos = size ;
return FH - > pos ;
}
1999-01-18 02:10:05 +03:00
int
vfs_s_close ( void * fh )
1998-10-23 12:26:25 +04:00
{
1998-11-21 22:36:01 +03:00
int res = 0 ;
vfs * me = FH_SUPER - > me ;
1998-10-23 12:26:25 +04:00
1998-11-21 22:36:01 +03:00
FH_SUPER - > fd_usage - - ;
1999-01-18 02:10:05 +03:00
if ( ! FH_SUPER - > fd_usage ) {
1998-10-23 12:26:25 +04:00
struct vfs_stamping * parent ;
vfs * v ;
1998-11-21 22:36:01 +03:00
v = vfs_type ( FH_SUPER - > name ) ;
1999-01-18 02:10:05 +03:00
if ( v = = & vfs_local_ops ) {
1998-10-23 12:26:25 +04:00
parent = NULL ;
} else {
1999-01-21 01:01:11 +03:00
parent = g_new ( struct vfs_stamping , 1 ) ;
1998-10-23 12:26:25 +04:00
parent - > v = v ;
parent - > next = 0 ;
1998-11-21 22:36:01 +03:00
parent - > id = ( * v - > getid ) ( v , FH_SUPER - > name , & ( parent - > parent ) ) ;
1998-10-23 12:26:25 +04:00
}
1999-11-03 17:51:22 +03:00
vfs_add_noncurrent_stamps ( me , ( vfsid ) ( FH_SUPER ) , parent ) ;
1998-10-23 12:26:25 +04:00
vfs_rm_parents ( parent ) ;
}
1998-11-21 22:36:01 +03:00
if ( FH - > linear = = LS_LINEAR_OPEN )
MEDATA - > linear_close ( me , fh ) ;
if ( MEDATA - > fh_close )
res = MEDATA - > fh_close ( me , fh ) ;
1999-01-18 02:10:05 +03:00
if ( FH - > changed & & MEDATA - > file_store ) {
char * s = vfs_s_fullpath ( me , FH - > ino ) ;
1999-01-11 03:48:23 +03:00
if ( ! s )
res = - 1 ;
2000-04-05 17:08:42 +04:00
else {
1999-01-11 03:48:23 +03:00
res = MEDATA - > file_store ( me , FH_SUPER , s , FH - > ino - > localname ) ;
2000-04-05 17:08:42 +04:00
g_free ( s ) ;
}
1999-01-18 02:10:05 +03:00
vfs_s_invalidate ( me , FH_SUPER ) ;
1998-11-21 22:36:01 +03:00
}
1998-10-23 12:26:25 +04:00
if ( FH - > handle )
1999-01-18 02:10:05 +03:00
close ( FH - > handle ) ;
1998-10-23 12:26:25 +04:00
1998-11-21 22:36:01 +03:00
vfs_s_free_inode ( me , FH - > ino ) ;
1999-01-21 01:01:11 +03:00
g_free ( fh ) ;
1998-11-21 22:36:01 +03:00
return res ;
1998-10-23 12:26:25 +04:00
}
1999-11-03 17:51:22 +03:00
int
vfs_s_retrieve_file ( vfs * me , struct vfs_s_inode * ino )
{
/* If you want reget, you'll have to open file with O_LINEAR */
int total = 0 ;
char buffer [ 8192 ] ;
int handle , n ;
int stat_size = ino - > st . st_size ;
struct vfs_s_fh fh ;
memset ( & fh , 0 , sizeof ( fh ) ) ;
fh . ino = ino ;
if ( ! ( ino - > localname = tempnam ( NULL , me - > name ) ) ) ERRNOR ( ENOMEM , 0 ) ;
handle = open ( ino - > localname , O_RDWR | O_CREAT | O_TRUNC | O_EXCL , 0600 ) ;
if ( handle = = - 1 ) {
me - > verrno = errno ;
goto error_4 ;
}
if ( ! MEDATA - > linear_start ( me , & fh , 0 ) )
goto error_3 ;
/* Clear the interrupt status */
2000-01-31 16:48:00 +03:00
while ( ( n = MEDATA - > linear_read ( me , & fh , buffer , sizeof ( buffer ) ) ) ) {
1999-11-03 17:51:22 +03:00
if ( n < 0 )
goto error_1 ;
total + = n ;
1999-12-16 15:55:16 +03:00
vfs_print_stats ( me - > name , _ ( " Getting file " ) , ino - > ent - > name , total , stat_size ) ;
1999-11-03 17:51:22 +03:00
if ( write ( handle , buffer , n ) < 0 ) {
me - > verrno = errno ;
goto error_1 ;
}
}
MEDATA - > linear_close ( me , & fh ) ;
close ( handle ) ;
if ( stat ( ino - > localname , & ino - > u . fish . local_stat ) < 0 )
ino - > u . fish . local_stat . st_mtime = 0 ;
return 0 ;
error_1 :
MEDATA - > linear_close ( me , & fh ) ;
error_3 :
disable_interrupt_key ( ) ;
close ( handle ) ;
unlink ( ino - > localname ) ;
error_4 :
g_free ( ino - > localname ) ;
ino - > localname = NULL ;
return - 1 ;
}
1998-10-23 12:26:25 +04:00
/* ------------------------------- mc support ---------------------------- */
1999-01-18 02:10:05 +03:00
void
vfs_s_fill_names ( vfs * me , void ( * func ) ( char * ) )
1998-10-23 12:26:25 +04:00
{
struct vfs_s_super * a = MEDATA - > supers ;
char * name ;
while ( a ) {
1999-01-27 03:49:11 +03:00
name = g_strconcat ( a - > name , " # " , me - > prefix , " / " , /* a->current_dir->name, */ NULL ) ;
1998-10-23 12:26:25 +04:00
( * func ) ( name ) ;
1999-01-21 01:01:11 +03:00
g_free ( name ) ;
1998-10-23 12:26:25 +04:00
a = a - > next ;
}
}
int
1999-01-18 02:10:05 +03:00
vfs_s_ferrno ( vfs * me )
1998-10-23 12:26:25 +04:00
{
return me - > verrno ;
}
void
1999-01-18 02:10:05 +03:00
vfs_s_dump ( vfs * me , char * prefix , vfs_s_inode * ino )
1998-10-23 12:26:25 +04:00
{
1999-01-18 02:10:05 +03:00
printf ( " %s %s %d " , prefix , S_ISDIR ( ino - > st . st_mode ) ? " DIR " : " FILE " , ino - > st . st_mode ) ;
1999-01-11 03:48:23 +03:00
if ( ! ino - > subdir )
printf ( " FILE \n " ) ;
1998-10-23 12:26:25 +04:00
else
{
struct vfs_s_entry * ent ;
2000-01-31 16:48:00 +03:00
for ( ent = ino - > subdir ; ent ; ent = ent - > next ) {
char * s = g_strconcat ( prefix , " / " , ent - > name , NULL ) ;
1998-10-23 12:26:25 +04:00
if ( ent - > name [ 0 ] = = ' . ' )
1999-01-18 02:10:05 +03:00
printf ( " %s IGNORED \n " , s ) ;
1998-10-23 12:26:25 +04:00
else
1999-01-18 02:10:05 +03:00
vfs_s_dump ( me , s , ent - > ino ) ;
1999-01-21 01:01:11 +03:00
g_free ( s ) ;
1998-10-23 12:26:25 +04:00
}
}
}
1999-01-18 02:10:05 +03:00
char *
vfs_s_getlocalcopy ( vfs * me , char * path )
1998-10-23 12:26:25 +04:00
{
struct vfs_s_inode * ino ;
char buf [ MC_MAXPATHLEN ] ;
1999-01-18 02:10:05 +03:00
strcpy ( buf , path ) ;
1998-10-23 12:26:25 +04:00
ino = vfs_s_inode_from_path ( me , path , FL_FOLLOW | FL_NONE ) ;
if ( ! ino - > localname )
ino - > localname = mc_def_getlocalcopy ( me , buf ) ;
1998-12-31 18:54:49 +03:00
/* FIXME: fd_usage++ missing */
1999-08-18 23:08:56 +04:00
return g_strdup ( ino - > localname ) ;
1998-10-23 12:26:25 +04:00
}
1998-11-21 22:36:01 +03:00
int
vfs_s_setctl ( vfs * me , char * path , int ctlop , char * arg )
{
1999-01-18 02:10:05 +03:00
vfs_s_inode * ino = vfs_s_inode_from_path ( me , path , 0 ) ;
1998-11-21 22:36:01 +03:00
if ( ! ino )
return 0 ;
1999-01-18 02:10:05 +03:00
switch ( ctlop ) {
case MCCTL_WANT_STALE_DATA :
ino - > super - > want_stale = 1 ;
return 1 ;
case MCCTL_NO_STALE_DATA :
ino - > super - > want_stale = 0 ;
vfs_s_invalidate ( me , ino - > super ) ;
return 1 ;
1998-11-21 22:36:01 +03:00
#if 0 /* FIXME: We should implement these */
1999-01-18 02:10:05 +03:00
case MCCTL_REMOVELOCALCOPY :
return remove_temp_file ( path ) ;
case MCCTL_FORGET_ABOUT :
my_forget ( path ) ;
return 0 ;
1998-11-21 22:36:01 +03:00
# endif
}
return 0 ;
}
/* ----------------------------- Stamping support -------------------------- */
1998-10-23 12:26:25 +04:00
1999-01-18 02:10:05 +03:00
vfsid
vfs_s_getid ( vfs * me , char * path , struct vfs_stamping * * parent )
1998-10-23 12:26:25 +04:00
{
vfs_s_super * archive ;
vfs * v ;
char * p ;
vfsid id ;
struct vfs_stamping * par ;
* parent = NULL ;
if ( ! ( p = vfs_s_get_path ( me , path , & archive , FL_NO_OPEN ) ) )
return ( vfsid ) - 1 ;
1999-01-21 01:01:11 +03:00
g_free ( p ) ;
1998-10-23 12:26:25 +04:00
v = vfs_type ( archive - > name ) ;
id = ( * v - > getid ) ( v , archive - > name , & par ) ;
1999-01-18 02:10:05 +03:00
if ( id ! = ( vfsid ) - 1 ) {
1999-01-21 01:01:11 +03:00
* parent = g_new ( struct vfs_stamping , 1 ) ;
1998-10-23 12:26:25 +04:00
( * parent ) - > v = v ;
( * parent ) - > id = id ;
( * parent ) - > parent = par ;
( * parent ) - > next = NULL ;
}
return ( vfsid ) archive ;
}
1999-01-18 02:10:05 +03:00
int
vfs_s_nothingisopen ( vfsid id )
1998-10-23 12:26:25 +04:00
{
1999-11-03 17:51:22 +03:00
/* Our data structures should survive free of superblock at any time */
return 1 ;
1998-10-23 12:26:25 +04:00
}
1999-01-18 02:10:05 +03:00
void
vfs_s_free ( vfsid id )
1998-10-23 12:26:25 +04:00
{
vfs_s_free_super ( ( ( vfs_s_super * ) id ) - > me , ( vfs_s_super * ) id ) ;
}
1998-11-21 22:36:01 +03:00
/* ----------- Utility functions for networked filesystems -------------- */
int
vfs_s_select_on_two ( int fd1 , int fd2 )
{
fd_set set ;
struct timeval timeout ;
int v ;
int maxfd = ( fd1 > fd2 ? fd1 : fd2 ) + 1 ;
timeout . tv_sec = 1 ;
timeout . tv_usec = 0 ;
1999-01-18 02:10:05 +03:00
FD_ZERO ( & set ) ;
FD_SET ( fd1 , & set ) ;
FD_SET ( fd2 , & set ) ;
1998-11-21 22:36:01 +03:00
v = select ( maxfd , & set , 0 , 0 , & timeout ) ;
if ( v < = 0 )
return v ;
if ( FD_ISSET ( fd1 , & set ) )
return 1 ;
if ( FD_ISSET ( fd2 , & set ) )
return 2 ;
return - 1 ;
}
int
vfs_s_get_line ( vfs * me , int sock , char * buf , int buf_len , char term )
{
FILE * logfile = MEDATA - > logfile ;
int i , status ;
char c ;
1999-01-18 02:10:05 +03:00
for ( i = 0 ; i < buf_len ; i + + , buf + + ) {
if ( read ( sock , buf , sizeof ( char ) ) < = 0 )
1998-11-21 22:36:01 +03:00
return 0 ;
if ( logfile ) {
fwrite ( buf , 1 , 1 , logfile ) ;
fflush ( logfile ) ;
}
1999-01-18 02:10:05 +03:00
if ( * buf = = term ) {
1998-11-21 22:36:01 +03:00
* buf = 0 ;
return 1 ;
}
}
* buf = 0 ;
1999-01-18 02:10:05 +03:00
while ( ( status = read ( sock , & c , sizeof ( c ) ) ) > 0 ) {
1998-11-21 22:36:01 +03:00
if ( logfile ) {
fwrite ( & c , 1 , 1 , logfile ) ;
fflush ( logfile ) ;
}
if ( c = = ' \n ' )
return 1 ;
}
return 0 ;
}
int
vfs_s_get_line_interruptible ( vfs * me , char * buffer , int size , int fd )
{
int n ;
2000-01-31 16:48:00 +03:00
int i ;
1998-11-21 22:36:01 +03:00
1999-01-18 02:10:05 +03:00
enable_interrupt_key ( ) ;
for ( i = 0 ; i < size - 1 ; i + + ) {
1998-11-21 22:36:01 +03:00
n = read ( fd , buffer + i , 1 ) ;
1999-01-18 02:10:05 +03:00
disable_interrupt_key ( ) ;
1998-11-21 22:36:01 +03:00
if ( n = = - 1 & & errno = = EINTR ) {
buffer [ i ] = 0 ;
return EINTR ;
}
if ( n = = 0 ) {
buffer [ i ] = 0 ;
return 0 ;
}
if ( buffer [ i ] = = ' \n ' ) {
buffer [ i ] = 0 ;
return 1 ;
}
}
buffer [ size - 1 ] = 0 ;
return 0 ;
}