1
0
mirror of https://github.com/UzixLS/ehs5fs.git synced 2025-07-18 23:01:29 +03:00
This commit is contained in:
UzixLS
2015-09-21 10:11:42 +03:00
commit b1adffb30f
8 changed files with 764 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.settings
.cproject
.project
.externalToolBuilders/
ehs5fs

10
Makefile Normal file
View File

@ -0,0 +1,10 @@
CWARNS = -Wall -Wextra -Wconversion -Wno-unused-parameter
CFLAGS = -std=gnu11 -fmessage-length=0 -O2 -g3
CDEFS = -D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=26
LDFLAGS = -lfuse
all:
$(CC) $(CWARNS) $(CFLAGS) $(CDEFS) $(LDFLAGS) *.c -o ehs5fs
clean:
rm ehs5fs

216
fuse.c Normal file
View File

@ -0,0 +1,216 @@
#include <fuse.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "main.h"
#include "fuse.h"
#include "modem.h"
static int fs_getattr( const char *path, struct stat *st )
{
int ret;
printf( "fs_getattr %s\n", path );
if( 0 == strcmp(path, "/") ) {
st->st_mode = S_IFDIR | 0777;
st->st_nlink = 2;
} else {
st->st_nlink = 1;
ret = m_stat( &M, path, st );
if( ret == ENOENT ) return -ret;
if( ret < 0 ) {
printf( "fs_getattr: tc_stat err ret=%d'\n", ret );
return 0;
}
}
return 0;
}
static int fs_readdir(
const char *path,
void *buf,
fuse_fill_dir_t filler,
off_t offset,
struct fuse_file_info *fi )
{
printf( "fs_readdir %s\n", path );
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
m_ls( &M, path, buf, filler );
return 0;
}
static int fs_read(
const char *path,
char *buf,
size_t size,
off_t offset,
struct fuse_file_info *fi )
{
int ret = 0;
int readchunk = min(MAX_SIZE, (int)size);
int readed = 0;
int left = 0;
struct stat st;
printf( "fs_read %s (%u+%lld)\n", path, size, offset);
int fh = m_open( &M, path, 0 );
if( fh < 0 ) return -1;
if( m_seek( &M, fh, (int)offset, 0) < 0 ) { ret = -EIO; goto fs_read_exit; }
if( m_stat( &M, path, &st ) < 0 ) { ret = -EIO; goto fs_read_exit; }
left = min( (int)size, (int)st.st_size - (int)offset );
while( left > 0 ) {
int bytes = min( (int)size, left );
if( bytes > readchunk ) bytes = readchunk;
if( m_read( &M, fh, (unsigned)bytes, buf + readed ) < 0 ) {
ret = -1; goto fs_read_exit;
}
readed += bytes;
left -= bytes;
printf( "fs_read readed %d bytes from %d (%d left)\n", readed, size, left );
usleep( 350 );
}
ret = readed;
fs_read_exit:
m_close( &M, fh );
printf( "fs_read ret=%d\n", ret );
return ret;
}
static int fs_write(
const char *path,
const char *buf,
size_t size,
off_t offset,
struct fuse_file_info *fi )
{
int ret = 0;
int left = (int)size;
int written = 0;
printf( "fs_write %s (%u+%lld)\n", path, size, offset );
int fh = m_open( &M, path, FLAG_APPEND );
if( fh < 0 ) return -1;
if( m_seek( &M, fh, (int)offset, 0) < 0 ) { ret = -EIO; goto fs_write_exit; }
while( left > 0 ) {
int bytes = min( MAX_SIZE, left );
if( m_write( &M, fh, (unsigned)bytes, buf + written ) < 0 ) {
ret = -EIO; goto fs_write_exit;
}
written += bytes;
left -= bytes;
printf( "fs_write writed %d bytes from %d (%d left)\n", written, size, left );
}
ret = written;
fs_write_exit:
m_close( &M, fh );
printf( "fs_write ret=%d\n", ret );
return ret;
}
static int fs_mknod(
const char *path,
mode_t mode,
dev_t dev )
{
int fh = m_open( &M, path, FLAG_CREATE );
if( fh < 0 ) return -EIO;
m_close( &M, fh );
return 0;
}
static int fs_mkdir( const char *path, mode_t mode )
{
if( m_mkdir( &M, path ) < 0 )
return -EIO;
else
return 0;
}
static int fs_rmdir( const char *path )
{
if( m_rmdir( &M, path ) < 0 )
return -EIO;
else
return 0;
}
static int fs_unlink( const char *path )
{
if( m_remove( &M, path ) < 0 )
return -EIO;
else
return 0;
}
static int fs_truncate( const char *path, off_t offset )
{
if( offset != 0 ) return -EFAULT;
int fh = m_open( &M, path, FLAG_TRUNCATE );
if( fh < 0 ) return -EIO;
m_close( &M, fh );
return 0;
}
static int fs_rename( const char *oldpath, const char *newpath )
{
int saferename = 1;
char *ptr_oldpath, *ptr_newpath;
ptr_oldpath = strrchr( oldpath, '/' );
ptr_newpath = strrchr( newpath, '/' );
if( strncmp( oldpath, newpath, (unsigned)(max( ptr_oldpath - oldpath, ptr_newpath - newpath ))
) != 0 )
saferename = 1;
if( ptr_oldpath[1] == '.' || ptr_newpath[1] == '.' )
saferename = 1;
if( saferename == 0 ) {
if( m_rename( &M, oldpath+1, newpath+1 ) < 0 ) return -EIO;
} else {
if( m_copy( &M, oldpath, newpath ) < 0 ) return -EIO;
if( m_remove( &M, oldpath ) < 0 ) return -EIO;
}
return 0;
}
static int fs_statfs( const char *path, struct statvfs *st )
{
if( m_gstat( &M, st ) < 0 )
return -EIO;
else
return 0;
}
struct fuse_operations fuse_ops = {
.getattr = fs_getattr,
.readdir = fs_readdir,
.read = fs_read,
.write = fs_write,
.mknod = fs_mknod,
.mkdir = fs_mkdir,
.rmdir = fs_rmdir,
.unlink = fs_unlink,
.truncate = fs_truncate,
.rename = fs_rename,
.statfs = fs_statfs,
};

