Adding fish, cleanups, and small updates everywhere to support fish.
Этот коммит содержится в:
родитель
6af6c687c5
Коммит
f45e5aa3fc
@ -1,3 +1,12 @@
|
||||
Fri Sep 11 22:36:38 1998 Pavel Machek <pavel@ucw.cz>
|
||||
* sfs.c: memory leak fixed
|
||||
|
||||
* vfs.c: split parse_ls_lga into more functions
|
||||
|
||||
* fish.c added, now you can access files over rsh/ssh connection
|
||||
|
||||
* shared*.c: reworked a bit not to include so many of ugly X_'s
|
||||
|
||||
Wed Sep 2 13:59:47 1998 Pavel Machek <pavel@ucw.cz>
|
||||
|
||||
* ftpfs.c: cleanup of code, few static's added
|
||||
|
@ -18,10 +18,10 @@ AR = @AR@
|
||||
# VFS code
|
||||
#
|
||||
NETFILES = tcputil.o ftpfs.o mcfs.o utilvfs.o
|
||||
NONETFILES = local.o vfs.o tar.o names.o container.o extfs.o sfs.o @undelfs_o@
|
||||
NONETFILES = local.o vfs.o tar.o names.o container.o extfs.o sfs.o fish.o @undelfs_o@
|
||||
|
||||
VFSSRCS = local.c vfs.c mcfs.c tcputil.c tar.c names.c \
|
||||
ftpfs.c container.c mcserv.c extfs.c undelfs.c utilvfs.c sfs.c
|
||||
ftpfs.c container.c mcserv.c extfs.c undelfs.c utilvfs.c sfs.c fish.c
|
||||
|
||||
VFSHDRS = vfs.h mcfs.h tcputil.h tar.h container.h ftpfs.h names.h \
|
||||
extfs.h
|
||||
@ -40,7 +40,7 @@ EXTFSSTUFF = $(EXTFS_MISC) $(EXTFS_CONST) $(EXTFS_IN)
|
||||
# Commands to build standalone version (.so)
|
||||
#
|
||||
|
||||
VFSSOOBJS = tcputil.so ftpfs.so mcfs.so utilvfs.so local.so vfs.so tar.so names.so container.so extfs.so util-alone.so util.sor utilunix.sor sfs.so
|
||||
VFSSOOBJS = tcputil.so ftpfs.so mcfs.so utilvfs.so local.so vfs.so tar.so names.so container.so extfs.so util-alone.so util.sor utilunix.sor sfs.so fish.so
|
||||
|
||||
%.sor: ../src/%.c
|
||||
$(CC) -c $(CPPFLAGS) $(DEFS) $(CFLAGS) -DVFS_STANDALONE $< -o $@
|
||||
@ -48,8 +48,8 @@ VFSSOOBJS = tcputil.so ftpfs.so mcfs.so utilvfs.so local.so vfs.so tar.so names.
|
||||
%.so: %.c
|
||||
$(CC) -c $(CPPFLAGS) $(DEFS) $(CFLAGS) -DVFS_STANDALONE $< -o $@
|
||||
|
||||
libvfs.so: $(VFSSOOBJS) libvfs.o
|
||||
gcc $(VFSSOOBJS) libvfs.o -shared -o libvfs.so
|
||||
libvfs.so: $(VFSSOOBJS)
|
||||
gcc $(VFSSOOBJS) -shared -o libvfs.so
|
||||
|
||||
|
||||
#
|
||||
@ -96,7 +96,7 @@ TAGS: $(VFSSRCS)
|
||||
etags $(VFSSRCS)
|
||||
|
||||
clean:
|
||||
$(RMF) mcserv *.o core a.out libvfs-mc.a mcservx libvfs.so
|
||||
$(RMF) mcserv *.o core a.out libvfs-mc.a mcservx *.so
|
||||
|
||||
realclean: clean
|
||||
$(RMF) .depend
|
||||
|
178
vfs/README.fish
Обычный файл
178
vfs/README.fish
Обычный файл
@ -0,0 +1,178 @@
|
||||
|
||||
FIles transferred over SHell protocol (V 0.0.2)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This protocol was designed for transferring files over secureshell
|
||||
(ssh) connection. It can be as well used for transfers over rsh, and
|
||||
there may be other uses.
|
||||
|
||||
Client sends requests of following form:
|
||||
|
||||
#FISH_COMMAND
|
||||
equivalent shell commands,
|
||||
which may be multiline
|
||||
|
||||
Only fish commands are defined here, shell equivalents are for your
|
||||
information only and will probably vary from implementation to
|
||||
implementation. Fish commands always have priority: server is
|
||||
expected to execute fish command if it understands it. If it does not,
|
||||
however, it can try the luck and execute shell command.
|
||||
|
||||
Server's reply is multiline, but alwyas ends with
|
||||
|
||||
### 000<optional text>
|
||||
|
||||
line. ### is prefix to mark this line, 000 is return code. Return
|
||||
codes are superset to those used in ftp.
|
||||
|
||||
There are few new exit codes defined:
|
||||
|
||||
000 don't know; if there were no previous lines, this marks COMPLETE
|
||||
success, if they were, it marks failure.
|
||||
|
||||
001 don't know; if there were no previous lines, this marks
|
||||
PRELIMinary success, if they were, it marks failure
|
||||
|
||||
Connecting
|
||||
~~~~~~~~~~
|
||||
Client uses "echo FISH:;/bin/sh" as command executed on remote
|
||||
machine. This should make it possible for server to distinguish FISH
|
||||
connections from normal rsh/ssh.
|
||||
|
||||
Commands
|
||||
~~~~~~~~
|
||||
#FISH
|
||||
echo; start_fish_server; echo '### 200'
|
||||
|
||||
This command is sent at the begining. It marks that client wishes to
|
||||
talk via FISH protocol. #VER command must follow. If server
|
||||
understands FISH protocol, it has option to put FISH server somewhere
|
||||
on system path and name it start_fish_server.
|
||||
|
||||
#VER 0.0.2 <feature1> <feature2> <...>
|
||||
echo '### 000'
|
||||
|
||||
This command is the second one. It sends client version and extensions
|
||||
to the server. Server should reply with protocol version to be used,
|
||||
and list of extensions accepted.
|
||||
|
||||
VER 0.0.0 <feature2>
|
||||
### 200
|
||||
|
||||
#PWD
|
||||
pwd; echo '### 200'
|
||||
|
||||
Server should reply with current directory (in form /abc/def/ghi)
|
||||
followed by line indicating success.
|
||||
|
||||
#LIST /directory
|
||||
ls -lLa $1 | grep '^[^cbt]' | ( while read p x u g s m d y n; do echo "P$p $u.$g
|
||||
S$s
|
||||
d$m $d $y
|
||||
:$n
|
||||
"; done )
|
||||
ls -lLa $1 | grep '^[cb]' | ( while read p x u g a i m d y n; do echo "P$p $u.$g
|
||||
E$a$i
|
||||
dD$m $d $y
|
||||
:$n
|
||||
"; done )
|
||||
echo '### 200'
|
||||
|
||||
This allows client to list directory or get status information about
|
||||
single file. Output is in following form (any line except :<filename>
|
||||
may be ommited):
|
||||
|
||||
P<unix permissions> <owner>.<group>
|
||||
S<size>
|
||||
d<3-letters month name> <day> <year or HH:MM>
|
||||
D<year> <month> <day> <hour> <minute> <second>[.1234]
|
||||
E<major-of-device>,<minor>
|
||||
:<filename>
|
||||
L<filename symlink points to>
|
||||
<blank line to separate items>
|
||||
|
||||
Unix permissions are of form X--------- where X is type of
|
||||
file. Currently, '-' means regular file, 'd' means directory, 'c', 'b'
|
||||
means character and block device, 'l' means symbolic link, 'p' means
|
||||
FIFO and 's' means socket.
|
||||
|
||||
'd' has three fields: month (one of strings Jan Feb Mar Apr May Jun
|
||||
Jul Aug Sep Oct Nov Dec), day of month, and third is either single
|
||||
number indicating year, or HH:MM field (assume current year in such
|
||||
case). As you've probably noticed, this is pretty broken; it is for
|
||||
compatibility with ls listing.
|
||||
|
||||
#RETR /some/name
|
||||
ls -l /some/name | ( read a b c d x e; echo $x ); echo '### 100'; cat /some/name; echo '### 200'
|
||||
|
||||
Server sends line with filesize on it, followed by line with ### 100
|
||||
indicating partial success, then it sends binary data (exactly
|
||||
filesize bytes) and follows them with (with no preceeding newline) ###
|
||||
200.
|
||||
|
||||
Note that there's no way to abort running RETR command - except
|
||||
closing the connection.
|
||||
|
||||
#STOR <size> /file/name
|
||||
> /file/name; echo '### 001'; ( dd bs=4096 count=<size/4096>; dd bs=<size%4096> count=1 ) 2>/dev/null | ( cat > %s; cat > /dev/null ); echo '### 200'
|
||||
|
||||
This command is for storing /file/name, which is exactly size bytes
|
||||
big. You probably think I went crazy. Well, I did not: that strange
|
||||
cat > /dev/null has purpose to discard any extra data which was not
|
||||
written to disk (due to for example out of space condition).
|
||||
|
||||
[Why? Imagine uploading file with "rm -rf /" line in it.]
|
||||
|
||||
#CWD /somewhere
|
||||
cd /somewhere; echo '### 000'
|
||||
|
||||
It is specified here, but I'm not sure how wise idea is to use this
|
||||
one: it breaks stateless-ness of the protocol.
|
||||
|
||||
Following commands should be rather self-explanatory:
|
||||
|
||||
#CHMOD 1234 file
|
||||
chmod 1234 file; echo '### 000'
|
||||
|
||||
#DELE /some/path
|
||||
rm -f /some/path; echo '### 000'
|
||||
|
||||
#MKD /some/path
|
||||
mkdir /some/path; echo '### 000'
|
||||
|
||||
#RMD /some/path
|
||||
rmdir /some/path; echo '### 000'
|
||||
|
||||
#RENAME /path/a /path/b
|
||||
mv /path/a /path/b; echo '### 000'
|
||||
|
||||
#LINK /path/a /path/b
|
||||
ln /path/a /path/b; echo '### 000'
|
||||
|
||||
#SYMLINK /path/a /path/b
|
||||
ln -s /path/a /path/b; echo '### 000'
|
||||
|
||||
#CHOWN user /file/name
|
||||
chown user /file/name; echo '### 000'
|
||||
|
||||
#CHGRP group /file/name
|
||||
chgrp group /file/name; echo '### 000'
|
||||
|
||||
#READ <offset> <size> /path/and/filename
|
||||
cat /path/and/filename | ( dd bs=4096 count=<offset/4096> > /dev/null;
|
||||
dd bs=<offset%4096> count=1 > /dev/null;
|
||||
dd bs=4096 count=<offset/4096>;
|
||||
dd bs=<offset%4096> count=1; )
|
||||
|
||||
Returns ### 200 on successfull exit, ### 291 on successfull exit when
|
||||
reading ended at eof, ### 292 on successfull exit when reading did not
|
||||
end at eof.
|
||||
|
||||
#WRITE <offset> <size> /path/and/filename
|
||||
|
||||
Hmm, shall we define these ones if we know our client is not going to
|
||||
use them?
|
||||
|
||||
|
||||
That's all, folks!
|
||||
pavel@ucw.cz
|
226
vfs/extfs.c
226
vfs/extfs.c
@ -46,11 +46,11 @@
|
||||
#include "vfs.h"
|
||||
#include "extfs.h"
|
||||
|
||||
static struct extfs_entry *
|
||||
extfs_find_entry (struct extfs_entry *dir, char *name, int make_dirs, int make_file);
|
||||
static struct entry *
|
||||
find_entry (struct entry *dir, char *name, int make_dirs, int make_file);
|
||||
|
||||
static struct extfs_archive *first_archive = NULL;
|
||||
static int extfserrno = 0;
|
||||
static struct archive *first_archive = NULL;
|
||||
static int my_errno = 0;
|
||||
static struct stat hstat; /* Stat struct corresponding */
|
||||
static char *current_file_name, *current_link_name;
|
||||
static char *extfs_current_dir;
|
||||
@ -62,7 +62,7 @@ static int extfs_no = 0;
|
||||
|
||||
void extfs_fill_names (void (*func)(char *))
|
||||
{
|
||||
struct extfs_archive *a = first_archive;
|
||||
struct archive *a = first_archive;
|
||||
char *name;
|
||||
|
||||
while (a){
|
||||
@ -75,12 +75,12 @@ void extfs_fill_names (void (*func)(char *))
|
||||
}
|
||||
}
|
||||
|
||||
static void make_dot_doubledot (struct extfs_entry *ent)
|
||||
static void make_dot_doubledot (struct entry *ent)
|
||||
{
|
||||
struct extfs_entry *entry = (struct extfs_entry *)
|
||||
xmalloc (sizeof (struct extfs_entry), "Extfs: extfs_entry");
|
||||
struct extfs_entry *parentry = ent->dir;
|
||||
struct extfs_inode *inode = ent->inode, *parent;
|
||||
struct entry *entry = (struct entry *)
|
||||
xmalloc (sizeof (struct entry), "Extfs: entry");
|
||||
struct entry *parentry = ent->dir;
|
||||
struct inode *inode = ent->inode, *parent;
|
||||
|
||||
parent = (parentry != NULL) ? parentry->inode : NULL;
|
||||
entry->name = strdup (".");
|
||||
@ -91,8 +91,8 @@ static void make_dot_doubledot (struct extfs_entry *ent)
|
||||
inode->first_in_subdir = entry;
|
||||
inode->last_in_subdir = entry;
|
||||
inode->nlink++;
|
||||
entry->next_in_dir = (struct extfs_entry *)
|
||||
xmalloc (sizeof (struct extfs_entry), "Extfs: extfs_entry");
|
||||
entry->next_in_dir = (struct entry *)
|
||||
xmalloc (sizeof (struct entry), "Extfs: entry");
|
||||
entry=entry->next_in_dir;
|
||||
entry->name = strdup ("..");
|
||||
entry->has_changed = 0;
|
||||
@ -109,16 +109,16 @@ static void make_dot_doubledot (struct extfs_entry *ent)
|
||||
}
|
||||
}
|
||||
|
||||
static struct extfs_entry *generate_entry (struct extfs_archive *archive,
|
||||
char *name, struct extfs_entry *parentry, mode_t mode)
|
||||
static struct entry *generate_entry (struct archive *archive,
|
||||
char *name, struct entry *parentry, mode_t mode)
|
||||
{
|
||||
mode_t myumask;
|
||||
struct extfs_inode *inode, *parent;
|
||||
struct extfs_entry *entry;
|
||||
struct inode *inode, *parent;
|
||||
struct entry *entry;
|
||||
|
||||
parent = (parentry != NULL) ? parentry->inode : NULL;
|
||||
entry = (struct extfs_entry *)
|
||||
xmalloc (sizeof (struct extfs_entry), "Extfs: extfs_entry");
|
||||
entry = (struct entry *)
|
||||
xmalloc (sizeof (struct entry), "Extfs: entry");
|
||||
|
||||
entry->name = strdup (name);
|
||||
entry->has_changed = 0;
|
||||
@ -128,8 +128,8 @@ static struct extfs_entry *generate_entry (struct extfs_archive *archive,
|
||||
parent->last_in_subdir->next_in_dir = entry;
|
||||
parent->last_in_subdir = entry;
|
||||
}
|
||||
inode = (struct extfs_inode *)
|
||||
xmalloc (sizeof (struct extfs_inode), "Extfs: extfs_inode");
|
||||
inode = (struct inode *)
|
||||
xmalloc (sizeof (struct inode), "Extfs: inode");
|
||||
entry->inode = inode;
|
||||
inode->has_changed = 0;
|
||||
inode->local_filename = NULL;
|
||||
@ -154,12 +154,12 @@ static struct extfs_entry *generate_entry (struct extfs_archive *archive,
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void free_entries (struct extfs_entry *entry)
|
||||
static void free_entries (struct entry *entry)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void free_archive (struct extfs_archive *archive)
|
||||
static void free_archive (struct archive *archive)
|
||||
{
|
||||
free_entries (archive->root_entry);
|
||||
if (archive->local_name != NULL) {
|
||||
@ -175,7 +175,7 @@ static void free_archive (struct extfs_archive *archive)
|
||||
free (archive);
|
||||
}
|
||||
|
||||
static FILE *open_extfs_archive (int fstype, char *name, struct extfs_archive **pparc)
|
||||
static FILE *open_archive (int fstype, char *name, struct archive **pparc)
|
||||
{
|
||||
static dev_t __extfs_no = 0;
|
||||
FILE *result;
|
||||
@ -183,8 +183,8 @@ static FILE *open_extfs_archive (int fstype, char *name, struct extfs_archive **
|
||||
char *cmd;
|
||||
char *mc_extfsdir;
|
||||
struct stat mystat;
|
||||
struct extfs_archive *current_archive;
|
||||
struct extfs_entry *root_entry;
|
||||
struct archive *current_archive;
|
||||
struct entry *root_entry;
|
||||
char *local_name = NULL, *tmp = 0;
|
||||
int uses_archive = extfs_need_archive [fstype];
|
||||
char *tmpfile;
|
||||
@ -221,8 +221,8 @@ static FILE *open_extfs_archive (int fstype, char *name, struct extfs_archive **
|
||||
return NULL;
|
||||
}
|
||||
|
||||
current_archive = (struct extfs_archive *)
|
||||
xmalloc (sizeof (struct extfs_archive), "Extfs archive");
|
||||
current_archive = (struct archive *)
|
||||
xmalloc (sizeof (struct archive), "Extfs archive");
|
||||
current_archive->fstype = fstype;
|
||||
current_archive->name = name ? strdup (name): name;
|
||||
current_archive->local_name = local_name;
|
||||
@ -261,13 +261,13 @@ static FILE *open_extfs_archive (int fstype, char *name, struct extfs_archive **
|
||||
* Main loop for reading an archive.
|
||||
* Returns 0 on success, -1 on error.
|
||||
*/
|
||||
int read_extfs_archive (int fstype, char *name, struct extfs_archive **pparc)
|
||||
int read_archive (int fstype, char *name, struct archive **pparc)
|
||||
{
|
||||
FILE *extfsd;
|
||||
char *buffer;
|
||||
struct extfs_archive *current_archive;
|
||||
struct archive *current_archive;
|
||||
|
||||
if ((extfsd = open_extfs_archive (fstype, name, ¤t_archive)) == NULL) {
|
||||
if ((extfsd = open_archive (fstype, name, ¤t_archive)) == NULL) {
|
||||
message_3s (1, MSG_ERROR, _("Couldn't open %s archive\n%s"),
|
||||
extfs_prefixes [fstype], name);
|
||||
return -1;
|
||||
@ -277,8 +277,8 @@ int read_extfs_archive (int fstype, char *name, struct extfs_archive **pparc)
|
||||
while (fgets (buffer, 4096, extfsd) != NULL) {
|
||||
current_link_name = NULL;
|
||||
if (parse_ls_lga (buffer, &hstat, ¤t_file_name, ¤t_link_name)) {
|
||||
struct extfs_entry *entry, *pent;
|
||||
struct extfs_inode *inode;
|
||||
struct entry *entry, *pent;
|
||||
struct inode *inode;
|
||||
char *p, *q, *cfn = current_file_name;
|
||||
|
||||
if (*cfn) {
|
||||
@ -298,7 +298,7 @@ int read_extfs_archive (int fstype, char *name, struct extfs_archive **pparc)
|
||||
if (S_ISDIR (hstat.st_mode) &&
|
||||
(!strcmp (p, ".") || !strcmp (p, "..")))
|
||||
goto read_extfs_continue;
|
||||
pent = extfs_find_entry (current_archive->root_entry, q, 1, 0) ;
|
||||
pent = find_entry (current_archive->root_entry, q, 1, 0) ;
|
||||
if (pent == NULL) {
|
||||
message_1s (1, MSG_ERROR, _("Inconsistent extfs archive"));
|
||||
/* FIXME: Should clean everything one day */
|
||||
@ -306,7 +306,7 @@ int read_extfs_archive (int fstype, char *name, struct extfs_archive **pparc)
|
||||
pclose (extfsd);
|
||||
return -1;
|
||||
}
|
||||
entry = (struct extfs_entry *) xmalloc (sizeof (struct extfs_entry), "Extfs: extfs_entry");
|
||||
entry = (struct entry *) xmalloc (sizeof (struct entry), "Extfs: entry");
|
||||
entry->name = strdup (p);
|
||||
entry->has_changed = 0;
|
||||
entry->next_in_dir = NULL;
|
||||
@ -318,7 +318,7 @@ int read_extfs_archive (int fstype, char *name, struct extfs_archive **pparc)
|
||||
}
|
||||
}
|
||||
if (!S_ISLNK (hstat.st_mode) && current_link_name != NULL) {
|
||||
pent = extfs_find_entry (current_archive->root_entry, current_link_name, 0, 0);
|
||||
pent = find_entry (current_archive->root_entry, current_link_name, 0, 0);
|
||||
if (pent == NULL) {
|
||||
message_1s (1, MSG_ERROR, _("Inconsistent extfs archive"));
|
||||
/* FIXME: Should clean everything one day */
|
||||
@ -330,7 +330,7 @@ int read_extfs_archive (int fstype, char *name, struct extfs_archive **pparc)
|
||||
pent->inode->nlink++;
|
||||
}
|
||||
} else {
|
||||
inode = (struct extfs_inode *) xmalloc (sizeof (struct extfs_inode), "Extfs: extfs_inode");
|
||||
inode = (struct inode *) xmalloc (sizeof (struct inode), "Extfs: inode");
|
||||
entry->inode = inode;
|
||||
inode->local_filename = NULL;
|
||||
inode->has_changed = 0;
|
||||
@ -377,18 +377,18 @@ int read_extfs_archive (int fstype, char *name, struct extfs_archive **pparc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *extfs_get_path (char *inname, struct extfs_archive **archive, int is_dir,
|
||||
static char *get_path (char *inname, struct archive **archive, int is_dir,
|
||||
int do_not_open);
|
||||
|
||||
/* Returns path inside argument. Returned char* is inside inname, which is mangled
|
||||
* by this operation (so you must not free it's return value)
|
||||
*/
|
||||
static char *extfs_get_path_mangle (char *inname, struct extfs_archive **archive, int is_dir,
|
||||
static char *get_path_mangle (char *inname, struct archive **archive, int is_dir,
|
||||
int do_not_open)
|
||||
{
|
||||
char *local, *archive_name, *op;
|
||||
int result = -1;
|
||||
struct extfs_archive *parc;
|
||||
struct archive *parc;
|
||||
struct vfs_stamping *parent;
|
||||
vfs *v;
|
||||
int fstype;
|
||||
@ -424,9 +424,9 @@ static char *extfs_get_path_mangle (char *inname, struct extfs_archive **archive
|
||||
}
|
||||
}
|
||||
|
||||
result = do_not_open ? -1 : read_extfs_archive (fstype, archive_name, &parc);
|
||||
result = do_not_open ? -1 : read_archive (fstype, archive_name, &parc);
|
||||
if (result == -1) {
|
||||
extfserrno = EIO;
|
||||
my_errno = EIO;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -449,7 +449,7 @@ static char *extfs_get_path_mangle (char *inname, struct extfs_archive **archive
|
||||
}
|
||||
|
||||
/* Returns allocated path (without leading slash) inside the archive */
|
||||
static char *extfs_get_path_from_entry (struct extfs_entry *entry)
|
||||
static char *get_path_from_entry (struct entry *entry)
|
||||
{
|
||||
struct list {
|
||||
struct list *next;
|
||||
@ -480,23 +480,23 @@ static char *extfs_get_path_from_entry (struct extfs_entry *entry)
|
||||
}
|
||||
|
||||
|
||||
struct extfs_loop_protect {
|
||||
struct extfs_entry *entry;
|
||||
struct extfs_loop_protect *next;
|
||||
struct loop_protect {
|
||||
struct entry *entry;
|
||||
struct loop_protect *next;
|
||||
};
|
||||
static int errloop;
|
||||
static int notadir;
|
||||
|
||||
static struct extfs_entry *
|
||||
__extfs_find_entry (struct extfs_entry *dir, char *name,
|
||||
struct extfs_loop_protect *list, int make_dirs, int make_file);
|
||||
static struct entry *
|
||||
__find_entry (struct entry *dir, char *name,
|
||||
struct loop_protect *list, int make_dirs, int make_file);
|
||||
|
||||
static struct extfs_entry *
|
||||
__extfs_resolve_symlinks (struct extfs_entry *entry,
|
||||
struct extfs_loop_protect *list)
|
||||
static struct entry *
|
||||
__resolve_symlinks (struct entry *entry,
|
||||
struct loop_protect *list)
|
||||
{
|
||||
struct extfs_entry *pent;
|
||||
struct extfs_loop_protect *looping;
|
||||
struct entry *pent;
|
||||
struct loop_protect *looping;
|
||||
|
||||
if (!S_ISLNK (entry->inode->mode))
|
||||
return entry;
|
||||
@ -505,42 +505,42 @@ __extfs_resolve_symlinks (struct extfs_entry *entry,
|
||||
errloop = 1;
|
||||
return NULL;
|
||||
}
|
||||
looping = (struct extfs_loop_protect *)
|
||||
xmalloc (sizeof (struct extfs_loop_protect),
|
||||
looping = (struct loop_protect *)
|
||||
xmalloc (sizeof (struct loop_protect),
|
||||
"Extfs: symlink looping protection");
|
||||
looping->entry = entry;
|
||||
looping->next = list;
|
||||
pent = __extfs_find_entry (entry->dir, entry->inode->linkname, looping, 0, 0);
|
||||
pent = __find_entry (entry->dir, entry->inode->linkname, looping, 0, 0);
|
||||
free (looping);
|
||||
if (pent == NULL)
|
||||
extfserrno = ENOENT;
|
||||
my_errno = ENOENT;
|
||||
return pent;
|
||||
}
|
||||
|
||||
static struct extfs_entry *extfs_resolve_symlinks (struct extfs_entry *entry)
|
||||
static struct entry *my_resolve_symlinks (struct entry *entry)
|
||||
{
|
||||
struct extfs_entry *res;
|
||||
struct entry *res;
|
||||
|
||||
errloop = 0;
|
||||
notadir = 0;
|
||||
res = __extfs_resolve_symlinks (entry, NULL);
|
||||
res = __resolve_symlinks (entry, NULL);
|
||||
if (res == NULL) {
|
||||
if (errloop)
|
||||
extfserrno = ELOOP;
|
||||
my_errno = ELOOP;
|
||||
else if (notadir)
|
||||
extfserrno = ENOTDIR;
|
||||
my_errno = ENOTDIR;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
struct extfs_pseudofile {
|
||||
struct extfs_archive *archive;
|
||||
struct pseudofile {
|
||||
struct archive *archive;
|
||||
unsigned int has_changed:1;
|
||||
int local_handle;
|
||||
struct extfs_entry *entry;
|
||||
struct entry *entry;
|
||||
};
|
||||
|
||||
static char *get_archive_name (struct extfs_archive *archive)
|
||||
static char *get_archive_name (struct archive *archive)
|
||||
{
|
||||
char *archive_name;
|
||||
|
||||
@ -557,10 +557,10 @@ static char *get_archive_name (struct extfs_archive *archive)
|
||||
|
||||
void extfs_run (char *file)
|
||||
{
|
||||
struct extfs_archive *archive;
|
||||
struct archive *archive;
|
||||
char *p, *q, *cmd, *archive_name, *mc_extfsdir;
|
||||
|
||||
if ((p = extfs_get_path (file, &archive, 0, 0)) == NULL)
|
||||
if ((p = get_path (file, &archive, 0, 0)) == NULL)
|
||||
return;
|
||||
q = name_quote (p, 0);
|
||||
|
||||
@ -582,30 +582,30 @@ void extfs_run (char *file)
|
||||
|
||||
static void *extfs_open (char *file, int flags, int mode)
|
||||
{
|
||||
struct extfs_pseudofile *extfs_info;
|
||||
struct extfs_archive *archive;
|
||||
struct pseudofile *extfs_info;
|
||||
struct archive *archive;
|
||||
char *q;
|
||||
char *mc_extfsdir;
|
||||
struct extfs_entry *entry;
|
||||
struct entry *entry;
|
||||
int local_handle;
|
||||
const int do_create = (flags & O_ACCMODE) != O_RDONLY;
|
||||
|
||||
if ((q = extfs_get_path_mangle (file, &archive, 0, 0)) == NULL)
|
||||
if ((q = get_path_mangle (file, &archive, 0, 0)) == NULL)
|
||||
return NULL;
|
||||
entry = extfs_find_entry (archive->root_entry, q, 0, do_create);
|
||||
entry = find_entry (archive->root_entry, q, 0, do_create);
|
||||
if (entry == NULL)
|
||||
return NULL;
|
||||
if ((entry = extfs_resolve_symlinks (entry)) == NULL)
|
||||
if ((entry = my_resolve_symlinks (entry)) == NULL)
|
||||
return NULL;
|
||||
if (S_ISDIR (entry->inode->mode)) {
|
||||
extfserrno = EISDIR;
|
||||
my_errno = EISDIR;
|
||||
return NULL;
|
||||
}
|
||||
if (entry->inode->local_filename == NULL) {
|
||||
char *cmd, *archive_name, *p;
|
||||
|
||||
entry->inode->local_filename = strdup (tempnam (NULL, "extfs"));
|
||||
p = extfs_get_path_from_entry (entry);
|
||||
p = get_path_from_entry (entry);
|
||||
q = name_quote (p, 0);
|
||||
free (p);
|
||||
archive_name = name_quote (get_archive_name (archive), 0);
|
||||
@ -623,7 +623,7 @@ static void *extfs_open (char *file, int flags, int mode)
|
||||
entry->inode->local_filename = NULL;
|
||||
free (cmd);
|
||||
free (mc_extfsdir);
|
||||
extfserrno = EIO;
|
||||
my_errno = EIO;
|
||||
return NULL;
|
||||
}
|
||||
free (cmd);
|
||||
@ -632,11 +632,11 @@ static void *extfs_open (char *file, int flags, int mode)
|
||||
|
||||
local_handle = open (entry->inode->local_filename, flags, mode);
|
||||
if (local_handle == -1) {
|
||||
extfserrno = EIO;
|
||||
my_errno = EIO;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
extfs_info = (struct extfs_pseudofile *) xmalloc (sizeof (struct extfs_pseudofile), "Extfs: extfs_open");
|
||||
extfs_info = (struct pseudofile *) xmalloc (sizeof (struct pseudofile), "Extfs: extfs_open");
|
||||
extfs_info->archive = archive;
|
||||
extfs_info->entry = entry;
|
||||
extfs_info->has_changed = 0;
|
||||
@ -650,22 +650,22 @@ static void *extfs_open (char *file, int flags, int mode)
|
||||
|
||||
static int extfs_read (void *data, char *buffer, int count)
|
||||
{
|
||||
struct extfs_pseudofile *file = (struct extfs_pseudofile *)data;
|
||||
struct pseudofile *file = (struct pseudofile *)data;
|
||||
|
||||
return read (file->local_handle, buffer, count);
|
||||
}
|
||||
|
||||
static int extfs_close (void *data)
|
||||
{
|
||||
struct extfs_pseudofile *file;
|
||||
struct pseudofile *file;
|
||||
int errno_code = 0;
|
||||
file = (struct extfs_pseudofile *)data;
|
||||
file = (struct pseudofile *)data;
|
||||
|
||||
close (file->local_handle);
|
||||
|
||||
/* Commit the file if it has changed */
|
||||
if (file->has_changed){
|
||||
struct extfs_archive *archive;
|
||||
struct archive *archive;
|
||||
char *archive_name, *file_name;
|
||||
char *cmd;
|
||||
char *mc_extfsdir;
|
||||
@ -673,7 +673,7 @@ static int extfs_close (void *data)
|
||||
|
||||
archive = file->archive;
|
||||
archive_name = name_quote (get_archive_name (archive), 0);
|
||||
p = extfs_get_path_from_entry (file->entry);
|
||||
p = get_path_from_entry (file->entry);
|
||||
file_name = name_quote (p, 0);
|
||||
free (p);
|
||||
|
||||
@ -718,28 +718,14 @@ static int extfs_close (void *data)
|
||||
|
||||
free (data);
|
||||
if (errno_code){
|
||||
extfserrno = EIO; /* Non standard, but who cares? */
|
||||
my_errno = EIO; /* Non standard, but who cares? */
|
||||
return -1;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define RECORDSIZE 512
|
||||
#define X_pseudofile extfs_pseudofile
|
||||
#define Xerrno extfserrno
|
||||
|
||||
#define X_entry extfs_entry
|
||||
#define X_archive extfs_archive
|
||||
#define X_get_path extfs_get_path
|
||||
#define X_get_path_mangle extfs_get_path_mangle
|
||||
#define X_find_entry extfs_find_entry
|
||||
#define X_resolve_symlinks extfs_resolve_symlinks
|
||||
#define X_inode extfs_inode
|
||||
#define __X_find_entry __extfs_find_entry
|
||||
#define __X_resolve_symlinks __extfs_resolve_symlinks
|
||||
#define X_loop_protect extfs_loop_protect
|
||||
|
||||
#include "shared.c"
|
||||
#include "shared_tar_ext.c"
|
||||
|
||||
static int extfs_chmod (char *path, int mode)
|
||||
{
|
||||
@ -748,7 +734,7 @@ static int extfs_chmod (char *path, int mode)
|
||||
|
||||
static int extfs_write (void *data, char *buf, int nbyte)
|
||||
{
|
||||
struct extfs_pseudofile *file = (struct extfs_pseudofile *)data;
|
||||
struct pseudofile *file = (struct pseudofile *)data;
|
||||
|
||||
file->has_changed = 1;
|
||||
return write (file->local_handle, buf, nbyte);
|
||||
@ -756,24 +742,24 @@ static int extfs_write (void *data, char *buf, int nbyte)
|
||||
|
||||
static int extfs_chdir (char *path)
|
||||
{
|
||||
struct extfs_archive *archive;
|
||||
struct archive *archive;
|
||||
char *q, *res;
|
||||
struct extfs_entry *entry;
|
||||
struct entry *entry;
|
||||
|
||||
extfserrno = ENOTDIR;
|
||||
if ((q = extfs_get_path_mangle (path, &archive, 1, 0)) == NULL)
|
||||
my_errno = ENOTDIR;
|
||||
if ((q = get_path_mangle (path, &archive, 1, 0)) == NULL)
|
||||
return -1;
|
||||
entry = extfs_find_entry (archive->root_entry, q, 0, 0);
|
||||
entry = find_entry (archive->root_entry, q, 0, 0);
|
||||
if (!entry)
|
||||
return -1;
|
||||
entry = extfs_resolve_symlinks (entry);
|
||||
entry = my_resolve_symlinks (entry);
|
||||
if ((!entry) || (!S_ISDIR (entry->inode->mode)))
|
||||
return -1;
|
||||
entry->inode->archive->current_dir = entry;
|
||||
res = copy_strings (
|
||||
entry->inode->archive->name, "#", extfs_prefixes [entry->inode->archive->fstype],
|
||||
"/", q, NULL);
|
||||
extfserrno = 0;
|
||||
my_errno = 0;
|
||||
if (extfs_current_dir)
|
||||
free (extfs_current_dir);
|
||||
extfs_current_dir = res;
|
||||
@ -782,21 +768,21 @@ static int extfs_chdir (char *path)
|
||||
|
||||
static int extfs_lseek (void *data, off_t offset, int whence)
|
||||
{
|
||||
struct extfs_pseudofile *file = (struct extfs_pseudofile *) data;
|
||||
struct pseudofile *file = (struct pseudofile *) data;
|
||||
|
||||
return lseek (file->local_handle, offset, whence);
|
||||
}
|
||||
|
||||
static vfsid extfs_getid (char *path, struct vfs_stamping **parent)
|
||||
{
|
||||
struct extfs_archive *archive;
|
||||
struct archive *archive;
|
||||
vfs *v;
|
||||
vfsid id;
|
||||
struct vfs_stamping *par;
|
||||
char *p;
|
||||
|
||||
*parent = NULL;
|
||||
if (!(p = extfs_get_path (path, &archive, 1, 1)))
|
||||
if (!(p = get_path (path, &archive, 1, 1)))
|
||||
return (vfsid) -1;
|
||||
free(p);
|
||||
if (archive->name){
|
||||
@ -815,17 +801,17 @@ static vfsid extfs_getid (char *path, struct vfs_stamping **parent)
|
||||
|
||||
static int extfs_nothingisopen (vfsid id)
|
||||
{
|
||||
if (((struct extfs_archive *)id)->fd_usage <= 0)
|
||||
if (((struct archive *)id)->fd_usage <= 0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_entry (struct extfs_entry *e)
|
||||
static void free_entry (struct entry *e)
|
||||
{
|
||||
int i = --(e->inode->nlink);
|
||||
if (S_ISDIR (e->inode->mode) && e->inode->first_in_subdir != NULL) {
|
||||
struct extfs_entry *f = e->inode->first_in_subdir;
|
||||
struct entry *f = e->inode->first_in_subdir;
|
||||
|
||||
e->inode->first_in_subdir = NULL;
|
||||
free_entry (f);
|
||||
@ -847,8 +833,8 @@ static void free_entry (struct extfs_entry *e)
|
||||
|
||||
static void extfs_free (vfsid id)
|
||||
{
|
||||
struct extfs_archive *parc;
|
||||
struct extfs_archive *archive = (struct extfs_archive *)id;
|
||||
struct archive *parc;
|
||||
struct archive *archive = (struct archive *)id;
|
||||
|
||||
free_entry (archive->root_entry);
|
||||
if (archive == first_archive) {
|
||||
@ -865,8 +851,8 @@ static void extfs_free (vfsid id)
|
||||
|
||||
static char *extfs_getlocalcopy (char *path)
|
||||
{
|
||||
struct extfs_pseudofile *fp =
|
||||
(struct extfs_pseudofile *) extfs_open (path, O_RDONLY, 0);
|
||||
struct pseudofile *fp =
|
||||
(struct pseudofile *) extfs_open (path, O_RDONLY, 0);
|
||||
char *p;
|
||||
|
||||
if (fp == NULL)
|
||||
@ -883,8 +869,8 @@ static char *extfs_getlocalcopy (char *path)
|
||||
|
||||
static void extfs_ungetlocalcopy (char *path, char *local, int has_changed)
|
||||
{
|
||||
struct extfs_pseudofile *fp =
|
||||
(struct extfs_pseudofile *) extfs_open (path, O_WRONLY, 0);
|
||||
struct pseudofile *fp =
|
||||
(struct pseudofile *) extfs_open (path, O_WRONLY, 0);
|
||||
|
||||
if (fp == NULL)
|
||||
return;
|
||||
|
30
vfs/extfs.h
30
vfs/extfs.h
@ -20,26 +20,26 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
struct extfs_inode;
|
||||
struct inode;
|
||||
|
||||
struct extfs_entry {
|
||||
struct entry {
|
||||
int has_changed;
|
||||
struct extfs_entry *next_in_dir;
|
||||
struct extfs_entry *dir;
|
||||
struct entry *next_in_dir;
|
||||
struct entry *dir;
|
||||
char *name;
|
||||
struct extfs_inode *inode;
|
||||
struct inode *inode;
|
||||
};
|
||||
|
||||
struct extfs_archive;
|
||||
struct archive;
|
||||
|
||||
struct extfs_inode {
|
||||
struct inode {
|
||||
int has_changed;
|
||||
nlink_t nlink;
|
||||
struct extfs_entry *first_in_subdir; /* only used if this is a directory */
|
||||
struct extfs_entry *last_in_subdir;
|
||||
struct entry *first_in_subdir; /* only used if this is a directory */
|
||||
struct entry *last_in_subdir;
|
||||
ino_t inode; /* This is inode # */
|
||||
dev_t dev; /* This is an internal identification of the extfs archive */
|
||||
struct extfs_archive *archive; /* And this is an archive structure */
|
||||
struct archive *archive; /* And this is an archive structure */
|
||||
dev_t rdev;
|
||||
umode_t mode;
|
||||
uid_t uid;
|
||||
@ -53,7 +53,7 @@ struct extfs_inode {
|
||||
char *local_filename;
|
||||
};
|
||||
|
||||
struct extfs_archive {
|
||||
struct archive {
|
||||
int fstype;
|
||||
char *name;
|
||||
char *local_name;
|
||||
@ -62,9 +62,9 @@ struct extfs_archive {
|
||||
dev_t rdev;
|
||||
int fd_usage;
|
||||
ino_t __inode_counter;
|
||||
struct extfs_entry *root_entry;
|
||||
struct extfs_entry *current_dir;
|
||||
struct extfs_archive *next;
|
||||
struct entry *root_entry;
|
||||
struct entry *current_dir;
|
||||
struct archive *next;
|
||||
};
|
||||
|
||||
void extfs_init (void);
|
||||
@ -74,3 +74,5 @@ char *extfs_get_prefix (int fstype);
|
||||
char *extfs_analysis (char *path, char **arc_name, int *fstype, int is_dir);
|
||||
void extfs_run (char *path);
|
||||
void extfs_done (void);
|
||||
|
||||
typedef struct archive extfs_archive; /* Do _not_ use this inside extfs.c */
|
||||
|
@ -1,10 +1,11 @@
|
||||
# Each external VFS type must be registered here if you want to use it
|
||||
|
||||
# Popular pc archivers, for arj usage you need special patch to unarj
|
||||
# Popular pc archivers
|
||||
uzip
|
||||
uzoo
|
||||
ulha
|
||||
urar
|
||||
# For arj usage you need special patch to unarj
|
||||
uarj
|
||||
|
||||
# ar is used for static libraries
|
||||
|
1025
vfs/fish.c
Обычный файл
1025
vfs/fish.c
Обычный файл
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
74
vfs/fish.h
Обычный файл
74
vfs/fish.h
Обычный файл
@ -0,0 +1,74 @@
|
||||
/* fish.h */
|
||||
|
||||
#if !defined(__FISH_H)
|
||||
#define __FISH_H
|
||||
|
||||
struct direntry
|
||||
{
|
||||
char *name;
|
||||
int count;
|
||||
char *linkname;
|
||||
char *local_filename;
|
||||
int local_is_temp:1;
|
||||
int freshly_created:1;
|
||||
struct stat local_stat;
|
||||
char *remote_filename;
|
||||
struct stat s;
|
||||
struct stat *l_stat;
|
||||
struct connection *bucket;
|
||||
int tmp_reget;
|
||||
};
|
||||
|
||||
struct dir
|
||||
{
|
||||
int count;
|
||||
struct timeval timestamp;
|
||||
char *remote_path;
|
||||
struct linklist *file_list;
|
||||
};
|
||||
|
||||
struct connection {
|
||||
char *host;
|
||||
char *user;
|
||||
char *current_directory;
|
||||
char *home;
|
||||
char *updir;
|
||||
char *password;
|
||||
int flags;
|
||||
int sockr, sockw;
|
||||
struct linklist *dcache;
|
||||
ino_t __inode_counter;
|
||||
int lock;
|
||||
int failed_on_login; /* used to pass the failure reason to upper levels */
|
||||
int use_proxy; /* use a proxy server */
|
||||
int result_pending;
|
||||
int use_source_route;
|
||||
int use_passive_connection;
|
||||
int isbinary;
|
||||
int cwd_defered; /* current_directory was changed but CWD command hasn't
|
||||
been sent yet */
|
||||
};
|
||||
|
||||
#define qhost(b) (b)->host
|
||||
#define quser(b) (b)->user
|
||||
#define qcdir(b) (b)->current_directory
|
||||
#define qflags(b) (b)->flags
|
||||
#define qsockr(b) (b)->sockr
|
||||
#define qsockw(b) (b)->sockw
|
||||
#define qlock(b) (b)->lock
|
||||
#define qdcache(b) (b)->dcache
|
||||
#define qhome(b) (b)->home
|
||||
#define qupdir(b) (b)->updir
|
||||
#define qproxy(b) (b)->use_proxy
|
||||
|
||||
/* Increased since now we may use C-r to reread the contents */
|
||||
#define FISH_DIRECTORY_TIMEOUT 30 * 60
|
||||
|
||||
#define DO_RESOLVE_SYMLINK 1
|
||||
#define DO_OPEN 2
|
||||
#define DO_FREE_RESOURCE 4
|
||||
|
||||
#define FISH_FLAG_COMPRESSED 1
|
||||
#define FISH_FLAG_RSH 2
|
||||
|
||||
#endif
|
1213
vfs/ftpfs.c
1213
vfs/ftpfs.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
14
vfs/ftpfs.h
14
vfs/ftpfs.h
@ -3,7 +3,7 @@
|
||||
#if !defined(__FTPFS_H)
|
||||
#define __FTPFS_H
|
||||
|
||||
struct ftpentry
|
||||
struct direntry
|
||||
{
|
||||
char *name;
|
||||
int count;
|
||||
@ -16,10 +16,10 @@ struct ftpentry
|
||||
char *remote_filename;
|
||||
struct stat s;
|
||||
struct stat *l_stat;
|
||||
struct ftpfs_connection *bucket;
|
||||
struct connection *bucket;
|
||||
};
|
||||
|
||||
struct ftpfs_dir
|
||||
struct dir
|
||||
{
|
||||
int count;
|
||||
struct timeval timestamp;
|
||||
@ -27,7 +27,7 @@ struct ftpfs_dir
|
||||
struct linklist *file_list;
|
||||
};
|
||||
|
||||
struct ftpfs_connection {
|
||||
struct connection {
|
||||
char *host;
|
||||
char *user;
|
||||
char *current_directory;
|
||||
@ -63,9 +63,9 @@ struct ftpfs_connection {
|
||||
/* Increased since now we may use C-r to reread the contents */
|
||||
#define FTPFS_DIRECTORY_TIMEOUT 30 * 60
|
||||
|
||||
#define FTPFS_RESOLVE_SYMLINK 1
|
||||
#define FTPFS_OPEN 2
|
||||
#define FTPFS_FREE_RESOURCE 4
|
||||
#define DO_RESOLVE_SYMLINK 1
|
||||
#define DO_OPEN 2
|
||||
#define DO_FREE_RESOURCE 4
|
||||
|
||||
extern char *ftpfs_anonymous_passwd;
|
||||
extern char *ftpfs_proxy_host;
|
||||
|
26
vfs/libvfs.c
26
vfs/libvfs.c
@ -1,26 +0,0 @@
|
||||
/*
|
||||
* These are functions that miss from vfs.c to make it complete library
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
void vfs_init( void );
|
||||
void ftpfs_init_passwd( void );
|
||||
|
||||
char *mc_home = LIBDIR;
|
||||
|
||||
void
|
||||
mc_vfs_init( void )
|
||||
{
|
||||
vfs_init();
|
||||
ftpfs_init_passwd();
|
||||
}
|
||||
|
||||
void
|
||||
mc_vfs_done( void )
|
||||
{
|
||||
vfs_shut();
|
||||
}
|
856
vfs/shared_ftp_fish.c
Обычный файл
856
vfs/shared_ftp_fish.c
Обычный файл
@ -0,0 +1,856 @@
|
||||
|
||||
static struct dir *retrieve_dir(struct connection *bucket, char *remote_path);
|
||||
static int store_file(struct direntry *fe);
|
||||
static int retrieve_file_start(struct direntry *fe);
|
||||
static int retrieve_file(struct direntry *fe);
|
||||
|
||||
static int
|
||||
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;
|
||||
FD_ZERO(&set);
|
||||
FD_SET(fd1, &set);
|
||||
FD_SET(fd2, &set);
|
||||
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;
|
||||
}
|
||||
|
||||
static int
|
||||
get_line (int sock, char *buf, int buf_len, char term)
|
||||
{
|
||||
int i, status;
|
||||
char c;
|
||||
|
||||
for (i = 0; i < buf_len; i++, buf++) {
|
||||
if (read(sock, buf, sizeof(char)) <= 0)
|
||||
return 0;
|
||||
if (logfile){
|
||||
fwrite (buf, 1, 1, logfile);
|
||||
fflush (logfile);
|
||||
}
|
||||
if (*buf == term) {
|
||||
*buf = 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
*buf = 0;
|
||||
while ((status = read(sock, &c, sizeof(c))) > 0){
|
||||
if (logfile){
|
||||
fwrite (&c, 1, 1, logfile);
|
||||
fflush (logfile);
|
||||
}
|
||||
if (c == '\n')
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
direntry_destructor (void *data)
|
||||
{
|
||||
struct direntry *fe = data;
|
||||
|
||||
fe->count--;
|
||||
if ((fe->tmp_reget == 1 && fe->local_filename)){
|
||||
unlink (fe->local_filename);
|
||||
fe->tmp_reget = 0;
|
||||
}
|
||||
|
||||
if (fe->count > 0)
|
||||
return;
|
||||
free(fe->name);
|
||||
if (fe->linkname)
|
||||
free(fe->linkname);
|
||||
if (fe->local_filename) {
|
||||
if (fe->local_is_temp) {
|
||||
if (!fe->local_stat.st_mtime)
|
||||
unlink(fe->local_filename);
|
||||
else {
|
||||
struct stat sb;
|
||||
|
||||
if (stat (fe->local_filename, &sb) >=0 &&
|
||||
fe->local_stat.st_mtime == sb.st_mtime)
|
||||
unlink (fe->local_filename); /* Delete only if it hasn't changed */
|
||||
}
|
||||
}
|
||||
free(fe->local_filename);
|
||||
fe->local_filename = 0;
|
||||
}
|
||||
if (fe->remote_filename)
|
||||
free(fe->remote_filename);
|
||||
if (fe->l_stat)
|
||||
free(fe->l_stat);
|
||||
free(fe);
|
||||
}
|
||||
|
||||
static void
|
||||
dir_destructor(void *data)
|
||||
{
|
||||
struct dir *fd = data;
|
||||
|
||||
fd->count--;
|
||||
if (fd->count > 0)
|
||||
return;
|
||||
free(fd->remote_path);
|
||||
linklist_destroy(fd->file_list, direntry_destructor);
|
||||
free(fd);
|
||||
}
|
||||
|
||||
static int
|
||||
get_line_interruptible (char *buffer, int size, int fd)
|
||||
{
|
||||
int n;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < size-1; i++) {
|
||||
n = read (fd, buffer+i, 1);
|
||||
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;
|
||||
}
|
||||
|
||||
static void
|
||||
free_bucket (void *data)
|
||||
{
|
||||
struct connection *bucket = data;
|
||||
|
||||
free(qhost(bucket));
|
||||
free(quser(bucket));
|
||||
if (qcdir(bucket))
|
||||
free(qcdir(bucket));
|
||||
if (qhome(bucket))
|
||||
free(qhome(bucket));
|
||||
if (qupdir(bucket))
|
||||
free(qupdir(bucket));
|
||||
if (bucket->password)
|
||||
wipe_password (bucket->password);
|
||||
linklist_destroy(qdcache(bucket), dir_destructor);
|
||||
free(bucket);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
connection_destructor(void *data)
|
||||
{
|
||||
connection_close (data);
|
||||
free_bucket (data);
|
||||
}
|
||||
|
||||
static void
|
||||
flush_all_directory(struct connection *bucket)
|
||||
{
|
||||
linklist_delete_all(qdcache(bucket), dir_destructor);
|
||||
}
|
||||
|
||||
void X_fill_names (void (*func)(char *))
|
||||
{
|
||||
struct linklist *lptr;
|
||||
char *path_name;
|
||||
struct connection *bucket;
|
||||
|
||||
if (!connections_list)
|
||||
return;
|
||||
lptr = connections_list;
|
||||
do {
|
||||
if ((bucket = lptr->data) != 0){
|
||||
|
||||
path_name = copy_strings ( X_myname, quser (bucket),
|
||||
"@", qhost (bucket),
|
||||
qcdir(bucket), 0);
|
||||
(*func)(path_name);
|
||||
free (path_name);
|
||||
}
|
||||
lptr = lptr->next;
|
||||
} while (lptr != connections_list);
|
||||
}
|
||||
|
||||
|
||||
/* get_path:
|
||||
* makes BUCKET point to the connection bucket descriptor for PATH
|
||||
* returns a malloced string with the pathname relative to BUCKET.
|
||||
*/
|
||||
static char*
|
||||
get_path (struct connection **bucket, char *path)
|
||||
{
|
||||
char *user, *host, *remote_path, *pass;
|
||||
int port;
|
||||
|
||||
#ifndef BROKEN_PATHS
|
||||
if (strncmp (path, X_myname, strlen (X_myname)))
|
||||
return NULL; /* Normal: consider cd /bla/#ftp */
|
||||
#else
|
||||
if (!(path = strstr (path, X_myname)))
|
||||
return NULL;
|
||||
#endif
|
||||
path += strlen (X_myname);
|
||||
|
||||
if (!(remote_path = my_get_host_and_username (path, &host, &user, &port, &pass)))
|
||||
my_errno = ENOENT;
|
||||
else {
|
||||
if ((*bucket = open_link (host, user, port, pass)) == NULL) {
|
||||
free (remote_path);
|
||||
remote_path = NULL;
|
||||
}
|
||||
}
|
||||
free (host);
|
||||
free (user);
|
||||
if (pass)
|
||||
wipe_password (pass);
|
||||
|
||||
if (!remote_path)
|
||||
return NULL;
|
||||
|
||||
/* NOTE: Usage of tildes is deprecated, consider:
|
||||
* cd /#ftp:pavel@hobit
|
||||
* cd ~
|
||||
* And now: what do I want to do? Do I want to go to /home/pavel or to
|
||||
* /#ftp:hobit/home/pavel? I think first has better sense...
|
||||
*/
|
||||
{
|
||||
int f = !strcmp( remote_path, "/~" );
|
||||
if (f || !strncmp( remote_path, "/~/", 3 )) {
|
||||
char *s;
|
||||
s = concat_dir_and_file( qhome (*bucket), remote_path +3-f );
|
||||
free (remote_path);
|
||||
remote_path = s;
|
||||
}
|
||||
}
|
||||
return remote_path;
|
||||
}
|
||||
|
||||
void X_flushdir (void)
|
||||
{
|
||||
force_expiration = 1;
|
||||
}
|
||||
|
||||
/* These variables are for the _ctl routine */
|
||||
static char *localname = NULL;
|
||||
static struct direntry *remoteent;
|
||||
static int remotetotal = 0;
|
||||
static int transfer_started = 0;
|
||||
static char *remotebuffer;
|
||||
static int isremotecopy = 0;
|
||||
|
||||
static int remove_temp_file (char *file_name);
|
||||
|
||||
static int s_setctl (char *path, int ctlop, char *arg)
|
||||
{
|
||||
switch (ctlop) {
|
||||
case MCCTL_REMOVELOCALCOPY:
|
||||
return remove_temp_file (path);
|
||||
|
||||
case MCCTL_SETREMOTECOPY: if (localname) free (localname);
|
||||
localname = strdup (vfs_canon (arg));
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct direntry *
|
||||
_get_file_entry(struct connection *bucket, char *file_name,
|
||||
int op, int flags)
|
||||
{
|
||||
char *p, q;
|
||||
struct direntry *ent;
|
||||
struct linklist *file_list, *lptr;
|
||||
struct dir *dcache;
|
||||
struct stat sb;
|
||||
|
||||
p = strrchr(file_name, '/');
|
||||
q = *p;
|
||||
*p = '\0';
|
||||
dcache = retrieve_dir(bucket, *file_name ? file_name : "/");
|
||||
if (dcache == NULL)
|
||||
return NULL;
|
||||
file_list = dcache->file_list;
|
||||
*p++ = q;
|
||||
if (!*p)
|
||||
p = ".";
|
||||
for (lptr = file_list->next; lptr != file_list; lptr = lptr->next) {
|
||||
ent = lptr->data;
|
||||
if (strcmp(p, ent->name) == 0) {
|
||||
if (S_ISLNK(ent->s.st_mode) && (op & DO_RESOLVE_SYMLINK)) {
|
||||
if (ent->l_stat == NULL) {
|
||||
my_errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
if (S_ISLNK(ent->l_stat->st_mode)) {
|
||||
my_errno = ELOOP;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (ent && (op & DO_OPEN)) {
|
||||
mode_t fmode;
|
||||
|
||||
fmode = S_ISLNK(ent->s.st_mode)
|
||||
? ent->l_stat->st_mode
|
||||
: ent->s.st_mode;
|
||||
if (S_ISDIR(fmode)) {
|
||||
my_errno = EISDIR;
|
||||
return NULL;
|
||||
}
|
||||
if (!S_ISREG(fmode)) {
|
||||
my_errno = EPERM;
|
||||
return NULL;
|
||||
}
|
||||
if ((flags & O_EXCL) && (flags & O_CREAT)) {
|
||||
my_errno = EEXIST;
|
||||
return NULL;
|
||||
}
|
||||
if (ent->remote_filename == NULL) {
|
||||
ent->remote_filename = strdup(file_name);
|
||||
if (ent->remote_filename == NULL) {
|
||||
my_errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (ent->local_filename == NULL ||
|
||||
!ent->local_stat.st_mtime ||
|
||||
stat (ent->local_filename, &sb) < 0 ||
|
||||
sb.st_mtime != ent->local_stat.st_mtime) {
|
||||
int handle;
|
||||
|
||||
if (ent->local_filename){
|
||||
free (ent->local_filename);
|
||||
ent->local_filename = 0;
|
||||
}
|
||||
if (flags & O_TRUNC) {
|
||||
ent->local_filename = tempnam (NULL, X "fs");
|
||||
if (ent->local_filename == NULL) {
|
||||
my_errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
handle = open(ent->local_filename, O_CREAT | O_TRUNC | O_RDWR | O_EXCL, 0600);
|
||||
if (handle < 0) {
|
||||
my_errno = EIO;
|
||||
return NULL;
|
||||
}
|
||||
close(handle);
|
||||
if (stat (ent->local_filename, &ent->local_stat) < 0)
|
||||
ent->local_stat.st_mtime = 0;
|
||||
}
|
||||
else {
|
||||
if (localname != NULL) {
|
||||
isremotecopy = 1;
|
||||
ent->local_is_temp = 0;
|
||||
ent->local_stat.st_mtime = 0;
|
||||
ent->local_filename = strdup (localname);
|
||||
if (!retrieve_file_start (ent)) {
|
||||
isremotecopy = 0;
|
||||
return NULL;
|
||||
}
|
||||
return ent;
|
||||
}
|
||||
if (!retrieve_file(ent))
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (flags & O_TRUNC) {
|
||||
truncate(ent->local_filename, 0);
|
||||
}
|
||||
}
|
||||
return ent;
|
||||
}
|
||||
}
|
||||
if ((op & DO_OPEN) && (flags & O_CREAT)) {
|
||||
int handle;
|
||||
|
||||
ent = xmalloc(sizeof(struct direntry), "struct direntry");
|
||||
ent->freshly_created = 0;
|
||||
ent->tmp_reget = 0;
|
||||
if (ent == NULL) {
|
||||
my_errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
ent->count = 1;
|
||||
ent->linkname = NULL;
|
||||
ent->l_stat = NULL;
|
||||
ent->bucket = bucket;
|
||||
ent->name = strdup(p);
|
||||
ent->remote_filename = strdup(file_name);
|
||||
ent->local_filename = tempnam (NULL, X "fs");
|
||||
if (!ent->name && !ent->remote_filename && !ent->local_filename) {
|
||||
direntry_destructor(ent);
|
||||
my_errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
handle = creat(ent->local_filename, 0700);
|
||||
if (handle == -1) {
|
||||
my_errno = EIO;
|
||||
direntry_destructor(ent);
|
||||
return NULL;
|
||||
}
|
||||
fstat(handle, &ent->s);
|
||||
close(handle);
|
||||
#if 0
|
||||
/* This is very wrong - like this a zero length file will be always created
|
||||
and usually preclude uploading anything more desirable */
|
||||
#if defined(UPLOAD_ZERO_LENGTH_FILE)
|
||||
if (!store_file(ent)) {
|
||||
direntry_destructor(ent);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
if (!linklist_insert(file_list, ent)) {
|
||||
my_errno = ENOMEM;
|
||||
direntry_destructor(ent);
|
||||
return NULL;
|
||||
}
|
||||
ent->freshly_created = 1;
|
||||
return ent;
|
||||
}
|
||||
else {
|
||||
my_errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* this just free's the local temp file. I don't know if the
|
||||
remote file can be used after this without crashing - paul
|
||||
psheer@obsidian.co.za psheer@icon.co.za */
|
||||
static int remove_temp_file (char *file_name)
|
||||
{
|
||||
char *p, q;
|
||||
struct connection *bucket;
|
||||
struct direntry *ent;
|
||||
struct linklist *file_list, *lptr;
|
||||
struct dir *dcache;
|
||||
|
||||
if (!(file_name = get_path (&bucket, file_name)))
|
||||
return -1;
|
||||
p = strrchr (file_name, '/');
|
||||
q = *p;
|
||||
*p = '\0';
|
||||
dcache = retrieve_dir (bucket, *file_name ? file_name : "/");
|
||||
if (dcache == NULL)
|
||||
return -1;
|
||||
file_list = dcache->file_list;
|
||||
*p++ = q;
|
||||
if (!*p)
|
||||
p = ".";
|
||||
for (lptr = file_list->next; lptr != file_list; lptr = lptr->next) {
|
||||
ent = lptr->data;
|
||||
if (strcmp (p, ent->name) == 0) {
|
||||
if (ent->local_filename) {
|
||||
unlink (ent->local_filename);
|
||||
free (ent->local_filename);
|
||||
ent->local_filename = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static struct direntry *
|
||||
get_file_entry(char *path, int op, int flags)
|
||||
{
|
||||
struct connection *bucket;
|
||||
struct direntry *fe;
|
||||
char *remote_path;
|
||||
|
||||
if (!(remote_path = get_path (&bucket, path)))
|
||||
return NULL;
|
||||
isremotecopy = 0;
|
||||
fe = _get_file_entry(bucket, remote_path, op,
|
||||
flags);
|
||||
free(remote_path);
|
||||
#if 0
|
||||
if (op & DO_FREE_RESOURCE)
|
||||
vfs_add_noncurrent_stamps (&X_vfs_ops, (vfsid) bucket, NULL);
|
||||
#endif
|
||||
return fe;
|
||||
}
|
||||
|
||||
#define OPT_FLUSH 1
|
||||
#define OPT_IGNORE_ERROR 2
|
||||
|
||||
static int normal_flush = 1;
|
||||
|
||||
void X_hint_reread(int reread)
|
||||
{
|
||||
if (reread)
|
||||
normal_flush++;
|
||||
else
|
||||
normal_flush--;
|
||||
}
|
||||
|
||||
|
||||
/* The callbacks */
|
||||
|
||||
struct filp {
|
||||
unsigned int has_changed:1;
|
||||
struct direntry *fe;
|
||||
int local_handle;
|
||||
};
|
||||
|
||||
static void *s_open (char *file, int flags, int mode)
|
||||
{
|
||||
struct filp *fp;
|
||||
struct direntry *fe;
|
||||
|
||||
fp = xmalloc(sizeof(struct filp), "struct filp");
|
||||
if (fp == NULL) {
|
||||
my_errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
fe = get_file_entry(file, DO_OPEN | DO_RESOLVE_SYMLINK, flags);
|
||||
if (fe == NULL) {
|
||||
free(fp);
|
||||
return NULL;
|
||||
}
|
||||
if (!isremotecopy) {
|
||||
fp->local_handle = open(fe->local_filename, flags, mode);
|
||||
if (fp->local_handle < 0) {
|
||||
my_errno = errno;
|
||||
free(fp);
|
||||
return NULL;
|
||||
}
|
||||
} else
|
||||
fp->local_handle = -1;
|
||||
#ifdef UPLOAD_ZERO_LENGTH_FILE
|
||||
fp->has_changed = fe->freshly_created;
|
||||
#else
|
||||
fp->has_changed = 0;
|
||||
#endif
|
||||
fp->fe = fe;
|
||||
qlock(fe->bucket)++;
|
||||
fe->count++;
|
||||
return fp;
|
||||
}
|
||||
|
||||
static int s_read (void *data, char *buffer, int count)
|
||||
{
|
||||
struct filp *fp;
|
||||
int n;
|
||||
|
||||
fp = data;
|
||||
n = read(fp->local_handle, buffer, count);
|
||||
if (n < 0)
|
||||
my_errno = errno;
|
||||
return n;
|
||||
}
|
||||
|
||||
static int s_write (void *data, char *buf, int nbyte)
|
||||
{
|
||||
struct filp *fp;
|
||||
int n;
|
||||
|
||||
fp = data;
|
||||
n = write(fp->local_handle, buf, nbyte);
|
||||
if (n < 0)
|
||||
my_errno = errno;
|
||||
fp->has_changed = 1;
|
||||
return n;
|
||||
}
|
||||
|
||||
static int s_close (void *data)
|
||||
{
|
||||
struct filp *fp = data;
|
||||
int result = 0;
|
||||
|
||||
if (fp->has_changed) {
|
||||
if (!store_file(fp->fe))
|
||||
result = -1;
|
||||
if (normal_flush)
|
||||
flush_all_directory(fp->fe->bucket);
|
||||
}
|
||||
if (fp->local_handle >= 0)
|
||||
close(fp->local_handle);
|
||||
qlock(fp->fe->bucket)--;
|
||||
direntry_destructor(fp->fe);
|
||||
free(fp);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int s_errno (void)
|
||||
{
|
||||
return my_errno;
|
||||
}
|
||||
|
||||
|
||||
/* Explanation:
|
||||
* On some operating systems (Slowaris 2 for example)
|
||||
* the d_name member is just a char long (nice trick that break everything),
|
||||
* so we need to set up some space for the filename.
|
||||
*/
|
||||
struct my_dirent {
|
||||
struct dirent dent;
|
||||
#ifdef NEED_EXTRA_DIRENT_BUFFER
|
||||
char extra_buffer [MC_MAXPATHLEN];
|
||||
#endif
|
||||
struct linklist *pos;
|
||||
struct dir *dcache;
|
||||
};
|
||||
|
||||
/* Possible FIXME: what happens if one directory is opened twice ? */
|
||||
|
||||
static void *s_opendir (char *dirname)
|
||||
{
|
||||
struct connection *bucket;
|
||||
char *remote_path;
|
||||
struct my_dirent *dirp;
|
||||
|
||||
if (!(remote_path = get_path (&bucket, dirname)))
|
||||
return NULL;
|
||||
dirp = xmalloc(sizeof(struct my_dirent), "struct my_dirent");
|
||||
if (dirp == NULL) {
|
||||
my_errno = ENOMEM;
|
||||
goto error_return;
|
||||
}
|
||||
dirp->dcache = retrieve_dir(bucket, remote_path);
|
||||
if (dirp->dcache == NULL)
|
||||
goto error_return;
|
||||
dirp->pos = dirp->dcache->file_list->next;
|
||||
free(remote_path);
|
||||
dirp->dcache->count++;
|
||||
return (void *)dirp;
|
||||
error_return:
|
||||
vfs_add_noncurrent_stamps (&X_vfs_ops, (vfsid) bucket, NULL);
|
||||
free(remote_path);
|
||||
free(dirp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *s_readdir (void *data)
|
||||
{
|
||||
struct direntry *fe;
|
||||
struct my_dirent *dirp = data;
|
||||
|
||||
if (dirp->pos == dirp->dcache->file_list)
|
||||
return NULL;
|
||||
fe = dirp->pos->data;
|
||||
strcpy (&(dirp->dent.d_name [0]), fe->name);
|
||||
#ifndef DIRENT_LENGTH_COMPUTED
|
||||
dirp->d_namlen = strlen (dirp->d_name);
|
||||
#endif
|
||||
dirp->pos = dirp->pos->next;
|
||||
return (void *) &dirp->dent;
|
||||
}
|
||||
|
||||
static int s_telldir (void *data)
|
||||
{
|
||||
struct my_dirent *dirp = data;
|
||||
struct linklist *pos;
|
||||
int i = 0;
|
||||
|
||||
pos = dirp->dcache->file_list->next;
|
||||
while( pos!=dirp->dcache->file_list) {
|
||||
if (pos == dirp->pos)
|
||||
return i;
|
||||
pos = pos->next;
|
||||
i++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void s_seekdir (void *data, int pos)
|
||||
{
|
||||
struct my_dirent *dirp = data;
|
||||
int i;
|
||||
|
||||
dirp->pos = dirp->dcache->file_list->next;
|
||||
for (i=0; i<pos; i++)
|
||||
s_readdir(data);
|
||||
}
|
||||
|
||||
static int s_closedir (void *info)
|
||||
{
|
||||
struct my_dirent *dirp = info;
|
||||
dir_destructor(dirp->dcache);
|
||||
free(dirp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s_lstat (char *path, struct stat *buf)
|
||||
{
|
||||
struct direntry *fe;
|
||||
|
||||
fe = get_file_entry(path, DO_FREE_RESOURCE, 0);
|
||||
if (fe) {
|
||||
*buf = fe->s;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int s_stat (char *path, struct stat *buf)
|
||||
{
|
||||
struct direntry *fe;
|
||||
|
||||
fe = get_file_entry(path, DO_RESOLVE_SYMLINK | DO_FREE_RESOURCE, 0);
|
||||
if (fe) {
|
||||
if (!S_ISLNK(fe->s.st_mode))
|
||||
*buf = fe->s;
|
||||
else
|
||||
*buf = *fe->l_stat;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int s_fstat (void *data, struct stat *buf)
|
||||
{
|
||||
struct filp *fp = data;
|
||||
|
||||
if (!S_ISLNK(fp->fe->s.st_mode))
|
||||
*buf = fp->fe->s;
|
||||
else
|
||||
*buf = *fp->fe->l_stat;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int s_readlink (char *path, char *buf, int size)
|
||||
{
|
||||
struct direntry *fe;
|
||||
|
||||
fe = get_file_entry(path, DO_FREE_RESOURCE, 0);
|
||||
if (!fe)
|
||||
return -1;
|
||||
if (!S_ISLNK(fe->s.st_mode)) {
|
||||
my_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (fe->linkname == NULL) {
|
||||
my_errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
if (strlen(fe->linkname) >= size) {
|
||||
my_errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
strncpy(buf, fe->linkname, size);
|
||||
return strlen(fe->linkname);
|
||||
}
|
||||
|
||||
|
||||
static int s_chdir (char *path)
|
||||
{
|
||||
char *remote_path;
|
||||
struct connection *bucket;
|
||||
|
||||
if (!(remote_path = get_path(&bucket, path)))
|
||||
return -1;
|
||||
if (qcdir(bucket))
|
||||
free(qcdir(bucket));
|
||||
qcdir(bucket) = remote_path;
|
||||
bucket->cwd_defered = 1;
|
||||
|
||||
vfs_add_noncurrent_stamps (&X_vfs_ops, (vfsid) bucket, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s_lseek (void *data, off_t offset, int whence)
|
||||
{
|
||||
struct filp *fp = data;
|
||||
|
||||
return lseek(fp->local_handle, offset, whence);
|
||||
}
|
||||
|
||||
|
||||
static vfsid s_getid (char *p, struct vfs_stamping **parent)
|
||||
{
|
||||
struct connection *bucket;
|
||||
char *remote_path;
|
||||
|
||||
*parent = NULL; /* We are not enclosed in any other fs */
|
||||
|
||||
if (!(remote_path = get_path (&bucket, p)))
|
||||
return (vfsid) -1;
|
||||
else {
|
||||
free(remote_path);
|
||||
return (vfsid) bucket;
|
||||
}
|
||||
}
|
||||
|
||||
static int s_nothingisopen (vfsid id)
|
||||
{
|
||||
return qlock((struct connection *)id) == 0;
|
||||
}
|
||||
|
||||
static void s_free (vfsid id)
|
||||
{
|
||||
struct connection *bucket = (struct connection *) id;
|
||||
|
||||
connection_destructor(bucket);
|
||||
linklist_delete(connections_list, bucket);
|
||||
}
|
||||
|
||||
static char *s_getlocalcopy (char *path)
|
||||
{
|
||||
struct filp *fp = (struct filp *) s_open (path, O_RDONLY, 0);
|
||||
char *p;
|
||||
|
||||
if (fp == NULL)
|
||||
return NULL;
|
||||
if (fp->fe->local_filename == NULL) {
|
||||
s_close ((void *) fp);
|
||||
return NULL;
|
||||
}
|
||||
p = strdup (fp->fe->local_filename);
|
||||
qlock(fp->fe->bucket)++;
|
||||
fp->fe->count++;
|
||||
s_close ((void *) fp);
|
||||
return p;
|
||||
}
|
||||
|
||||
static void s_ungetlocalcopy (char *path, char *local, int has_changed)
|
||||
{
|
||||
struct filp *fp = (struct filp *) s_open (path, O_WRONLY, 0);
|
||||
|
||||
if (fp == NULL)
|
||||
return;
|
||||
if (!strcmp (fp->fe->local_filename, local)) {
|
||||
fp->has_changed = has_changed;
|
||||
qlock(fp->fe->bucket)--;
|
||||
direntry_destructor(fp->fe);
|
||||
s_close ((void *) fp);
|
||||
} else {
|
||||
/* Should not happen */
|
||||
s_close ((void *) fp);
|
||||
mc_def_ungetlocalcopy (path, local, has_changed);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
X_done(void)
|
||||
{
|
||||
linklist_destroy(connections_list, connection_destructor);
|
||||
connections_list = NULL;
|
||||
if (logfile)
|
||||
fclose (logfile);
|
||||
logfile = NULL;
|
||||
}
|
@ -5,11 +5,11 @@
|
||||
* 1998 Pavel Machek
|
||||
*/
|
||||
|
||||
static char *X_get_path (char *inname, struct X_archive **archive, int is_dir,
|
||||
static char *get_path (char *inname, struct archive **archive, int is_dir,
|
||||
int do_not_open)
|
||||
{
|
||||
char *buf = strdup( inname );
|
||||
char *res = X_get_path_mangle( buf, archive, is_dir, do_not_open );
|
||||
char *res = get_path_mangle( buf, archive, is_dir, do_not_open );
|
||||
char *res2 = NULL;
|
||||
if (res)
|
||||
res2 = strdup(res);
|
||||
@ -17,11 +17,11 @@ static char *X_get_path (char *inname, struct X_archive **archive, int is_dir,
|
||||
return res2;
|
||||
}
|
||||
|
||||
static struct X_entry*
|
||||
__X_find_entry (struct X_entry *dir, char *name,
|
||||
struct X_loop_protect *list, int make_dirs, int make_file)
|
||||
static struct entry*
|
||||
__find_entry (struct entry *dir, char *name,
|
||||
struct loop_protect *list, int make_dirs, int make_file)
|
||||
{
|
||||
struct X_entry *pent, *pdir;
|
||||
struct entry *pent, *pdir;
|
||||
char *p, *q, *name_end;
|
||||
char c;
|
||||
|
||||
@ -46,7 +46,7 @@ __X_find_entry (struct X_entry *dir, char *name,
|
||||
if (!strcmp (p, ".."))
|
||||
pent = pent->dir;
|
||||
else {
|
||||
if ((pent = __X_resolve_symlinks (pent, list))==NULL){
|
||||
if ((pent = __resolve_symlinks (pent, list))==NULL){
|
||||
*q = c;
|
||||
return NULL;
|
||||
}
|
||||
@ -87,22 +87,22 @@ __X_find_entry (struct X_entry *dir, char *name,
|
||||
q = strchr (p, 0);
|
||||
}
|
||||
if (pent == NULL)
|
||||
Xerrno = ENOENT;
|
||||
my_errno = ENOENT;
|
||||
return pent;
|
||||
}
|
||||
|
||||
static struct X_entry *X_find_entry (struct X_entry *dir, char *name, int make_dirs, int make_file)
|
||||
static struct entry *find_entry (struct entry *dir, char *name, int make_dirs, int make_file)
|
||||
{
|
||||
struct X_entry *res;
|
||||
struct entry *res;
|
||||
|
||||
errloop = 0;
|
||||
notadir = 0;
|
||||
res = __X_find_entry (dir, name, NULL, make_dirs, make_file);
|
||||
res = __find_entry (dir, name, NULL, make_dirs, make_file);
|
||||
if (res == NULL) {
|
||||
if (errloop)
|
||||
Xerrno = ELOOP;
|
||||
my_errno = ELOOP;
|
||||
else if (notadir)
|
||||
Xerrno = ENOTDIR;
|
||||
my_errno = ENOTDIR;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@ -110,29 +110,29 @@ static struct X_entry *X_find_entry (struct X_entry *dir, char *name, int make_d
|
||||
|
||||
static int s_errno (void)
|
||||
{
|
||||
return Xerrno;
|
||||
return my_errno;
|
||||
}
|
||||
|
||||
static void * s_opendir (char *dirname)
|
||||
{
|
||||
struct X_archive *archive;
|
||||
struct archive *archive;
|
||||
char *q;
|
||||
struct X_entry *entry;
|
||||
struct X_entry **info;
|
||||
struct entry *entry;
|
||||
struct entry **info;
|
||||
|
||||
if ((q = X_get_path_mangle (dirname, &archive, 1, 0)) == NULL)
|
||||
if ((q = get_path_mangle (dirname, &archive, 1, 0)) == NULL)
|
||||
return NULL;
|
||||
entry = X_find_entry (archive->root_entry, q, 0, 0);
|
||||
entry = find_entry (archive->root_entry, q, 0, 0);
|
||||
if (entry == NULL)
|
||||
return NULL;
|
||||
if ((entry = X_resolve_symlinks (entry)) == NULL)
|
||||
if ((entry = my_resolve_symlinks (entry)) == NULL)
|
||||
return NULL;
|
||||
if (!S_ISDIR (entry->inode->mode)) {
|
||||
Xerrno = ENOTDIR;
|
||||
my_errno = ENOTDIR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
info = (struct X_entry **) xmalloc (2*sizeof (struct X_entry *), "shared opendir");
|
||||
info = (struct entry **) xmalloc (2*sizeof (struct entry *), "shared opendir");
|
||||
info[0] = entry->inode->first_in_subdir;
|
||||
info[1] = entry->inode->first_in_subdir;
|
||||
|
||||
@ -148,7 +148,7 @@ static void * s_readdir (void *data)
|
||||
#endif
|
||||
} dir;
|
||||
|
||||
struct X_entry **info = (struct X_entry **) data;
|
||||
struct entry **info = (struct entry **) data;
|
||||
|
||||
if (!*info)
|
||||
return NULL;
|
||||
@ -165,8 +165,8 @@ static void * s_readdir (void *data)
|
||||
|
||||
static int s_telldir (void *data)
|
||||
{
|
||||
struct X_entry **info = (struct X_entry **) data;
|
||||
struct X_entry *cur;
|
||||
struct entry **info = (struct entry **) data;
|
||||
struct entry *cur;
|
||||
int num = 0;
|
||||
|
||||
cur = info[1];
|
||||
@ -180,7 +180,7 @@ static int s_telldir (void *data)
|
||||
|
||||
static void s_seekdir (void *data, int offset)
|
||||
{
|
||||
struct X_entry **info = (struct X_entry **) data;
|
||||
struct entry **info = (struct entry **) data;
|
||||
int i;
|
||||
info[0] = info[1];
|
||||
for (i=0; i<offset; i++)
|
||||
@ -193,7 +193,7 @@ static int s_closedir (void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stat_move( struct stat *buf, struct X_inode *inode )
|
||||
static void stat_move( struct stat *buf, struct inode *inode )
|
||||
{
|
||||
buf->st_dev = inode->dev;
|
||||
buf->st_ino = inode->inode;
|
||||
@ -218,20 +218,20 @@ static void stat_move( struct stat *buf, struct X_inode *inode )
|
||||
|
||||
static int s_internal_stat (char *path, struct stat *buf, int resolve)
|
||||
{
|
||||
struct X_archive *archive;
|
||||
struct archive *archive;
|
||||
char *q;
|
||||
struct X_entry *entry;
|
||||
struct X_inode *inode;
|
||||
struct entry *entry;
|
||||
struct inode *inode;
|
||||
char debugbuf[10240];
|
||||
strcpy( debugbuf, path );
|
||||
|
||||
|
||||
if ((q = X_get_path_mangle (path, &archive, 0, 0)) == NULL)
|
||||
if ((q = get_path_mangle (path, &archive, 0, 0)) == NULL)
|
||||
return -1;
|
||||
entry = X_find_entry (archive->root_entry, q, 0, 0);
|
||||
entry = find_entry (archive->root_entry, q, 0, 0);
|
||||
if (entry == NULL)
|
||||
return -1;
|
||||
if (resolve && (entry = X_resolve_symlinks (entry)) == NULL)
|
||||
if (resolve && (entry = my_resolve_symlinks (entry)) == NULL)
|
||||
return -1;
|
||||
inode = entry->inode;
|
||||
stat_move( buf, inode );
|
||||
@ -250,8 +250,8 @@ static int s_lstat (char *path, struct stat *buf)
|
||||
|
||||
static int s_fstat (void *data, struct stat *buf)
|
||||
{
|
||||
struct X_pseudofile *file = (struct X_pseudofile *)data;
|
||||
struct X_inode *inode;
|
||||
struct pseudofile *file = (struct pseudofile *)data;
|
||||
struct inode *inode;
|
||||
|
||||
inode = file->entry->inode;
|
||||
stat_move( buf, inode );
|
||||
@ -260,18 +260,18 @@ static int s_fstat (void *data, struct stat *buf)
|
||||
|
||||
static int s_readlink (char *path, char *buf, int size)
|
||||
{
|
||||
struct X_archive *archive;
|
||||
struct archive *archive;
|
||||
char *q;
|
||||
int i;
|
||||
struct X_entry *entry;
|
||||
struct entry *entry;
|
||||
|
||||
if ((q = X_get_path_mangle (path, &archive, 0, 0)) == NULL)
|
||||
if ((q = get_path_mangle (path, &archive, 0, 0)) == NULL)
|
||||
return -1;
|
||||
entry = X_find_entry (archive->root_entry, q, 0, 0);
|
||||
entry = find_entry (archive->root_entry, q, 0, 0);
|
||||
if (entry == NULL)
|
||||
return -1;
|
||||
if (!S_ISLNK (entry->inode->mode)) {
|
||||
Xerrno = EINVAL;
|
||||
my_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (size > (i = strlen (entry->inode->linkname))) {
|
291
vfs/tar.c
291
vfs/tar.c
@ -41,6 +41,7 @@
|
||||
#include "../src/dialog.h" /* For MSG_ERROR */
|
||||
#include "../src/mem.h"
|
||||
#include "../src/mad.h"
|
||||
#include "../src/main.h"
|
||||
#include "vfs.h"
|
||||
#include "tar.h"
|
||||
#include "names.h"
|
||||
@ -78,15 +79,15 @@ long from_oct (int digs, char *where)
|
||||
return value;
|
||||
}
|
||||
|
||||
static struct tarfs_archive *first_archive = NULL;
|
||||
static int tarerrno = 0;
|
||||
static struct archive *first_archive = NULL;
|
||||
static int my_errno = 0;
|
||||
static struct stat hstat; /* Stat struct corresponding */
|
||||
static char *current_file_name, *current_link_name;
|
||||
static struct tarfs_entry *tarfs_find_entry (struct tarfs_entry *dir, char *name, int make_dirs, int make_file);
|
||||
static struct entry *find_entry (struct entry *dir, char *name, int make_dirs, int make_file);
|
||||
|
||||
void tarfs_fill_names (void (*func)(char *))
|
||||
{
|
||||
struct tarfs_archive *a = first_archive;
|
||||
struct archive *a = first_archive;
|
||||
char *name;
|
||||
|
||||
while (a){
|
||||
@ -98,12 +99,12 @@ void tarfs_fill_names (void (*func)(char *))
|
||||
}
|
||||
}
|
||||
|
||||
static void make_dot_doubledot (struct tarfs_entry *ent)
|
||||
static void make_dot_doubledot (struct entry *ent)
|
||||
{
|
||||
struct tarfs_entry *entry = (struct tarfs_entry *)
|
||||
xmalloc (sizeof (struct tarfs_entry), "Tar: tarfs_entry");
|
||||
struct tarfs_entry *parentry = ent->dir;
|
||||
struct tarfs_inode *inode = ent->inode, *parent;
|
||||
struct entry *entry = (struct entry *)
|
||||
xmalloc (sizeof (struct entry), "Tar: entry");
|
||||
struct entry *parentry = ent->dir;
|
||||
struct inode *inode = ent->inode, *parent;
|
||||
|
||||
parent = (parentry != NULL) ? parentry->inode : NULL;
|
||||
entry->name = strdup (".");
|
||||
@ -117,8 +118,8 @@ static void make_dot_doubledot (struct tarfs_entry *ent)
|
||||
inode->first_in_subdir = entry;
|
||||
inode->last_in_subdir = entry;
|
||||
inode->nlink++;
|
||||
entry->next_in_dir = (struct tarfs_entry *)
|
||||
xmalloc (sizeof (struct tarfs_entry), "Tar: tarfs_entry");
|
||||
entry->next_in_dir = (struct entry *)
|
||||
xmalloc (sizeof (struct entry), "Tar: entry");
|
||||
entry=entry->next_in_dir;
|
||||
entry->name = strdup ("..");
|
||||
entry->has_changed = 0;
|
||||
@ -139,16 +140,16 @@ static void make_dot_doubledot (struct tarfs_entry *ent)
|
||||
}
|
||||
}
|
||||
|
||||
static struct tarfs_entry *generate_entry (struct tarfs_archive *archive,
|
||||
char *name, struct tarfs_entry *parentry, mode_t mode)
|
||||
static struct entry *generate_entry (struct archive *archive,
|
||||
char *name, struct entry *parentry, mode_t mode)
|
||||
{
|
||||
mode_t myumask;
|
||||
struct tarfs_inode *inode, *parent;
|
||||
struct tarfs_entry *entry;
|
||||
struct inode *inode, *parent;
|
||||
struct entry *entry;
|
||||
|
||||
parent = (parentry != NULL) ? parentry->inode : NULL;
|
||||
entry = (struct tarfs_entry *)
|
||||
xmalloc (sizeof (struct tarfs_entry), "Tar: tarfs_entry");
|
||||
entry = (struct entry *)
|
||||
xmalloc (sizeof (struct entry), "Tar: entry");
|
||||
|
||||
entry->name = strdup (name);
|
||||
entry->has_changed = 0;
|
||||
@ -162,8 +163,8 @@ static struct tarfs_entry *generate_entry (struct tarfs_archive *archive,
|
||||
parent->last_in_subdir->next_in_dir = entry;
|
||||
parent->last_in_subdir = entry;
|
||||
}
|
||||
inode = (struct tarfs_inode *)
|
||||
xmalloc (sizeof (struct tarfs_inode), "Tar: tarfs_inode");
|
||||
inode = (struct inode *)
|
||||
xmalloc (sizeof (struct inode), "Tar: inode");
|
||||
entry->inode = inode;
|
||||
inode->local_filename = NULL;
|
||||
inode->has_changed = 0;
|
||||
@ -203,12 +204,12 @@ static struct tarfs_entry *generate_entry (struct tarfs_archive *archive,
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void free_entries (struct tarfs_entry *entry)
|
||||
static void free_entries (struct entry *entry)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void free_archive (struct tarfs_archive *archive)
|
||||
static void free_archive (struct archive *archive)
|
||||
{
|
||||
long l;
|
||||
|
||||
@ -220,10 +221,8 @@ static void free_archive (struct tarfs_archive *archive)
|
||||
free (archive->block_ptr);
|
||||
}
|
||||
} else {
|
||||
if (archive->is_gzipped == tar_uncompressed_local) {
|
||||
mc_unlink (archive->tmpname);
|
||||
if (archive->tmpname)
|
||||
free (archive->tmpname);
|
||||
}
|
||||
if (archive->fd != -1)
|
||||
mc_close(archive->fd);
|
||||
}
|
||||
@ -246,7 +245,7 @@ static INLINE int gzip_limit_ok (int size)
|
||||
*
|
||||
* Returns: 0 on failure
|
||||
*/
|
||||
static INLINE int load_compressed_tar (struct tarfs_archive *current_archive,
|
||||
static INLINE int load_compressed_tar (struct archive *current_archive,
|
||||
int size, int fd, int type)
|
||||
{
|
||||
int pipehandle, i;
|
||||
@ -337,76 +336,39 @@ static INLINE int load_compressed_tar (struct tarfs_archive *current_archive,
|
||||
}
|
||||
|
||||
/* Returns a file handle of the opened local tar file or -1 on error */
|
||||
static INLINE int uncompress_tar_file (struct tarfs_archive *current_archive,
|
||||
static INLINE int uncompress_tar_file (struct archive *current_archive,
|
||||
int size, int fd, int type)
|
||||
{
|
||||
FILE *f;
|
||||
char *command;
|
||||
int i, result;
|
||||
int dash_number = 0;
|
||||
char buffer [8192]; /* Changed to 8K: better transfer size */
|
||||
|
||||
current_archive->is_gzipped = tar_uncompressed_local;
|
||||
current_archive->tmpname = strdup (tempnam (NULL, "tarfs"));
|
||||
|
||||
/* Some security is sometimes neccessary :) */
|
||||
command = copy_strings ("touch ", current_archive->tmpname,
|
||||
" ; chmod 0600 ", current_archive->tmpname, " ; ",
|
||||
decompress_command (type),
|
||||
"2>/dev/null >", current_archive->tmpname, NULL);
|
||||
|
||||
if ((f = popen (command, "w")) == NULL) {
|
||||
mc_close (fd);
|
||||
free_archive (current_archive);
|
||||
free (command);
|
||||
return -1;
|
||||
}
|
||||
free (command);
|
||||
|
||||
while ((i = mc_read (fd, buffer, sizeof (buffer))) > 0){
|
||||
if ((dash_number++ % 64) == 0)
|
||||
rotate_dash ();
|
||||
fwrite (buffer, 1, i, f);
|
||||
if (ferror (f)) {
|
||||
pclose (f);
|
||||
#ifdef SCO_FLAVOR
|
||||
waitpid(-1,NULL,WNOHANG);
|
||||
#endif /* SCO_FLAVOR */
|
||||
mc_close (fd);
|
||||
free_archive (current_archive);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
int result;
|
||||
|
||||
pclose (f);
|
||||
#ifdef SCO_FLAVOR
|
||||
waitpid(-1,NULL,WNOHANG);
|
||||
#endif /* SCO_FLAVOR */
|
||||
mc_close (fd);
|
||||
/* From time we have sfs this function is pretty trivial */
|
||||
current_archive->is_gzipped = tar_uncompressed_local;
|
||||
current_archive->tmpname = copy_strings( current_archive->name, "#ugz", NULL );
|
||||
|
||||
result = mc_open (current_archive->tmpname, O_RDONLY);
|
||||
if (result == -1){
|
||||
if (result == -1)
|
||||
free_archive (current_archive);
|
||||
return -1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Returns fd of the open tar file */
|
||||
static int open_tar_archive (char *name, struct tarfs_archive **pparc)
|
||||
static int open_tar_archive (char *name, struct archive **pparc)
|
||||
{
|
||||
static dev_t __tar_no = 0;
|
||||
int result, type;
|
||||
long size;
|
||||
mode_t mode;
|
||||
struct tarfs_archive *current_archive;
|
||||
static struct tarfs_entry *root_entry;
|
||||
struct archive *current_archive;
|
||||
static struct entry *root_entry;
|
||||
|
||||
result = mc_open (name, O_RDONLY);
|
||||
if (result == -1)
|
||||
if (result == -1) {
|
||||
message_2s (1, MSG_ERROR, _("Couldn't open tar archive\n%s"), name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
current_archive = (struct tarfs_archive *)
|
||||
xmalloc (sizeof (struct tarfs_archive), "Tar archive");
|
||||
current_archive = (struct archive *)
|
||||
xmalloc (sizeof (struct archive), "Tar archive");
|
||||
current_archive->current_tar_position = 0;
|
||||
current_archive->name = strdup (name);
|
||||
current_archive->__inode_counter = 0;
|
||||
@ -415,18 +377,23 @@ static int open_tar_archive (char *name, struct tarfs_archive **pparc)
|
||||
current_archive->next = first_archive;
|
||||
current_archive->fd_usage = 0;
|
||||
current_archive->fd = -1;
|
||||
current_archive->tmpname = NULL;
|
||||
size = is_gunzipable (result, &type);
|
||||
mc_lseek (result, 0, SEEK_SET);
|
||||
|
||||
/* Find out the method to handle this tar file */
|
||||
if (size > 0 && gzip_limit_ok (size)) {
|
||||
if (load_compressed_tar (current_archive, size, result, type) == 0)
|
||||
if (load_compressed_tar (current_archive, size, result, type) == 0) {
|
||||
message_2s (1, MSG_ERROR, _("Couldn't load compressed tar\n%s"), name);
|
||||
return -1;
|
||||
}
|
||||
result = 0;
|
||||
} else if (size > 0) {
|
||||
result = uncompress_tar_file (current_archive, size, result, type);
|
||||
if (result == -1)
|
||||
if (result == -1) {
|
||||
message_2s (1, MSG_ERROR, _("Couldn't uncompress tar archive\n%s"), name);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
current_archive->is_gzipped = tar_normal;
|
||||
}
|
||||
@ -455,12 +422,12 @@ static int open_tar_archive (char *name, struct tarfs_archive **pparc)
|
||||
return result;
|
||||
}
|
||||
|
||||
static int get_current_position (struct tarfs_archive *archive, int tard)
|
||||
static int get_current_position (struct archive *archive, int tard)
|
||||
{
|
||||
return archive->current_tar_position;
|
||||
}
|
||||
|
||||
static union record *find_current_record (struct tarfs_archive *archive, long pos)
|
||||
static union record *find_current_record (struct archive *archive, long pos)
|
||||
{
|
||||
long l, l2;
|
||||
static union record *ur;
|
||||
@ -477,7 +444,7 @@ static union record *find_current_record (struct tarfs_archive *archive, long po
|
||||
|
||||
static union record rec_buf;
|
||||
|
||||
static union record *get_next_record (struct tarfs_archive *archive, int tard)
|
||||
static union record *get_next_record (struct archive *archive, int tard)
|
||||
{
|
||||
if (archive->is_gzipped == targz_growing) {
|
||||
bcopy (archive->current_record, rec_buf.charptr, RECORDSIZE);
|
||||
@ -488,7 +455,7 @@ static union record *get_next_record (struct tarfs_archive *archive, int tard)
|
||||
return &rec_buf;
|
||||
}
|
||||
|
||||
static void skip_n_records (struct tarfs_archive *archive, int tard, int n)
|
||||
static void skip_n_records (struct archive *archive, int tard, int n)
|
||||
{
|
||||
if (archive->is_gzipped == targz_growing)
|
||||
archive->current_record = find_current_record (archive, archive->current_tar_position + n * RECORDSIZE);
|
||||
@ -502,7 +469,7 @@ static void skip_n_records (struct tarfs_archive *archive, int tard, int n)
|
||||
* 2 for a record full of zeros (EOF marker).
|
||||
*
|
||||
*/
|
||||
static int read_header (struct tarfs_archive *archive, int tard)
|
||||
static int read_header (struct archive *archive, int tard)
|
||||
{
|
||||
register int i;
|
||||
register long sum, signed_sum, recsum;
|
||||
@ -599,8 +566,8 @@ static int read_header (struct tarfs_archive *archive, int tard)
|
||||
#endif
|
||||
goto recurse;
|
||||
} else {
|
||||
struct tarfs_entry *entry, *pent;
|
||||
struct tarfs_inode *inode;
|
||||
struct entry *entry, *pent;
|
||||
struct inode *inode;
|
||||
long data_position;
|
||||
char *p, *q;
|
||||
int len;
|
||||
@ -635,12 +602,12 @@ static int read_header (struct tarfs_archive *archive, int tard)
|
||||
q = current_file_name;
|
||||
}
|
||||
|
||||
pent = tarfs_find_entry (archive->root_entry, q, 1, 0);
|
||||
pent = find_entry (archive->root_entry, q, 1, 0);
|
||||
if (pent == NULL) {
|
||||
message_1s (1, MSG_ERROR, _("Inconsistent tar archive"));
|
||||
}
|
||||
|
||||
entry = (struct tarfs_entry *) xmalloc (sizeof (struct tarfs_entry), "Tar: tarfs_entry");
|
||||
entry = (struct entry *) xmalloc (sizeof (struct entry), "Tar: entry");
|
||||
entry->name = strdup (p);
|
||||
entry->has_changed = 0;
|
||||
entry->header_offset = header_position;
|
||||
@ -656,7 +623,7 @@ static int read_header (struct tarfs_archive *archive, int tard)
|
||||
free (current_file_name);
|
||||
|
||||
if (header->header.linkflag == LF_LINK) {
|
||||
pent = tarfs_find_entry (archive->root_entry, current_link_name, 0, 0);
|
||||
pent = find_entry (archive->root_entry, current_link_name, 0, 0);
|
||||
if (pent == NULL) {
|
||||
message_1s (1, MSG_ERROR, _("Inconsistent tar archive"));
|
||||
} else {
|
||||
@ -672,7 +639,7 @@ static int read_header (struct tarfs_archive *archive, int tard)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
inode = (struct tarfs_inode *) xmalloc (sizeof (struct tarfs_inode), "Tar: tarfs_inode");
|
||||
inode = (struct inode *) xmalloc (sizeof (struct inode), "Tar: inode");
|
||||
entry->inode = inode;
|
||||
inode->local_filename = NULL;
|
||||
inode->has_changed = 0;
|
||||
@ -750,12 +717,12 @@ static int read_header (struct tarfs_archive *archive, int tard)
|
||||
* Main loop for reading an archive.
|
||||
* Returns 0 on success, -1 on error.
|
||||
*/
|
||||
int read_tar_archive (char *name, struct tarfs_archive **pparc)
|
||||
int read_tar_archive (char *name, struct archive **pparc)
|
||||
{
|
||||
int status = 3; /* Initial status at start of archive */
|
||||
int prev_status;
|
||||
int tard;
|
||||
struct tarfs_archive *archive;
|
||||
struct archive *archive;
|
||||
|
||||
if ((tard = open_tar_archive (name, &archive)) == -1) { /* Open for reading */
|
||||
message_2s (1, MSG_ERROR, _("Couldn't open tar archive\n%s"), name);
|
||||
@ -801,18 +768,18 @@ int read_tar_archive (char *name, struct tarfs_archive **pparc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *tarfs_get_path (char *inname, struct tarfs_archive **archive, int is_dir,
|
||||
static char *get_path (char *inname, struct archive **archive, int is_dir,
|
||||
int do_not_open);
|
||||
|
||||
/* Returns path inside argument. Returned char* is inside inname, which is mangled
|
||||
* by this operation (so you must not free it's return value)
|
||||
*/
|
||||
static char *tarfs_get_path_mangle (char *inname, struct tarfs_archive **archive, int is_dir,
|
||||
static char *get_path_mangle (char *inname, struct archive **archive, int is_dir,
|
||||
int do_not_open)
|
||||
{
|
||||
char *local, *archive_name;
|
||||
int result = -1;
|
||||
struct tarfs_archive *parc;
|
||||
struct archive *parc;
|
||||
struct vfs_stamping *parent;
|
||||
vfs *v;
|
||||
struct stat stat_buf;
|
||||
@ -845,7 +812,7 @@ static char *tarfs_get_path_mangle (char *inname, struct tarfs_archive **archive
|
||||
else
|
||||
result = read_tar_archive (archive_name, &parc);
|
||||
if (result == -1) {
|
||||
tarerrno = EIO;
|
||||
my_errno = EIO;
|
||||
return NULL;
|
||||
}
|
||||
v = vfs_type (archive_name);
|
||||
@ -864,23 +831,23 @@ return_success:
|
||||
return local;
|
||||
}
|
||||
|
||||
struct tarfs_loop_protect {
|
||||
struct tarfs_entry *entry;
|
||||
struct tarfs_loop_protect *next;
|
||||
struct loop_protect {
|
||||
struct entry *entry;
|
||||
struct loop_protect *next;
|
||||
};
|
||||
static int errloop;
|
||||
static int notadir;
|
||||
|
||||
static struct tarfs_entry *
|
||||
__tarfs_find_entry (struct tarfs_entry *dir, char *name,
|
||||
struct tarfs_loop_protect *list, int make_dirs, int make_file);
|
||||
static struct entry *
|
||||
__find_entry (struct entry *dir, char *name,
|
||||
struct loop_protect *list, int make_dirs, int make_file);
|
||||
|
||||
static struct tarfs_entry *
|
||||
__tarfs_resolve_symlinks (struct tarfs_entry *entry,
|
||||
struct tarfs_loop_protect *list)
|
||||
static struct entry *
|
||||
__resolve_symlinks (struct entry *entry,
|
||||
struct loop_protect *list)
|
||||
{
|
||||
struct tarfs_entry *pent;
|
||||
struct tarfs_loop_protect *looping;
|
||||
struct entry *pent;
|
||||
struct loop_protect *looping;
|
||||
|
||||
if (!S_ISLNK (entry->inode->mode))
|
||||
return entry;
|
||||
@ -889,68 +856,68 @@ __tarfs_resolve_symlinks (struct tarfs_entry *entry,
|
||||
errloop = 1;
|
||||
return NULL;
|
||||
}
|
||||
looping = (struct tarfs_loop_protect *)
|
||||
xmalloc (sizeof (struct tarfs_loop_protect),
|
||||
looping = (struct loop_protect *)
|
||||
xmalloc (sizeof (struct loop_protect),
|
||||
"Tar: symlink looping protection");
|
||||
looping->entry = entry;
|
||||
looping->next = list;
|
||||
pent = __tarfs_find_entry (entry->dir, entry->inode->linkname, looping, 0, 0);
|
||||
pent = __find_entry (entry->dir, entry->inode->linkname, looping, 0, 0);
|
||||
free (looping);
|
||||
if (pent == NULL)
|
||||
tarerrno = ENOENT;
|
||||
my_errno = ENOENT;
|
||||
return pent;
|
||||
}
|
||||
|
||||
static struct tarfs_entry *tarfs_resolve_symlinks (struct tarfs_entry *entry)
|
||||
static struct entry *my_resolve_symlinks (struct entry *entry)
|
||||
{
|
||||
struct tarfs_entry *res;
|
||||
struct entry *res;
|
||||
|
||||
errloop = 0;
|
||||
notadir = 0;
|
||||
res = __tarfs_resolve_symlinks (entry, NULL);
|
||||
res = __resolve_symlinks (entry, NULL);
|
||||
if (res == NULL) {
|
||||
if (errloop)
|
||||
tarerrno = ELOOP;
|
||||
my_errno = ELOOP;
|
||||
else if (notadir)
|
||||
tarerrno = ENOTDIR;
|
||||
my_errno = ENOTDIR;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
struct tar_pseudofile {
|
||||
struct tarfs_archive *archive;
|
||||
struct pseudofile {
|
||||
struct archive *archive;
|
||||
long pos;
|
||||
long begin;
|
||||
long end;
|
||||
struct tarfs_entry *entry;
|
||||
struct entry *entry;
|
||||
};
|
||||
|
||||
static struct tarfs_entry *tarfs_find_entry (struct tarfs_entry *dir, char *name, int make_dirs, int make_file);
|
||||
static struct entry *find_entry (struct entry *dir, char *name, int make_dirs, int make_file);
|
||||
|
||||
static void *tar_open (char *file, int flags, int mode)
|
||||
{
|
||||
struct tar_pseudofile *tar_info;
|
||||
struct tarfs_archive *archive;
|
||||
struct pseudofile *tar_info;
|
||||
struct archive *archive;
|
||||
char *q;
|
||||
struct tarfs_entry *entry;
|
||||
struct entry *entry;
|
||||
|
||||
if ((q = tarfs_get_path_mangle (file, &archive, 0, 0)) == NULL)
|
||||
if ((q = get_path_mangle (file, &archive, 0, 0)) == NULL)
|
||||
return NULL;
|
||||
entry = tarfs_find_entry (archive->root_entry, q, 0, 0);
|
||||
entry = find_entry (archive->root_entry, q, 0, 0);
|
||||
if (entry == NULL)
|
||||
return NULL;
|
||||
if ((entry = tarfs_resolve_symlinks (entry)) == NULL)
|
||||
if ((entry = my_resolve_symlinks (entry)) == NULL)
|
||||
return NULL;
|
||||
if (S_ISDIR (entry->inode->mode)) {
|
||||
tarerrno = EISDIR;
|
||||
my_errno = EISDIR;
|
||||
return NULL;
|
||||
}
|
||||
if ((flags & O_ACCMODE) != O_RDONLY) {
|
||||
tarerrno = EROFS; /* At the moment we are RO */
|
||||
my_errno = EROFS; /* At the moment we are RO */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tar_info = (struct tar_pseudofile *) xmalloc (sizeof (struct tar_pseudofile), "Tar: tar_open");
|
||||
tar_info = (struct pseudofile *) xmalloc (sizeof (struct pseudofile), "Tar: tar_open");
|
||||
tar_info->archive = archive;
|
||||
tar_info->pos = 0;
|
||||
tar_info->begin = entry->inode->data_offset;
|
||||
@ -966,12 +933,12 @@ static void *tar_open (char *file, int flags, int mode)
|
||||
|
||||
static int tar_read (void *data, char *buffer, int count)
|
||||
{
|
||||
struct tar_pseudofile *file = (struct tar_pseudofile *)data;
|
||||
struct pseudofile *file = (struct pseudofile *)data;
|
||||
|
||||
if (file->archive->is_gzipped != targz_growing &&
|
||||
mc_lseek (file->archive->fd, file->begin + file->pos, SEEK_SET) !=
|
||||
file->begin + file->pos) {
|
||||
tarerrno = EIO;
|
||||
my_errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1005,7 +972,7 @@ static int tar_read (void *data, char *buffer, int count)
|
||||
}
|
||||
}
|
||||
else if ((count = mc_read (file->archive->fd, buffer, count)) == -1) {
|
||||
tarerrno = errno;
|
||||
my_errno = errno;
|
||||
return -1;
|
||||
}
|
||||
file->pos += count;
|
||||
@ -1014,9 +981,9 @@ static int tar_read (void *data, char *buffer, int count)
|
||||
|
||||
static int tar_close (void *data)
|
||||
{
|
||||
struct tar_pseudofile *file;
|
||||
struct pseudofile *file;
|
||||
|
||||
file = (struct tar_pseudofile *)data;
|
||||
file = (struct pseudofile *)data;
|
||||
|
||||
file->archive->fd_usage--;
|
||||
if (!file->archive->fd_usage) {
|
||||
@ -1041,21 +1008,7 @@ static int tar_close (void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define X_pseudofile tar_pseudofile
|
||||
#define Xerrno tarerrno
|
||||
|
||||
#define X_entry tarfs_entry
|
||||
#define X_archive tarfs_archive
|
||||
#define X_get_path tarfs_get_path
|
||||
#define X_get_path_mangle tarfs_get_path_mangle
|
||||
#define X_find_entry tarfs_find_entry
|
||||
#define X_resolve_symlinks tarfs_resolve_symlinks
|
||||
#define X_inode tarfs_inode
|
||||
#define __X_find_entry __tarfs_find_entry
|
||||
#define __X_resolve_symlinks __tarfs_resolve_symlinks
|
||||
#define X_loop_protect tarfs_loop_protect
|
||||
|
||||
#include "shared.c"
|
||||
#include "shared_tar_ext.c"
|
||||
|
||||
static int tar_chmod (char *path, int mode)
|
||||
{ /* Fixme: are you sure? IMO this is guaranteed to fail */
|
||||
@ -1069,27 +1022,27 @@ static int tar_chown (char *path, int owner, int group)
|
||||
|
||||
static int tar_chdir (char *path)
|
||||
{
|
||||
struct tarfs_archive *archive;
|
||||
struct archive *archive;
|
||||
char *q;
|
||||
struct tarfs_entry *entry;
|
||||
struct entry *entry;
|
||||
|
||||
tarerrno = ENOTDIR;
|
||||
if ((q = tarfs_get_path_mangle (path, &archive, 1, 0)) == NULL)
|
||||
my_errno = ENOTDIR;
|
||||
if ((q = get_path_mangle (path, &archive, 1, 0)) == NULL)
|
||||
return -1;
|
||||
entry = tarfs_find_entry (archive->root_entry, q, 0, 0);
|
||||
entry = find_entry (archive->root_entry, q, 0, 0);
|
||||
if (!entry)
|
||||
return -1;
|
||||
entry = tarfs_resolve_symlinks (entry);
|
||||
entry = my_resolve_symlinks (entry);
|
||||
if ((!entry) || (!S_ISDIR (entry->inode->mode)))
|
||||
return -1;
|
||||
entry->inode->archive->current_dir = entry;
|
||||
tarerrno = 0;
|
||||
my_errno = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tar_lseek (void *data, off_t offset, int whence)
|
||||
{
|
||||
struct tar_pseudofile *file = (struct tar_pseudofile *) data;
|
||||
struct pseudofile *file = (struct pseudofile *) data;
|
||||
|
||||
switch (whence) {
|
||||
case SEEK_CUR:
|
||||
@ -1108,14 +1061,14 @@ static int tar_lseek (void *data, off_t offset, int whence)
|
||||
|
||||
static vfsid tar_getid (char *path, struct vfs_stamping **parent)
|
||||
{
|
||||
struct tarfs_archive *archive;
|
||||
struct archive *archive;
|
||||
vfs *v;
|
||||
char *p;
|
||||
vfsid id;
|
||||
struct vfs_stamping *par;
|
||||
|
||||
*parent = NULL;
|
||||
if (!(p = tarfs_get_path (path, &archive, 0, 1)))
|
||||
if (!(p = get_path (path, &archive, 0, 1)))
|
||||
return (vfsid) -1;
|
||||
free(p);
|
||||
v = vfs_type (archive->name);
|
||||
@ -1132,17 +1085,17 @@ static vfsid tar_getid (char *path, struct vfs_stamping **parent)
|
||||
|
||||
static int tar_nothingisopen (vfsid id)
|
||||
{
|
||||
if (((struct tarfs_archive *)id)->fd_usage <= 0)
|
||||
if (((struct archive *)id)->fd_usage <= 0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_entry (struct tarfs_entry *e)
|
||||
static void free_entry (struct entry *e)
|
||||
{
|
||||
int i = --(e->inode->nlink);
|
||||
if (S_ISDIR (e->inode->mode) && e->inode->first_in_subdir != NULL) {
|
||||
struct tarfs_entry *f = e->inode->first_in_subdir;
|
||||
struct entry *f = e->inode->first_in_subdir;
|
||||
|
||||
e->inode->first_in_subdir = NULL;
|
||||
free_entry (f);
|
||||
@ -1164,8 +1117,8 @@ static void free_entry (struct tarfs_entry *e)
|
||||
|
||||
static void tar_free (vfsid id)
|
||||
{
|
||||
struct tarfs_archive *parc;
|
||||
struct tarfs_archive *archive = (struct tarfs_archive *)id;
|
||||
struct archive *parc;
|
||||
struct archive *archive = (struct archive *)id;
|
||||
|
||||
free_entry (archive->root_entry);
|
||||
if (archive == first_archive) {
|
||||
@ -1182,18 +1135,18 @@ static void tar_free (vfsid id)
|
||||
|
||||
static char *tar_getlocalcopy (char *path)
|
||||
{
|
||||
struct tarfs_archive *archive;
|
||||
struct archive *archive;
|
||||
char *p, *q;
|
||||
struct tarfs_entry *entry;
|
||||
struct entry *entry;
|
||||
char buf[MC_MAXPATHLEN];
|
||||
|
||||
strcpy( buf, path );
|
||||
if ((q = tarfs_get_path_mangle (path, &archive, 1, 0)) == NULL)
|
||||
if ((q = get_path_mangle (path, &archive, 1, 0)) == NULL)
|
||||
return NULL;
|
||||
entry = tarfs_find_entry (archive->root_entry, q, 0, 0);
|
||||
entry = find_entry (archive->root_entry, q, 0, 0);
|
||||
if (entry == NULL)
|
||||
return NULL;
|
||||
if ((entry = tarfs_resolve_symlinks (entry)) == NULL)
|
||||
if ((entry = my_resolve_symlinks (entry)) == NULL)
|
||||
return NULL;
|
||||
|
||||
if (entry->inode->local_filename != NULL)
|
||||
|
28
vfs/tar.h
28
vfs/tar.h
@ -157,34 +157,34 @@ union record {
|
||||
|
||||
#ifndef TAR_NAMES
|
||||
|
||||
struct tarfs_inode;
|
||||
struct inode;
|
||||
|
||||
struct tarfs_entry {
|
||||
struct entry {
|
||||
int has_changed;
|
||||
long header_offset; /* -1 if not in stored in archive */
|
||||
int header_size;
|
||||
struct tarfs_entry *next_in_dir;
|
||||
struct tarfs_entry *dir;
|
||||
struct entry *next_in_dir;
|
||||
struct entry *dir;
|
||||
long extended_offset; /* -1 if not present */
|
||||
int extended_size;
|
||||
|
||||
char *name;
|
||||
struct tarfs_inode *inode;
|
||||
struct inode *inode;
|
||||
};
|
||||
|
||||
struct tarfs_archive;
|
||||
struct archive;
|
||||
|
||||
struct tarfs_inode {
|
||||
struct inode {
|
||||
int has_changed;
|
||||
int is_open;
|
||||
nlink_t nlink;
|
||||
struct tarfs_entry *first_in_subdir; /* only used if linkflag == L_DIR */
|
||||
struct tarfs_entry *last_in_subdir;
|
||||
struct entry *first_in_subdir; /* only used if linkflag == L_DIR */
|
||||
struct entry *last_in_subdir;
|
||||
long data_offset;
|
||||
char *local_filename;
|
||||
ino_t inode; /* This is inode # */
|
||||
dev_t dev; /* This is an internal identification of the tar archive */
|
||||
struct tarfs_archive *archive; /* And this is an archive structure */
|
||||
struct archive *archive; /* And this is an archive structure */
|
||||
dev_t rdev;
|
||||
int std; /* 0 if old Unix inode */
|
||||
|
||||
@ -199,15 +199,15 @@ struct tarfs_inode {
|
||||
time_t ctime;
|
||||
};
|
||||
|
||||
struct tarfs_archive {
|
||||
struct archive {
|
||||
char *name;
|
||||
struct stat tarstat;
|
||||
int is_gzipped;
|
||||
dev_t rdev;
|
||||
ino_t __inode_counter;
|
||||
struct tarfs_entry *root_entry;
|
||||
struct tarfs_entry *current_dir;
|
||||
struct tarfs_archive *next;
|
||||
struct entry *root_entry;
|
||||
struct entry *current_dir;
|
||||
struct archive *next;
|
||||
long current_tar_position;
|
||||
int fd;
|
||||
int fd_usage; /* Zero means fd is invalid, otherwise is number of
|
||||
|
@ -178,12 +178,24 @@ char *get_host_and_username (char *path, char **host, char **user, int *port,
|
||||
/* Check if the host comes with a port spec, if so, chop it */
|
||||
colon = strchr (rest, ':');
|
||||
if (colon){
|
||||
*port = atoi (colon+1);
|
||||
|
||||
if (*port <= 0 || *port >= 65536)
|
||||
*port = 21;
|
||||
*colon = 0;
|
||||
if (sscanf(colon+1, "%d", port)==1) {
|
||||
if (*port <= 0 || *port >= 65536)
|
||||
*port = default_port;
|
||||
} else {
|
||||
while(1) {
|
||||
colon++;
|
||||
switch(*colon) {
|
||||
case 'C': *port = 1;
|
||||
break;
|
||||
case 'r': *port = 2;
|
||||
break;
|
||||
case 0: goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
done:
|
||||
*host = strdup (rest);
|
||||
|
||||
free (pcopy);
|
||||
|
350
vfs/vfs.c
350
vfs/vfs.c
@ -19,6 +19,10 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Warning: funtions like extfs_lstat() have right to destroy any
|
||||
* strings you pass to them. This is acutally ok as you strdup what
|
||||
* you are passing to them, anyway; still, beware. */
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* For atol() */
|
||||
@ -86,7 +90,7 @@ static struct {
|
||||
vfs *operations;
|
||||
} vfs_file_table [MAX_VFS_FILES];
|
||||
|
||||
static int get_bucket ()
|
||||
static int get_bucket (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -95,8 +99,7 @@ static int get_bucket ()
|
||||
if (!vfs_file_table [i].fs_info)
|
||||
return i;
|
||||
}
|
||||
fprintf (stderr, "No more virtual file handles\n");
|
||||
exit (1);
|
||||
vfs_die ("No more virtual file handles");
|
||||
}
|
||||
|
||||
vfs *vfs_type_from_op (char *path)
|
||||
@ -111,6 +114,8 @@ vfs *vfs_type_from_op (char *path)
|
||||
if (!(vfs_flags & FL_NO_UNDELFS) && !strncmp (path, "undel:", 6))
|
||||
return &undelfs_vfs_ops;
|
||||
#endif
|
||||
if (!(vfs_flags & FL_NO_FISH) && !strncmp (path, "sh:", 3))
|
||||
return &fish_vfs_ops;
|
||||
if (!(vfs_flags & FL_NO_TARFS) && !strcmp (path, "utar"))
|
||||
return &tarfs_vfs_ops;
|
||||
if (!(vfs_flags & FL_NO_EXTFS) && extfs_which (path) != -1)
|
||||
@ -122,12 +127,12 @@ vfs *vfs_type_from_op (char *path)
|
||||
|
||||
int path_magic( char *path )
|
||||
{
|
||||
int res;
|
||||
int res;
|
||||
|
||||
res = !strncmp( path, "/#/", 3 );
|
||||
if (res)
|
||||
path[1] = '/';
|
||||
return res || (vfs_flags & FL_ALWAYS_MAGIC);
|
||||
res = !strncmp( path, "/#/", 3 );
|
||||
if (res)
|
||||
path[1] = '/';
|
||||
return res || (vfs_flags & FL_ALWAYS_MAGIC);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -742,7 +747,7 @@ void vfs_add_noncurrent_stamps (vfs * oldvfs, vfsid oldvfsid, struct vfs_stampin
|
||||
}
|
||||
|
||||
if ((*oldvfs->nothingisopen) (oldvfsid)){
|
||||
if (oldvfs == &extfs_vfs_ops && ((struct extfs_archive *) oldvfsid)->name == 0){
|
||||
if (oldvfs == &extfs_vfs_ops && ((extfs_archive *) oldvfsid)->name == 0){
|
||||
/* Free the resources immediatly when we leave a mtools fs
|
||||
('cd a:') instead of waiting for the vfs-timeout */
|
||||
(oldvfs->free) (oldvfsid);
|
||||
@ -755,7 +760,7 @@ void vfs_add_noncurrent_stamps (vfs * oldvfs, vfsid oldvfsid, struct vfs_stampin
|
||||
stamp->id == (vfsid) - 1 ||
|
||||
!(*stamp->v->nothingisopen) (stamp->id))
|
||||
break;
|
||||
if (stamp->v == &extfs_vfs_ops && ((struct extfs_archive *) stamp->id)->name == 0){
|
||||
if (stamp->v == &extfs_vfs_ops && ((extfs_archive *) stamp->id)->name == 0){
|
||||
(stamp->v->free) (stamp->id);
|
||||
vfs_rmstamp (stamp->v, stamp->id, 0);
|
||||
} else
|
||||
@ -888,7 +893,8 @@ char *vfs_get_current_dir (void)
|
||||
void vfs_setup_wd (void)
|
||||
{
|
||||
current_dir = strdup ("/");
|
||||
mc_return_cwd(); /* mc_return_cwd will fixup current_dir for us */
|
||||
if (!(vfs_flags & FL_NO_CWDSETUP))
|
||||
mc_return_cwd();
|
||||
|
||||
if (strlen(current_dir)>MC_MAXPATHLEN-2)
|
||||
vfs_die ("Current dir too long.\n");
|
||||
@ -1084,6 +1090,7 @@ void vfs_init (void)
|
||||
tcp_init();
|
||||
ftpfs_init();
|
||||
#endif
|
||||
fish_init ();
|
||||
extfs_init ();
|
||||
sfs_init ();
|
||||
vfs_setup_wd ();
|
||||
@ -1134,11 +1141,11 @@ void vfs_shut (void)
|
||||
free (current_dir);
|
||||
|
||||
extfs_done ();
|
||||
|
||||
sfs_done();
|
||||
#ifdef USE_NETCODE
|
||||
fish_done();
|
||||
ftpfs_done();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* These ones grab information from the VFS
|
||||
@ -1149,6 +1156,7 @@ void vfs_fill_names (void (*func)(char *))
|
||||
#ifdef USE_NETCODE
|
||||
mcfs_fill_names (func);
|
||||
ftpfs_fill_names (func);
|
||||
fish_fill_names (func);
|
||||
#endif
|
||||
tarfs_fill_names (func);
|
||||
extfs_fill_names (func);
|
||||
@ -1161,7 +1169,7 @@ void vfs_fill_names (void (*func)(char *))
|
||||
static char *columns [MAXCOLS]; /* Points to the string in column n */
|
||||
static int column_ptr [MAXCOLS]; /* Index from 0 to the starting positions of the columns */
|
||||
|
||||
static int split_text (char *p)
|
||||
int split_text (char *p)
|
||||
{
|
||||
char *original = p;
|
||||
int numcols;
|
||||
@ -1182,7 +1190,7 @@ static int split_text (char *p)
|
||||
|
||||
static int is_num (int idx)
|
||||
{
|
||||
if (columns [idx][0] < '0' || columns [idx][0] > '9')
|
||||
if (!columns [idx] || columns [idx][0] < '0' || columns [idx][0] > '9')
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@ -1230,37 +1238,173 @@ static int is_year(char *str, struct tm *tim)
|
||||
where "2904 1234" is filename. Well, this code decodes it as year :-(.
|
||||
*/
|
||||
|
||||
int parse_filetype (char c)
|
||||
{
|
||||
switch (c){
|
||||
case 'd': return S_IFDIR;
|
||||
case 'b': return S_IFBLK;
|
||||
case 'c': return S_IFCHR;
|
||||
case 'l': return S_IFLNK;
|
||||
case 's':
|
||||
#ifdef IS_IFSOCK /* And if not, we fall through to IFIFO, which is pretty close */
|
||||
return S_IFSOCK;
|
||||
#endif
|
||||
case 'p': return S_IFIFO;
|
||||
case 'm': case 'n': /* Don't know what these are :-) */
|
||||
case '-': case '?': return S_IFREG;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int parse_filemode (char *p)
|
||||
{ /* converts rw-rw-rw- into 0666 */
|
||||
int res = 0;
|
||||
switch (*(p++)){
|
||||
case 'r': res |= 0400; break;
|
||||
case '-': break;
|
||||
default: return -1;
|
||||
}
|
||||
switch (*(p++)){
|
||||
case 'w': res |= 0200; break;
|
||||
case '-': break;
|
||||
default: return -1;
|
||||
}
|
||||
switch (*(p++)){
|
||||
case 'x': res |= 0100; break;
|
||||
case 's': res |= 0100 | S_ISUID; break;
|
||||
case 'S': res |= S_ISUID; break;
|
||||
case '-': break;
|
||||
default: return -1;
|
||||
}
|
||||
switch (*(p++)){
|
||||
case 'r': res |= 0040; break;
|
||||
case '-': break;
|
||||
default: return -1;
|
||||
}
|
||||
switch (*(p++)){
|
||||
case 'w': res |= 0020; break;
|
||||
case '-': break;
|
||||
default: return -1;
|
||||
}
|
||||
switch (*(p++)){
|
||||
case 'x': res |= 0010; break;
|
||||
case 's': res |= 0010 | S_ISGID; break;
|
||||
case 'S': res |= S_ISGID; break;
|
||||
case '-': break;
|
||||
default: return -1;
|
||||
}
|
||||
switch (*(p++)){
|
||||
case 'r': res |= 0004; break;
|
||||
case '-': break;
|
||||
default: return -1;
|
||||
}
|
||||
switch (*(p++)){
|
||||
case 'w': res |= 0002; break;
|
||||
case '-': break;
|
||||
default: return -1;
|
||||
}
|
||||
switch (*(p++)){
|
||||
case 'x': res |= 0001; break;
|
||||
case 't': res |= 0001 | S_ISVTX; break;
|
||||
case 'T': res |= S_ISVTX; break;
|
||||
case '-': break;
|
||||
default: return -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int parse_filedate(int idx, time_t *t)
|
||||
{ /* This thing parses from idx in columns[] array */
|
||||
static char *month = "JanFebMarAprMayJunJulAugSepOctNovDec";
|
||||
static char *week = "SunMonTueWedThuFriSat";
|
||||
char *p, *pos;
|
||||
int extfs_format_date = 0;
|
||||
struct tm tim;
|
||||
|
||||
/* Let's setup default time values */
|
||||
tim.tm_year = current_year;
|
||||
tim.tm_mon = current_mon;
|
||||
tim.tm_mday = current_mday;
|
||||
tim.tm_hour = 0;
|
||||
tim.tm_min = 0;
|
||||
tim.tm_sec = 0;
|
||||
tim.tm_isdst = 0;
|
||||
|
||||
p = columns [idx++];
|
||||
|
||||
if((pos=strstr(week, p)) != NULL){
|
||||
tim.tm_wday = (pos - week)/3;
|
||||
p = columns [idx++];
|
||||
}
|
||||
|
||||
if((pos=strstr(month, p)) != NULL)
|
||||
tim.tm_mon = (pos - month)/3;
|
||||
else {
|
||||
/* This case should not normaly happen, but in extfs we allow these
|
||||
date formats:
|
||||
Mon DD hh:mm
|
||||
Mon DD YYYY
|
||||
Mon DD YYYY hh:mm
|
||||
Wek Mon DD hh:mm:ss YYYY
|
||||
MM-DD-YY hh:mm
|
||||
where Mon is Jan-Dec, DD, MM, YY two digit day, month, year,
|
||||
YYYY four digit year, hh, mm two digit hour and minute. */
|
||||
|
||||
if (strlen (p) == 8 && p [2] == '-' && p [5] == '-'){
|
||||
p [2] = 0;
|
||||
p [5] = 0;
|
||||
tim.tm_mon = (int) atol (p);
|
||||
if (!tim.tm_mon)
|
||||
return 0;
|
||||
else
|
||||
tim.tm_mon--;
|
||||
tim.tm_mday = (int) atol (p + 3);
|
||||
tim.tm_year = (int) atol (p + 6);
|
||||
if (tim.tm_year < 70)
|
||||
tim.tm_year += 70;
|
||||
extfs_format_date = 1;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!extfs_format_date){
|
||||
if (!is_num (idx))
|
||||
return 0;
|
||||
tim.tm_mday = (int)atol (columns [idx++]);
|
||||
}
|
||||
|
||||
if (is_num (idx)) {
|
||||
if(is_time(columns[idx], &tim) || is_year(columns[idx], &tim)) {
|
||||
idx++;
|
||||
|
||||
if(is_num (idx) &&
|
||||
(is_year(columns[idx], &tim) || is_time(columns[idx], &tim)))
|
||||
idx++; /* time & year or reverse */
|
||||
} /* only time or date */
|
||||
}
|
||||
else
|
||||
return 0; /* Nor time or date */
|
||||
|
||||
if ((*t = mktime(&tim)) ==-1)
|
||||
*t = 0;
|
||||
return idx;
|
||||
}
|
||||
|
||||
#define free_and_return(x) { free (p_copy); return (x); }
|
||||
int parse_ls_lga (char *p, struct stat *s, char **filename, char **linkname)
|
||||
{
|
||||
static char *month = "JanFebMarAprMayJunJulAugSepOctNovDec";
|
||||
static char *week = "SunMonTueWedThuFriSat";
|
||||
char *pos;
|
||||
int idx, idx2, num_cols, isconc = 0;
|
||||
int i;
|
||||
struct tm tim;
|
||||
int extfs_format_date = 0;
|
||||
char *p_copy;
|
||||
|
||||
s->st_mode = 0;
|
||||
if (strncmp (p, "total", 5) == 0){
|
||||
if (strncmp (p, "total", 5) == 0)
|
||||
return 0;
|
||||
}
|
||||
switch (*(p++)){
|
||||
case 'd': s->st_mode |= S_IFDIR; break;
|
||||
case 'b': s->st_mode |= S_IFBLK; break;
|
||||
case 'c': s->st_mode |= S_IFCHR; break;
|
||||
case 'm': s->st_mode |= S_IFREG; break; /* Don't know what it is :-) */
|
||||
case 'n': s->st_mode |= S_IFREG; break; /* and this as well */
|
||||
case 'l': s->st_mode |= S_IFLNK; break;
|
||||
#ifdef IS_IFSOCK
|
||||
case 's': s->st_mode |= S_IFSOCK; break;
|
||||
#endif
|
||||
case 'p': s->st_mode |= S_IFIFO; break;
|
||||
case '-': s->st_mode |= S_IFREG; break;
|
||||
case '?': s->st_mode |= S_IFREG; break;
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
if ((i = parse_filetype(*(p++))) == -1)
|
||||
return 0;
|
||||
|
||||
s->st_mode = i;
|
||||
if (*p == '['){
|
||||
if (strlen (p) <= 8 || p [8] != ']')
|
||||
return 0;
|
||||
@ -1271,57 +1415,10 @@ int parse_ls_lga (char *p, struct stat *s, char **filename, char **linkname)
|
||||
s->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
|
||||
p += 9;
|
||||
} else {
|
||||
switch (*(p++)){
|
||||
case 'r': s->st_mode |= 0400; break;
|
||||
case '-': break;
|
||||
default: return 0;
|
||||
}
|
||||
switch (*(p++)){
|
||||
case 'w': s->st_mode |= 0200; break;
|
||||
case '-': break;
|
||||
default: return 0;
|
||||
}
|
||||
switch (*(p++)){
|
||||
case 'x': s->st_mode |= 0100; break;
|
||||
case 's': s->st_mode |= 0100 | S_ISUID; break;
|
||||
case 'S': s->st_mode |= S_ISUID; break;
|
||||
case '-': break;
|
||||
default: return 0;
|
||||
}
|
||||
switch (*(p++)){
|
||||
case 'r': s->st_mode |= 0040; break;
|
||||
case '-': break;
|
||||
default: return 0;
|
||||
}
|
||||
switch (*(p++)){
|
||||
case 'w': s->st_mode |= 0020; break;
|
||||
case '-': break;
|
||||
default: return 0;
|
||||
}
|
||||
switch (*(p++)){
|
||||
case 'x': s->st_mode |= 0010; break;
|
||||
case 's': s->st_mode |= 0010 | S_ISGID; break;
|
||||
case 'S': s->st_mode |= S_ISGID; break;
|
||||
case '-': break;
|
||||
default: return 0;
|
||||
}
|
||||
switch (*(p++)){
|
||||
case 'r': s->st_mode |= 0004; break;
|
||||
case '-': break;
|
||||
default: return 0;
|
||||
}
|
||||
switch (*(p++)){
|
||||
case 'w': s->st_mode |= 0002; break;
|
||||
case '-': break;
|
||||
default: return 0;
|
||||
}
|
||||
switch (*(p++)){
|
||||
case 'x': s->st_mode |= 0001; break;
|
||||
case 't': s->st_mode |= 0001 | S_ISVTX; break;
|
||||
case 'T': s->st_mode |= S_ISVTX; break;
|
||||
case '-': break;
|
||||
default: return 0;
|
||||
}
|
||||
if ((i = parse_filemode(p)) ==-1)
|
||||
return 0;
|
||||
s->st_mode |= i;
|
||||
p += 9;
|
||||
}
|
||||
|
||||
p_copy = strdup (p);
|
||||
@ -1391,76 +1488,11 @@ int parse_ls_lga (char *p, struct stat *s, char **filename, char **linkname)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Let's setup default time values */
|
||||
tim.tm_year = current_year;
|
||||
tim.tm_mon = current_mon;
|
||||
tim.tm_mday = current_mday;
|
||||
tim.tm_hour = 0;
|
||||
tim.tm_min = 0;
|
||||
tim.tm_sec = 0;
|
||||
tim.tm_isdst = 0;
|
||||
|
||||
p = columns [idx++];
|
||||
|
||||
if((pos=strstr(week, p)) != NULL){
|
||||
tim.tm_wday = (pos - week)/3;
|
||||
p = columns [idx++];
|
||||
}
|
||||
|
||||
if((pos=strstr(month, p)) != NULL)
|
||||
tim.tm_mon = (pos - month)/3;
|
||||
else {
|
||||
/* This case should not normaly happen, but in extfs we allow these
|
||||
date formats:
|
||||
Mon DD hh:mm
|
||||
Mon DD YYYY
|
||||
Mon DD YYYY hh:mm
|
||||
Wek Mon DD hh:mm:ss YYYY
|
||||
MM-DD-YY hh:mm
|
||||
where Mon is Jan-Dec, DD, MM, YY two digit day, month, year,
|
||||
YYYY four digit year, hh, mm two digit hour and minute. */
|
||||
|
||||
if (strlen (p) == 8 && p [2] == '-' && p [5] == '-'){
|
||||
p [2] = 0;
|
||||
p [5] = 0;
|
||||
tim.tm_mon = (int) atol (p);
|
||||
if (!tim.tm_mon)
|
||||
free_and_return (0)
|
||||
else
|
||||
tim.tm_mon--;
|
||||
tim.tm_mday = (int) atol (p + 3);
|
||||
tim.tm_year = (int) atol (p + 6);
|
||||
if (tim.tm_year < 70)
|
||||
tim.tm_year += 70;
|
||||
extfs_format_date = 1;
|
||||
} else
|
||||
free_and_return (0);
|
||||
}
|
||||
|
||||
if (!extfs_format_date){
|
||||
if (!is_num (idx))
|
||||
free_and_return (0);
|
||||
tim.tm_mday = (int)atol (columns [idx++]);
|
||||
}
|
||||
|
||||
if (is_num (idx)) {
|
||||
if(is_time(columns[idx], &tim) || is_year(columns[idx], &tim)) {
|
||||
idx++;
|
||||
|
||||
if(is_num (idx) &&
|
||||
(is_year(columns[idx], &tim) || is_time(columns[idx], &tim)))
|
||||
idx++; /* time & year or reverse */
|
||||
} /* only time or date */
|
||||
}
|
||||
else
|
||||
free_and_return (0); /* Nor time or date */
|
||||
|
||||
/* Use resultimg time value */
|
||||
s->st_mtime = mktime (&tim);
|
||||
if (s->st_mtime == -1)
|
||||
s->st_mtime = 0;
|
||||
s->st_atime = s->st_mtime;
|
||||
s->st_ctime = s->st_mtime;
|
||||
idx = parse_filedate(idx, &s->st_mtime);
|
||||
if (!idx)
|
||||
free_and_return (0);
|
||||
/* Use resulting time value */
|
||||
s->st_atime = s->st_ctime = s->st_mtime;
|
||||
s->st_dev = 0;
|
||||
s->st_ino = 0;
|
||||
#ifdef HAVE_ST_BLKSIZE
|
||||
|
15
vfs/vfs.h
15
vfs/vfs.h
@ -6,9 +6,9 @@
|
||||
#else
|
||||
#define BROKEN_PATHS
|
||||
/*
|
||||
* We should really only allow /:ftp/ tree to export ftp, but midnight's users may
|
||||
* We should really only allow /#ftp/ tree to export ftp, but midnight's users may
|
||||
* like to be able to cd .. to get back where there were before ftp. How to solve?
|
||||
* Ok, we'll allow /any/path/:ftp/ to access ftp tree. Broken, yes.
|
||||
* Ok, we'll allow /any/path/#ftp/ to access ftp tree. Broken, yes.
|
||||
*/
|
||||
#endif
|
||||
|
||||
@ -90,6 +90,7 @@ struct utimbuf {
|
||||
extern vfs tarfs_vfs_ops;
|
||||
|
||||
extern vfs ftpfs_vfs_ops;
|
||||
extern vfs fish_vfs_ops;
|
||||
extern vfs mcfs_vfs_ops;
|
||||
|
||||
extern vfs extfs_vfs_ops;
|
||||
@ -316,8 +317,6 @@ extern int vfs_flags;
|
||||
extern uid_t vfs_uid;
|
||||
extern gid_t vfs_gid;
|
||||
|
||||
|
||||
|
||||
#define FL_ALWAYS_MAGIC 1
|
||||
#define FL_NO_MCFS 2
|
||||
#define FL_NO_FTPFS 4
|
||||
@ -325,6 +324,14 @@ extern gid_t vfs_gid;
|
||||
#define FL_NO_TARFS 16
|
||||
#define FL_NO_EXTFS 32
|
||||
#define FL_NO_SFS 64
|
||||
#define FL_NO_FISH 128
|
||||
|
||||
#define FL_NO_CWDSETUP 0x40000000
|
||||
|
||||
#ifdef VFS_STANDALONE
|
||||
extern void mc_vfs_init( void );
|
||||
extern void mc_vfs_done( void );
|
||||
#endif
|
||||
|
||||
#endif /* __VFS_H */
|
||||
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user