This is fo_nfs.c in view mode; [Download] [Up]
/*
* Name: fo_nfs.c
* Description: File operation functions that can be called from the
* NFS server stubs.
* Author: Christian Starkjohann <cs@hal.kph.tuwien.ac.at>
* Date: 1996-12-06
* Copyright: GNU-GPL
* Tabsize: 4
*/
#include "syshdr.h"
#include "psinode.h"
#include "smb_abstraction.h"
#include "my_defines.h"
#define TRANSFER_BUFFER_SIZE 8192 /* NFS uses this size... */
#define MAX_OPEN_FILES 20 /* keep at maximum this much files open */
#define KEEP_OPEN_TIMEOUT 5 /* keep files max 5s long open */
#define DPRINTF(arg) if(debug_mode & DEBUG_FOPS) dprintf arg
#define DFPRINTF(arg) if(debug_mode & DEBUG_FILE) dprintf arg
/* ------------------------------------------------------------------------- */
#define MODE_NONE 0
#define MODE_READ 1
#define MODE_WRITE 2
#define MODE_ANY 2
/* ------------------------------------------------------------------------- */
typedef struct file_info{
struct file_info *next;
struct file_info **prevnext; /* doubly linked list for LRU */
long long ino; /* pseudo inode number */
int index; /* index in hashtable */
time_t touched; /* for automatic close timeout */
int mode; /* opened for read or write */
smba_file_t *file; /* information managed by smb-abstraction*/
}file_info_t;
/* ------------------------------------------------------------------------- */
file_info_t file_buffer[MAX_OPEN_FILES];
list_t file_buffer_lru; /* LRU list for file buffers */
smba_server_t *the_server;
/* ------------------------------------------------------------------------- */
static inline void file_touch(file_info_t *p)
{
p->touched = time(NULL);
list_move_to_end(&file_buffer_lru, p);
}
/* ------------------------------------------------------------------------- */
static void file_close(file_info_t *finfo)
{
if(finfo->file != NULL){
DFPRINTF(("closing inode %d\n", (int)finfo->ino));
smba_close(finfo->file);
finfo->file = NULL;
}
}
/* ------------------------------------------------------------------------- */
file_info_t *file_get_open(long long ino, int mode, int *errnum)
{
int i, free_i = -1, importance;
file_info_t *p, *least_important;
char *path;
*errnum = 0;
for(i=0;i<MAX_OPEN_FILES;i++){
if(file_buffer[i].file != NULL){
if(file_buffer[i].ino == ino){
if(rw_is_safe || file_buffer[i].mode == mode
|| mode == MODE_NONE || file_buffer[i].mode == MODE_NONE){
file_touch(&file_buffer[i]);
if(mode != MODE_NONE)
file_buffer[i].mode = mode;
return &file_buffer[i];
}else{
file_close(&file_buffer[i]);
free_i = i;
break;
}
}
}else{
free_i = i;
}
}
if(free_i < 0){
/* no free entry, search for least important least recently used */
least_important = p = file_buffer_lru.head;
importance = 10;
while(p != NULL){
i = smba_file_importance(p->file);
if(i < importance){
least_important = p;
if((importance = i) == 0)
break;
}
p = p->next;
}
p = least_important;
file_close(p);
}else{
p = &file_buffer[free_i];
}
if((i = psi_index(ino)) < 0){
eprintf("file_get_open: requested inode not found\n");
*errnum = -MY_NFSERR_STALE;
return NULL;
}
path = psi_to_path(i, DOS_PATHSEP, NULL);
if((*errnum = smba_open(the_server, path, &p->file)) == 0){
DFPRINTF(("opening inode %d\n", (int)ino));
p->ino = ino;
p->index = i;
file_touch(p);
return p;
}else{
p->file = NULL;
return NULL;
}
}
/* ------------------------------------------------------------------------- */
static void set_attr(smba_stat_t *smbattr, my_attr_t *attr)
{
memset(smbattr, 0, sizeof(*smbattr));
if(attr->mode != -1){
if((attr->mode & S_IFMT) == S_IFDIR)
smbattr->is_dir = 1;
if((attr->mode & 0200) == 0 && allow_readonly)
smbattr->is_wp = 1;
}
smbattr->atime = attr->atime;
smbattr->mtime = attr->mtime;
smbattr->ctime = attr->ctime;
}
/* ------------------------------------------------------------------------- */
static void get_attr(smba_stat_t *smbattr, my_attr_t *attr, int inum)
{
attr->mode = smbattr->is_dir ? conf_dirmode : conf_filemode;
if(smbattr->is_wp){
attr->mode &= ~0222;
}
attr->mode |= smbattr->is_dir ? S_IFDIR : S_IFREG;
attr->nlink = 1;
attr->uid = conf_uid;
attr->gid = conf_gid;
attr->size = smbattr->is_dir && smbattr->size == 0 ?
100000 : smbattr->size; /* fake a directory size */
attr->blocksize = 4096;
attr->blocks = smbattr->size / 512;
attr->fileid = inum;
attr->atime = smbattr->atime;
attr->mtime = smbattr->mtime;
attr->ctime = smbattr->ctime;
attr->rdev = 0;
}
/* ------------------------------------------------------------------------- */
static int fo_new(int is_dir, fh_t *fh, my_attr_t *fa, fh_t dir,
char *name, my_attr_t *sa)
{
int errnum = 0;
file_info_t *p;
smba_stat_t smbattr;
if((p = file_get_open(dir, MODE_NONE, &errnum)) == NULL)
return errnum;
set_attr(&smbattr, sa);
if(is_dir){
errnum = smba_mkdir(p->file, name, &smbattr);
}else{
errnum = smba_create(p->file, name, &smbattr);
}
if(errnum)
return errnum;
errnum = fo_lookup(fh, fa, dir, name);
return errnum;
}
/* ------------------------------------------------------------------------- */
int fo_create(fh_t *fh, my_attr_t *fa, fh_t dir, char *name, my_attr_t *sa)
{
DPRINTF(("fo_create(ino=%d, name=%s)\n", (int)dir, name));
return fo_new(0, fh, fa, dir, name, sa);
}
/* ------------------------------------------------------------------------- */
int fo_mkdir(fh_t *fh, my_attr_t *fa, fh_t dir, char *name, my_attr_t *sa)
{
DPRINTF(("fo_mkdir(ino=%d, name=%s)\n", (int)dir, name));
return fo_new(1, fh, fa, dir, name, sa);
}
/* ------------------------------------------------------------------------- */
int fo_getattr(my_attr_t *fa, fh_t fh)
{
int errnum = 0;
file_info_t *file;
smba_stat_t smbattr;
DPRINTF(("fo_getattr(ino=%d)\n", (int)fh));
if((file = file_get_open(fh, MODE_NONE, &errnum)) == NULL)
return errnum;
if((errnum = smba_getattr(file->file, &smbattr)) != 0)
return errnum;
get_attr(&smbattr, fa, (int)fh);
return errnum;
}
/* ------------------------------------------------------------------------- */
int fo_setattr(my_attr_t *fa, fh_t fh, my_attr_t *sa)
{
int errnum = 0;
file_info_t *file;
smba_stat_t smbattr;
DPRINTF(("fo_setattr(ino=%d)\n", (int)fh));
if((file = file_get_open(fh, MODE_NONE, &errnum)) == NULL)
return errnum;
if((errnum = smba_getattr(file->file, &smbattr)) != 0)
return errnum;
set_attr(&smbattr, sa);
errnum = smba_setattr(file->file, &smbattr);
get_attr(&smbattr, fa, (int)fh);
return errnum;
}
/* ------------------------------------------------------------------------- */
int fo_lookup(fh_t *fh, my_attr_t *fa, fh_t dir, char *name)
{
int dir_i;
DPRINTF(("fo_lookup(ino=%d, name=%s)\n", (int)dir, name));
if((dir_i = psi_index(dir)) < 0)
return MY_NFSERR_STALE;
psi_lookup(dir_i, name, fh);
return fo_getattr(fa, *fh);
}
/* ------------------------------------------------------------------------- */
struct readdir_stat{
fh_t dir_ino;
my_direntry_t **tail;
int maxlen;
int *eof;
};
/* ------------------------------------------------------------------------- */
static int callback(void *d, int fpos, int nextpos, char *name, int eof)
{
struct readdir_stat *rstat = d;
my_direntry_t *dirent;
char *n;
int len, namelen;
n = strrchr(name, DOS_PATHSEP);
if(n == NULL) /* root path! */
n = name;
else
n++;
namelen = strlen(n) + 1;
len = namelen + sizeof(my_direntry_t);
if(len > rstat->maxlen)
return -1;
dirent = calloc(1, sizeof(my_direntry_t));
dirent->fh = (int)psi_inum(rstat->dir_ino, n);
dirent->name = malloc(namelen);
memcpy(dirent->name, n, namelen);
dirent->cookie = nextpos;
dirent->next = NULL;
DPRINTF(("fo_readdir(): appended entry:\n"));
DPRINTF(("\tfh=%d\n", dirent->fh));
DPRINTF(("\tname=%s\n", dirent->name));
DPRINTF(("\tcookie=%d\n", dirent->cookie));
*rstat->tail = dirent;
rstat->tail = &dirent->next;
rstat->maxlen -= len;
*rstat->eof = eof;
return 0;
}
/* ------------------------------------------------------------------------- */
int fo_readdir(my_direntry_t **result, int *eof, int max_bytes,
fh_t dir, int cookie)
{
struct readdir_stat rstat;
int errnum = 0;
file_info_t *f;
if((f = file_get_open(dir, MODE_NONE, &errnum)) == NULL)
return errnum;
rstat.dir_ino = dir;
rstat.tail = result;
rstat.maxlen = max_bytes;
rstat.eof = eof;
*eof = 0;
if(dir == root_inum && cookie == 0){ /* fake "." and ".." in root */
if(fake_dot_in_root){
callback(&rstat, -3, -2, ".", 0);
}
if(fake_dotdot_in_root){
callback(&rstat, -2, -1, "..", 0);
}
}
errnum = smba_readdir(f->file, cookie, &rstat, callback);
if(errnum == 0)
*eof = 1;
if(errnum < 0)
return errnum;
return 0;
}
/* ------------------------------------------------------------------------- */
static int fo_rm(int is_dir, fh_t dir, char *name)
{
int dir_i, errnum = 0;
char *path;
DPRINTF(("fo_rm(ino=%d, name=%s)\n", (int)dir, name));
if((dir_i = psi_index(dir)) < 0)
return MY_NFSERR_STALE;
path = psi_to_path(dir_i, DOS_PATHSEP, name);
if(is_dir)
errnum = smba_rmdir(the_server, path);
else
errnum = smba_remove(the_server, path);
return errnum;
}
/* ------------------------------------------------------------------------- */
int fo_remove(fh_t dir, char *name)
{
return fo_rm(0, dir, name);
}
/* ------------------------------------------------------------------------- */
int fo_rmdir(fh_t dir, char *name)
{
return fo_rm(1, dir, name);
}
/* ------------------------------------------------------------------------- */
int fo_rename(fh_t fromdir, char *fromname, fh_t todir, char *toname)
{
int i, lold, errnum = 0;
char *p, *old, *new;
DPRINTF(("fo_rename(ino=%d, name=%s, ino=%d, name=%s)\n", (int)fromdir,
fromname, (int)todir, toname));
if((i = psi_index(fromdir)) < 0)
return MY_NFSERR_STALE;
p = psi_to_path(i, DOS_PATHSEP, fromname);
if((i = psi_index(todir)) < 0)
return MY_NFSERR_STALE;
lold = strlen(p);
old = malloc(lold + 1);
memcpy(old, p, lold + 1);
new = psi_to_path(i, DOS_PATHSEP, toname);
errnum = smba_rename(the_server, old, new);
free(old);
return errnum;
}
/* ------------------------------------------------------------------------- */
int fo_statfs(my_statfs_t *fsstat)
{
int errnum = 0;
DPRINTF(("fo_statfs()\n"));
errnum = smba_statfs(the_server, &fsstat->bsize, &fsstat->blocks,
&fsstat->bfree);
if(errnum)
return errnum;
fsstat->type = 0;
fsstat->bavail = fsstat->bfree;
fsstat->files = -1;
fsstat->ffree = -1;
return 0;
}
/* ------------------------------------------------------------------------- */
int fo_read(my_attr_t *fa, int *len, char **data, fh_t fh, int offs,
int totalcount)
{
static char transfer_buf[TRANSFER_BUFFER_SIZE];
file_info_t *p;
smba_stat_t smbattr;
int errnum = 0;
DPRINTF(("fo_read(ino=%d, offs=%d, len=%d)\n", (int)fh, offs, totalcount));
if(totalcount > TRANSFER_BUFFER_SIZE)
totalcount = TRANSFER_BUFFER_SIZE;
*data = transfer_buf;
if((p = file_get_open(fh, MODE_READ, &errnum)) == NULL)
return errnum;
if((errnum = smba_getattr(p->file, &smbattr)) < 0)
return errnum;
get_attr(&smbattr, fa, (int)p->ino);
errnum = smba_read(p->file, transfer_buf, totalcount, offs);
*len = errnum; /* normally returns bytes read */
DPRINTF(("fo_read() returns %d\n", errnum));
if(errnum < 0)
return errnum;
return 0;
}
/* ------------------------------------------------------------------------- */
int fo_write(my_attr_t *fa, fh_t fh, int offset, int totalcount, char *data)
{
file_info_t *p;
smba_stat_t smbattr;
int errnum = 0;
DPRINTF(("fo_write(ino=%d, offs=%d, len=%d)\n",(int)fh,offset,totalcount));
if((p = file_get_open(fh, MODE_WRITE, &errnum)) == NULL)
return errnum;
if((errnum = smba_write(p->file, data, totalcount, offset)) < 0)
return errnum;
smba_touch(p->file);
if((errnum = smba_getattr(p->file, &smbattr)) < 0)
return errnum;
get_attr(&smbattr, fa, (int)p->ino);
DPRINTF(("fo_write() returns %d\n", errnum));
return errnum;
}
/* ------------------------------------------------------------------------- */
int fo_link(fh_t from, fh_t dir, char *name)
{
return -EFBIG;
}
/* ------------------------------------------------------------------------- */
int fo_readlink(char **path, fh_t fh)
{
return -EFBIG;
}
/* ------------------------------------------------------------------------- */
int fo_symlink(fh_t fromdir, char *fromname, char *topath, my_attr_t *sa)
{
return -EFBIG;
}
/* ------------------------------------------------------------------------- */
int fo_mount(char *server_ipname, char *server_name, char *client_name,
char *service, char *root_path, char *username,
char *password, int max_xmit, int port)
{
smba_connect_parameters_t par;
par.server_ipname = server_ipname;
par.server_name = server_name;
par.client_name = client_name;
par.service = service;
par.root_path = root_path;
par.username = username;
par.password = password;
par.max_xmit = max_xmit;
par.port = port;
return smba_connect(&par, use_extended, &the_server);
}
/* ------------------------------------------------------------------------- */
void fo_unmount(void)
{
int i;
for(i=0;i<MAX_OPEN_FILES;i++){
if(file_buffer[i].file != NULL){
file_close(&file_buffer[i]);
}
}
smba_disconnect(the_server);
}
/* ------------------------------------------------------------------------- */
void fo_regular(void)
{
int i;
time_t now = time(NULL);
for(i=0;i<MAX_OPEN_FILES;i++){
if(file_buffer[i].file != NULL){
if((now - file_buffer[i].touched) > KEEP_OPEN_TIMEOUT){
file_close(&file_buffer[i]);
}
}
}
smba_regular();
}
/* ------------------------------------------------------------------------- */
void fo_init(void)
{
int i;
smba_init();
list_init(&file_buffer_lru);
for(i=0;i<MAX_OPEN_FILES;i++){
list_append(&file_buffer_lru, &file_buffer[i]);
}
}
/* ------------------------------------------------------------------------- */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.