5
fuse.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include <fuse.h>
extern struct fuse_operations fuse_ops;

110
main.c Normal file
View File

@ -0,0 +1,110 @@
#include <fuse.h>
#include <fuse/fuse_opt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fuse.h"
#include "modem.h"
struct modem M;
struct {
char *point;
char *dev;
char *mountpoint;
int readonly;
int debug;
} options = {
.point = NULL,
.dev = NULL,
.readonly = 0,
.debug = 0,
};
enum {
KEY_VERSION,
KEY_HELP,
KEY_PORT,
KEY_READONLY,
KEY_DEBUG,
};
static struct fuse_opt opts[] = {
FUSE_OPT_KEY("-V", KEY_VERSION),
FUSE_OPT_KEY("--version", KEY_VERSION),
FUSE_OPT_KEY("-h", KEY_HELP),
FUSE_OPT_KEY("--help", KEY_HELP),
FUSE_OPT_KEY("--readonly", KEY_READONLY),
FUSE_OPT_KEY("--debug", KEY_DEBUG),
FUSE_OPT_END
};
const char *usage = "\
usage: tc65fs [fuse options] device mountpoint\n\
-V --version show software version inforamtion\n\
--port=/dev/ttyS0 connect to specified port\n\
--readonly disable any writting operations\n\
--debug start in debug mode\n\
";
static int opt_proc(
void *data,
const char *arg,
int key,
struct fuse_args *outargs )
{
switch (key) {
case KEY_VERSION:
printf("ehs5fs build at %s %s, (c)2015 Eugene Lozovoy <lozovoy.ep@gmail.com>\n", __DATE__, __TIME__);
exit( 1 );
case KEY_HELP:
printf( usage );
exit( 0 );
case FUSE_OPT_KEY_NONOPT:
if (options.dev == NULL) {
options.dev = strdup(arg);
return 0;
}
if (options.point == NULL) {
options.point = strdup(arg);
return 0;
}
return 1;
case KEY_PORT:
if (options.dev == NULL) {
options.dev = strdup(arg+11);
return 0;
}
return 1;
case KEY_READONLY:
options.readonly = 1;
return 0;
case KEY_DEBUG:
options.debug = 1;
return 0;
}
return 0;
}
int main( int argc, char *argv[] )
{
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
if( fuse_opt_parse( &args, NULL, opts, opt_proc ) ) return 1;
fuse_opt_add_arg( &args, "-s" );
if( options.debug ) fuse_opt_add_arg( &args, "-d" );
if( options.readonly ) fuse_opt_add_arg( &args, "-oro" );
if( options.point ) fuse_opt_add_arg( &args, options.point );
if( !options.point || !options.dev ) {
printf( usage );
return -2;
}
if( m_init( &M, options.dev ) < 0 ) {
printf( "m_init failed!\n" );
return -1;
}
return fuse_main( args.argc, args.argv, &fuse_ops, NULL );
}

