mirror of
https://github.com/UzixLS/ehs5fs.git
synced 2025-07-18 23:01:29 +03:00
initial
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
.settings
|
||||||
|
.cproject
|
||||||
|
.project
|
||||||
|
.externalToolBuilders/
|
||||||
|
ehs5fs
|
10
Makefile
Normal file
10
Makefile
Normal 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
216
fuse.c
Normal 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
5
fuse.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fuse.h>
|
||||||
|
|
||||||
|
extern struct fuse_operations fuse_ops;
|
110
main.c
Normal file
110
main.c
Normal 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
8
main.h
Normal 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
354
modem.c
Normal 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
56
modem.h
Normal 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 );
|
Reference in New Issue
Block a user