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.