8
main.h Normal file
View File

@ -0,0 +1,8 @@
#pragma once
#include "modem.h"
#define max(a,b) ((a)>(b))?(a):(b)
#define min(a,b) ((a)<(b))?(a):(b)
extern struct modem M;

354
modem.c Normal file
View File

@ -0,0 +1,354 @@
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>
#include "modem.h"
static int call(
struct modem *m,
const char *cmd,
unsigned cmdlen,
char *retbuf,
unsigned retmaxbytes,
unsigned *retbytes )
{
#define call_checkstr(str, retcode) \
if( bytes >= sizeof(str)-1 && strncmp( &(retbuf[bytes-sizeof(str)+1]), str, sizeof(str)-1 ) == 0 ) { \
ret = retcode; \
bytes -= sizeof(str)-1; \
break; \
}
unsigned bytes = 0;
int ret = 0;
if( m == NULL || cmd == NULL ) return -1;
if( cmdlen == 0 ){
printf( "call write [[[%s]]]\n", cmd );
cmdlen = strlen( cmd );
} else {
printf( "call write %u raw bytes\n", cmdlen );
}
tcflush( m->fd, TCIOFLUSH );
while( cmdlen-- ) {
if( write( m->fd, cmd, 1 ) != 1 ) {
perror( "call write error" );
return -1;
}
cmd++;
}
fsync( m->fd );
if( retmaxbytes < 1 || retbuf == NULL ) return 0;
while( bytes < retmaxbytes ) {
if( read( m->fd, &(retbuf[bytes]), 1 ) != 1 ) break;
bytes++;
call_checkstr( "\r\nOK\r\n", 1 );
call_checkstr( "\r\nERROR\r\n", -2 );
call_checkstr( "\r\nCONNECT\r\n", 1 );
}
retbuf[bytes] = 0;
if( retbytes != NULL ) *retbytes = bytes;
printf( "call read %d bytes (from %d) ret=%d [[[%s]]]\n", bytes, retmaxbytes, ret, retbuf );
return ret;
}
int m_ls( struct modem *m, const char *path, void *fusebuf, fuse_fill_dir_t fusefiller )
{
char buf[1024], scanbuf[128];
char *bufptr = buf;
if( m == NULL || path == NULL || fusebuf == NULL || fusefiller == NULL ) return -1;
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"ls\",\"a:/%s\"\r\n", path );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -1;
while( 1 ) {
strsep( &bufptr, "\n" );
if( bufptr == NULL ) break;
scanbuf[0] = 0;
if( sscanf( bufptr, "^SFSA: \"%s\"\r\n", scanbuf ) != 1) continue;
if( strlen( scanbuf ) < 2 ) continue;
scanbuf[strlen(scanbuf)-1] = 0;
if( scanbuf[strlen(scanbuf)-1] == '/' )
scanbuf[strlen(scanbuf)-1] = 0;
if( fusebuf != NULL && fusefiller != NULL )
fusefiller( fusebuf, scanbuf, NULL, 0 );
}
return 0;
}
int m_stat( struct modem *m, const char *path, struct stat *fusest )
{
char buf[1024];
char *bufptr = buf;
if( m == NULL || path == NULL || fusest == NULL ) return -1;
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"stat\",\"a:/%s\"\r\n", path );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) {
int errcode;
strsep( &bufptr, "\n" );
if( bufptr == NULL ) return -1;
if( sscanf( bufptr, "^SFSA: %d\r\n", &errcode ) != 1 ) return -1;
printf( "m_stat errcode %d\n", errcode );
switch( errcode ) {
case RESULT_NOTFOUND:
return ENOENT;
default:
return EIO;
}
}
for( int i = 0; i < 6; i++ ) {
int tmp;
struct tm tp;
strsep( &bufptr, "\n" );
if( bufptr == NULL ) return -3;
switch( i ) {
case 1:
case 2:
case 3:
if( sscanf( bufptr, "^SFSA: \"%d/%d/%d,%d:%d:%d\"\r\n",
&(tp.tm_year), &(tp.tm_mon), &(tp.tm_mday),
&(tp.tm_hour), &(tp.tm_min), &(tp.tm_sec) ) != 6 ) return -4-i;
tp.tm_year += 100;
}
switch( i ) {
case 0:
if( sscanf( bufptr, "^SFSA: %d\r\n", &tmp ) != 1 ) return -4;
fusest->st_size = tmp;
break;
case 1:
fusest->st_atim.tv_sec = mktime( &tp );
break;
case 2:
fusest->st_mtim.tv_sec = mktime( &tp );
break;
case 3:
fusest->st_ctim.tv_sec = mktime( &tp );
break;
case 4:
if( sscanf( bufptr, "^SFSA: %d\r\n", &tmp ) != 1 ) return -8;
if( tmp == ATTR_FILE )
fusest->st_mode = S_IFREG | 0666;
else
fusest->st_mode = S_IFDIR | 0777;
break;
}
}
return 0;
}
int m_read( struct modem *m, int fh, unsigned size, char *outbuf )
{
char buf[MAX_SIZE+100];
char *bufptr = buf;
if ( m == NULL ) return -1;
printf( "m_read %d (%u)\n", fh, size );
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"read\",%d,%u\r\n", fh, size );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -2;
strsep( &bufptr, "\n" );
strsep( &bufptr, "\n" );
if( bufptr == NULL ) return -3;
if( outbuf != NULL )
memcpy( outbuf, bufptr, size );
return 0;
}
int m_seek( struct modem *m, int fh, int offset, enum seek flags )
{
char buf[100];
if( m == NULL ) return -1;
printf( "m_seek %d to %d\n", fh, offset );
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"seek\",%d,%d,%d\r\n", fh, offset, flags );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -2;
return 0;
}
int m_open( struct modem *m, const char *path, enum flags flags )
{
int fh = -1;
char buf[100];
char *bufptr = buf;
if( m == NULL || path == NULL ) return -1;
printf( "m_open %s\n", path );
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"open\",\"a:/%s\",%u\r\n", path, flags );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -1;
strsep( &bufptr, "\n" );
if( bufptr == NULL ) return -2;
if( sscanf( bufptr, "^SFSA: %d,0\r\n", &fh ) != 1 ) {
printf( "m_open sscanf failed\n" );
return -3;
}
printf( "m_open ret %d\n", fh );
return fh;
}
int m_close( struct modem *m, int fh )
{
char buf[100];
if( m == NULL ) return -1;
printf( "m_close #%d\n", fh );
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"close\",%d\r\n", fh );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -2;
return 0;
}
int m_write( struct modem *m, int fh, unsigned size, const char *data )
{
char buf[size+100];
if( m == NULL || data == NULL ) return -1;
printf( "m_write %u bytes to #%d\n", size, fh );
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"write\",%d,%u\r\n", fh, size );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) < 0 ) return -2;
if( call( m, data, size, buf, size, NULL ) < 0 ) return -3;
return (int)size;
}
int m_remove( struct modem *m, const char *path )
{
char buf[100];
if( m == NULL || path == NULL ) return -1;
printf( "m_remove %s\n", path );
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"remove\",\"a:/%s\"\r\n", path );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -1;
return 0;
}
int m_mkdir( struct modem *m, const char *path )
{
char buf[100];
if( m == NULL || path == NULL ) return -1;
printf( "m_mkdir %s\n", path );
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"mkdir\",\"a:/%s\"\r\n", path );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -1;
return 0;
}
int m_rmdir( struct modem *m, const char *path )
{
char buf[100];
if( m == NULL || path == NULL ) return -1;
printf( "m_rmdir %s\n", path );
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"rmdir\",\"a:/%s\"\r\n", path );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -1;
return 0;
}
int m_copy( struct modem *m, const char *srcpath, const char *dstpath )
{
char buf[100];
if( m == NULL || srcpath == NULL || dstpath == NULL ) return -1;
printf( "m_copy %s to %s\n", srcpath, dstpath );
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"copy\",\"a:/%s\",\"a:/%s\"\r\n", srcpath, dstpath );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -1;
return 0;
}
int m_rename( struct modem *m, const char *path, const char *newname )
{
char buf[100];
if( m == NULL || path == NULL || newname == NULL ) return -1;
printf( "m_rename %s to %s\n", path, newname );
snprintf( buf, sizeof(buf)-1, "AT^SFSA=\"rename\",\"a:/%s\",\"%s\"\r\n", path, newname );
if( call( m, buf, 0, buf, sizeof(buf), NULL ) <= 0 ) return -1;
return 0;
}
int m_gstat( struct modem *modem, struct statvfs *st )
{
char buf[200];
char *bufptr = buf;
if( modem == NULL || st == NULL ) return -1;
printf( "m_gstat\n" );
if( call( modem, "AT^SFSA=\"gstat\"\r\n", 0, buf, sizeof(buf), NULL ) <= 0 ) return -1;
for( int i = 0; i < 2; i++ ) {
unsigned tmp;
strsep( &bufptr, "\n" );
if( bufptr == NULL ) return -2;
switch( i ) {
case 0:
if( sscanf( bufptr, "^SFSA: %u\r\n", &tmp ) != 1) return -3;
st->f_blocks = tmp;
break;
case 1:
if( sscanf( bufptr, "^SFSA: %u\r\n", &tmp ) != 1) return -4;
st->f_bfree = tmp;
st->f_bavail = tmp;
break;
}
}
st->f_bsize = 1;
st->f_namemax = 64;
return 0;
}
int m_init( struct modem *m, const char *tty )
{
char buf[100];
if ( m == NULL )
return -1;
if ( (m->fd = open(tty, O_RDWR | O_NOCTTY | O_SYNC)) == -1 ) {
perror( "m_init: cannot open device" );
return -1;
}
tcgetattr( m->fd, &(m->termios) );
cfmakeraw( &(m->termios) );
m->termios.c_cc[VTIME] = 50;
m->termios.c_cc[VMIN] = 0;
/* set baud rates */
cfsetispeed( &(m->termios), B115200 );
cfsetospeed( &(m->termios), B115200 );
/* enable the receiver and set local mode */
m->termios.c_cflag |= (CLOCAL | CREAD);
/* set no parity, stop bits, data bits */
m->termios.c_cflag &= ~(unsigned)PARENB;
m->termios.c_cflag &= ~(unsigned)CSTOPB;
/* set character size as 8 bits */
m->termios.c_cflag &= ~(unsigned)CSIZE;
m->termios.c_cflag |= CS8;
/* Raw input mode, sends the raw and unprocessed data ( send as it is) */
m->termios.c_lflag &= ~(unsigned)(ICANON | ECHO | ISIG);
/* Raw output mode, sends the raw and unprocessed data ( send as it is). */
m->termios.c_oflag = ~(unsigned)OPOST;
tcflush( m->fd, TCOFLUSH );
tcsetattr( m->fd, TCSANOW, &(m->termios) );
if( call( m, "ATE0\r\n", 0, buf, sizeof(buf), NULL ) <= 0 )
return -1;
return 0;
}
int m_deinit( struct modem *m )
{
close( m->fd );
return 0;
}

56
modem.h Normal file
View File

@ -0,0 +1,56 @@
#pragma once
#include <fuse.h>
#include <termios.h>
#define CALL_TIMEOUT 2000
#define MAX_OPENS 24
#define MAX_SIZE 1500
enum flags {
FLAG_APPEND = 4,
FLAG_CREATE = 8,
FLAG_TRUNCATE = 16,
};
enum seek {
SEEK_FROMBEGIN = 0,
SEEK_FROMCURRENT = 1,
SEEK_FROMEND = 2,
};
enum attrs {
ATTR_FILE = 0,
ATTR_VOL = 8,
ATTR_DIR = 16
};
enum results {
RESULT_SUCCESS = 0,
RESULT_NOTFOUND = 2,
};
struct modem {
int fd;
struct termios termios;
};
int m_close( struct modem *m, int fh );
int m_copy( struct modem *m, const char *srcpath, const char *dstpath );
int m_crc( struct modem *m, const char *path );
int m_gstat( struct modem *m, struct statvfs *st );
int m_ls( struct modem *m, const char *path, void *fusebuf, fuse_fill_dir_t fusefiller );
int m_mkdir( struct modem *m, const char *path );
int m_open( struct modem *m, const char *path, enum flags flags );
int m_read( struct modem *m, int fh, unsigned size, char *outbuf );
int m_remove( struct modem *m, const char *path );
int m_rename( struct modem *m, const char *path, const char *newname );
int m_rmdir( struct modem *m, const char *path );
int m_seek( struct modem *m, int fh, int offset, enum seek flags );
int m_stat( struct modem *m, const char *path, struct stat *fusest );
int m_write( struct modem *m, int fh, unsigned size, const char *data );
int m_init( struct modem *m, const char *tty );
int m_deinit( struct modem *m );