Create SFFS library out of HGFS
This Shared Folders File System library (libsffs) now contains all the file system logic originally in HGFS. The actual HGFS server code is now a stub that passes on all the work to libsffs. The libhgfs library is changed accordingly.
This commit is contained in:
parent
09b327b042
commit
ef7b484e5c
41 changed files with 664 additions and 534 deletions
|
@ -14,7 +14,7 @@ INCS+= minix/acpi.h minix/audio_fw.h minix/bitmap.h \
|
||||||
minix/keymap.h minix/limits.h minix/mthread.h minix/minlib.h \
|
minix/keymap.h minix/limits.h minix/mthread.h minix/minlib.h \
|
||||||
minix/netdriver.h minix/optset.h minix/partition.h minix/portio.h \
|
minix/netdriver.h minix/optset.h minix/partition.h minix/portio.h \
|
||||||
minix/priv.h minix/procfs.h minix/profile.h minix/queryparam.h \
|
minix/priv.h minix/procfs.h minix/profile.h minix/queryparam.h \
|
||||||
minix/rs.h minix/safecopies.h minix/sched.h minix/sef.h \
|
minix/rs.h minix/safecopies.h minix/sched.h minix/sef.h minix/sffs.h \
|
||||||
minix/sound.h minix/spin.h minix/sys_config.h minix/sysinfo.h \
|
minix/sound.h minix/spin.h minix/sys_config.h minix/sysinfo.h \
|
||||||
minix/syslib.h minix/sysutil.h minix/timers.h minix/type.h \
|
minix/syslib.h minix/sysutil.h minix/timers.h minix/type.h \
|
||||||
minix/tty.h minix/u64.h minix/usb.h minix/usb_ch9.h minix/vbox.h \
|
minix/tty.h minix/u64.h minix/usb.h minix/usb_ch9.h minix/vbox.h \
|
||||||
|
|
|
@ -1,56 +1,11 @@
|
||||||
/* Part of libhgfs - (c) 2009, D.C. van Moolenbroek */
|
/* Part of libhgfs - (c) 2009, D.C. van Moolenbroek */
|
||||||
|
|
||||||
#ifndef _HGFS_H
|
#ifndef _MINIX_HGFS_H
|
||||||
#define _HGFS_H
|
#define _MINIX_HGFS_H
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <minix/sffs.h>
|
||||||
#include <minix/u64.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
typedef void *hgfs_file_t; /* handle to open file */
|
int hgfs_init(const struct sffs_table **tablep);
|
||||||
typedef void *hgfs_dir_t; /* handle to directory search */
|
|
||||||
|
|
||||||
struct hgfs_attr {
|
|
||||||
u32_t a_mask; /* which fields to retrieve/set */
|
|
||||||
mode_t a_mode; /* file type and permissions */
|
|
||||||
u64_t a_size; /* file size */
|
|
||||||
struct timespec a_crtime; /* file creation time */
|
|
||||||
struct timespec a_atime; /* file access time */
|
|
||||||
struct timespec a_mtime; /* file modification time */
|
|
||||||
struct timespec a_ctime; /* file change time */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define HGFS_ATTR_SIZE 0x01 /* get/set file size */
|
|
||||||
#define HGFS_ATTR_CRTIME 0x02 /* get/set file creation time */
|
|
||||||
#define HGFS_ATTR_ATIME 0x04 /* get/set file access time */
|
|
||||||
#define HGFS_ATTR_MTIME 0x08 /* get/set file modification time */
|
|
||||||
#define HGFS_ATTR_CTIME 0x10 /* get/set file change time */
|
|
||||||
#define HGFS_ATTR_MODE 0x20 /* get/set file mode */
|
|
||||||
|
|
||||||
int hgfs_init(void);
|
|
||||||
void hgfs_cleanup(void);
|
void hgfs_cleanup(void);
|
||||||
|
|
||||||
int hgfs_open(char *path, int flags, int mode, hgfs_file_t *handle);
|
#endif /* _MINIX_HGFS_H */
|
||||||
int hgfs_read(hgfs_file_t handle, char *buf, size_t size, u64_t offset);
|
|
||||||
int hgfs_write(hgfs_file_t handle, char *buf, size_t len, u64_t offset);
|
|
||||||
int hgfs_close(hgfs_file_t handle);
|
|
||||||
|
|
||||||
size_t hgfs_readbuf(char **ptr);
|
|
||||||
size_t hgfs_writebuf(char **ptr);
|
|
||||||
|
|
||||||
int hgfs_opendir(char *path, hgfs_dir_t *handle);
|
|
||||||
int hgfs_readdir(hgfs_dir_t handle, unsigned int index, char *buf,
|
|
||||||
size_t size, struct hgfs_attr *attr);
|
|
||||||
int hgfs_closedir(hgfs_dir_t handle);
|
|
||||||
|
|
||||||
int hgfs_getattr(char *path, struct hgfs_attr *attr);
|
|
||||||
int hgfs_setattr(char *path, struct hgfs_attr *attr);
|
|
||||||
|
|
||||||
int hgfs_mkdir(char *path, int mode);
|
|
||||||
int hgfs_unlink(char *path);
|
|
||||||
int hgfs_rmdir(char *path);
|
|
||||||
int hgfs_rename(char *opath, char *npath);
|
|
||||||
|
|
||||||
int hgfs_queryvol(char *path, u64_t *free, u64_t *total);
|
|
||||||
|
|
||||||
#endif /* _HGFS_H */
|
|
||||||
|
|
69
include/minix/sffs.h
Normal file
69
include/minix/sffs.h
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
/* Part of libsffs - (c) 2012, D.C. van Moolenbroek */
|
||||||
|
|
||||||
|
#ifndef _MINIX_SFFS_H
|
||||||
|
#define _MINIX_SFFS_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <minix/u64.h>
|
||||||
|
|
||||||
|
typedef void *sffs_file_t; /* handle to open file */
|
||||||
|
typedef void *sffs_dir_t; /* handle to directory search */
|
||||||
|
|
||||||
|
struct sffs_attr {
|
||||||
|
u32_t a_mask; /* which fields to retrieve/set */
|
||||||
|
mode_t a_mode; /* file type and permissions */
|
||||||
|
u64_t a_size; /* file size */
|
||||||
|
struct timespec a_crtime; /* file creation time */
|
||||||
|
struct timespec a_atime; /* file access time */
|
||||||
|
struct timespec a_mtime; /* file modification time */
|
||||||
|
struct timespec a_ctime; /* file change time */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SFFS_ATTR_SIZE 0x01 /* get/set file size */
|
||||||
|
#define SFFS_ATTR_CRTIME 0x02 /* get/set file creation time */
|
||||||
|
#define SFFS_ATTR_ATIME 0x04 /* get/set file access time */
|
||||||
|
#define SFFS_ATTR_MTIME 0x08 /* get/set file modification time */
|
||||||
|
#define SFFS_ATTR_CTIME 0x10 /* get/set file change time */
|
||||||
|
#define SFFS_ATTR_MODE 0x20 /* get/set file mode */
|
||||||
|
|
||||||
|
struct sffs_table {
|
||||||
|
int (*t_open)(char *path, int flags, int mode, sffs_file_t *handle);
|
||||||
|
ssize_t (*t_read)(sffs_file_t handle, char *buf, size_t size, u64_t pos);
|
||||||
|
ssize_t (*t_write)(sffs_file_t handle, char *buf, size_t size, u64_t pos);
|
||||||
|
int (*t_close)(sffs_file_t handle);
|
||||||
|
|
||||||
|
size_t (*t_readbuf)(char **ptr);
|
||||||
|
size_t (*t_writebuf)(char **ptr);
|
||||||
|
|
||||||
|
int (*t_opendir)(char *path, sffs_dir_t *handle);
|
||||||
|
int (*t_readdir)(sffs_dir_t handle, unsigned int index, char *buf,
|
||||||
|
size_t size, struct sffs_attr *attr);
|
||||||
|
int (*t_closedir)(sffs_dir_t handle);
|
||||||
|
|
||||||
|
int (*t_getattr)(char *path, struct sffs_attr *attr);
|
||||||
|
int (*t_setattr)(char *path, struct sffs_attr *attr);
|
||||||
|
|
||||||
|
int (*t_mkdir)(char *path, int mode);
|
||||||
|
int (*t_unlink)(char *path);
|
||||||
|
int (*t_rmdir)(char *path);
|
||||||
|
int (*t_rename)(char *opath, char *npath);
|
||||||
|
|
||||||
|
int (*t_queryvol)(char *path, u64_t *free, u64_t *total);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sffs_params {
|
||||||
|
char p_prefix[PATH_MAX]; /* prefix for all paths used */
|
||||||
|
uid_t p_uid; /* UID that owns all files */
|
||||||
|
gid_t p_gid; /* GID that owns all files */
|
||||||
|
unsigned int p_file_mask; /* AND-mask to apply to file permissions */
|
||||||
|
unsigned int p_dir_mask; /* AND-mask to apply to directory perms */
|
||||||
|
int p_case_insens; /* case insensitivity flag */
|
||||||
|
};
|
||||||
|
|
||||||
|
int sffs_init(char *name, const struct sffs_table *table,
|
||||||
|
struct sffs_params *params);
|
||||||
|
void sffs_signal(int signo);
|
||||||
|
void sffs_loop(void);
|
||||||
|
|
||||||
|
#endif /* _MINIX_SFFS_H */
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
SUBDIR= csu libcompat_minix libc libblockdriver libchardriver \
|
SUBDIR= csu libcompat_minix libc libblockdriver libchardriver \
|
||||||
libnetdriver libedit libm libsys libtimers libutil \
|
libnetdriver libedit libm libsys libtimers libutil \
|
||||||
libl libhgfs libz libfetch libvtreefs libaudiodriver libmthread \
|
libl libz libfetch libvtreefs libaudiodriver libmthread \
|
||||||
libexec libdevman libusb libminlib libasyn \
|
libexec libdevman libusb libminlib libasyn \
|
||||||
libddekit libminixfs libbdev libelf libminc libcrypt libterminfo \
|
libddekit libminixfs libbdev libelf libminc libcrypt libterminfo \
|
||||||
libcurses libvassert libutil libpuffs librefuse libbz2 libarchive libprop \
|
libcurses libvassert libutil libpuffs librefuse libbz2 libarchive \
|
||||||
libnetsock
|
libprop libnetsock libsffs libhgfs
|
||||||
|
|
||||||
SUBDIR+= ../external/public-domain/xz/lib
|
SUBDIR+= ../external/public-domain/xz/lib
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,6 @@
|
||||||
|
|
||||||
LIB= hgfs
|
LIB= hgfs
|
||||||
SRCS= backdoor.S attr.c channel.c dir.c error.c file.c \
|
SRCS= backdoor.S attr.c channel.c dir.c error.c file.c \
|
||||||
info.c link.c misc.c path.c rpc.c time.c
|
hgfs.c info.c link.c path.c rpc.c time.c
|
||||||
|
|
||||||
.include <bsd.lib.mk>
|
.include <bsd.lib.mk>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* attr_get *
|
* attr_get *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
void attr_get(attr)
|
void attr_get(attr)
|
||||||
struct hgfs_attr *attr;
|
struct sffs_attr *attr;
|
||||||
{
|
{
|
||||||
/* Get attribute information from the RPC buffer, storing the requested parts
|
/* Get attribute information from the RPC buffer, storing the requested parts
|
||||||
* in the given attr structure.
|
* in the given attr structure.
|
||||||
|
@ -20,16 +20,16 @@ struct hgfs_attr *attr;
|
||||||
|
|
||||||
size_lo = RPC_NEXT32;
|
size_lo = RPC_NEXT32;
|
||||||
size_hi = RPC_NEXT32;
|
size_hi = RPC_NEXT32;
|
||||||
if (attr->a_mask & HGFS_ATTR_SIZE)
|
if (attr->a_mask & SFFS_ATTR_SIZE)
|
||||||
attr->a_size = make64(size_lo, size_hi);
|
attr->a_size = make64(size_lo, size_hi);
|
||||||
|
|
||||||
time_get((attr->a_mask & HGFS_ATTR_CRTIME) ? &attr->a_crtime : NULL);
|
time_get((attr->a_mask & SFFS_ATTR_CRTIME) ? &attr->a_crtime : NULL);
|
||||||
time_get((attr->a_mask & HGFS_ATTR_ATIME) ? &attr->a_atime : NULL);
|
time_get((attr->a_mask & SFFS_ATTR_ATIME) ? &attr->a_atime : NULL);
|
||||||
time_get((attr->a_mask & HGFS_ATTR_MTIME) ? &attr->a_mtime : NULL);
|
time_get((attr->a_mask & SFFS_ATTR_MTIME) ? &attr->a_mtime : NULL);
|
||||||
time_get((attr->a_mask & HGFS_ATTR_CTIME) ? &attr->a_ctime : NULL);
|
time_get((attr->a_mask & SFFS_ATTR_CTIME) ? &attr->a_ctime : NULL);
|
||||||
|
|
||||||
mode |= HGFS_PERM_TO_MODE(RPC_NEXT8);
|
mode |= HGFS_PERM_TO_MODE(RPC_NEXT8);
|
||||||
if (attr->a_mask & HGFS_ATTR_MODE) attr->a_mode = mode;
|
if (attr->a_mask & SFFS_ATTR_MODE) attr->a_mode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -37,7 +37,7 @@ struct hgfs_attr *attr;
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
int hgfs_getattr(path, attr)
|
int hgfs_getattr(path, attr)
|
||||||
char *path;
|
char *path;
|
||||||
struct hgfs_attr *attr;
|
struct sffs_attr *attr;
|
||||||
{
|
{
|
||||||
/* Get selected attributes of a file by path name.
|
/* Get selected attributes of a file by path name.
|
||||||
*/
|
*/
|
||||||
|
@ -60,7 +60,7 @@ struct hgfs_attr *attr;
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
int hgfs_setattr(path, attr)
|
int hgfs_setattr(path, attr)
|
||||||
char *path;
|
char *path;
|
||||||
struct hgfs_attr *attr;
|
struct sffs_attr *attr;
|
||||||
{
|
{
|
||||||
/* Set selected attributes of a file by path name.
|
/* Set selected attributes of a file by path name.
|
||||||
*/
|
*/
|
||||||
|
@ -74,14 +74,14 @@ struct hgfs_attr *attr;
|
||||||
* HGFS protocol version (v2/v3).
|
* HGFS protocol version (v2/v3).
|
||||||
*/
|
*/
|
||||||
mask = 0;
|
mask = 0;
|
||||||
if (attr->a_mask & HGFS_ATTR_MODE) mask |= HGFS_ATTR_MODE;
|
if (attr->a_mask & SFFS_ATTR_MODE) mask |= HGFS_ATTR_MODE;
|
||||||
if (attr->a_mask & HGFS_ATTR_SIZE) mask |= HGFS_ATTR_SIZE;
|
if (attr->a_mask & SFFS_ATTR_SIZE) mask |= HGFS_ATTR_SIZE;
|
||||||
if (attr->a_mask & HGFS_ATTR_CRTIME) mask |= HGFS_ATTR_CRTIME;
|
if (attr->a_mask & SFFS_ATTR_CRTIME) mask |= HGFS_ATTR_CRTIME;
|
||||||
if (attr->a_mask & HGFS_ATTR_ATIME)
|
if (attr->a_mask & SFFS_ATTR_ATIME)
|
||||||
mask |= HGFS_ATTR_ATIME | HGFS_ATTR_ATIME_SET;
|
mask |= HGFS_ATTR_ATIME | HGFS_ATTR_ATIME_SET;
|
||||||
if (attr->a_mask & HGFS_ATTR_MTIME)
|
if (attr->a_mask & SFFS_ATTR_MTIME)
|
||||||
mask |= HGFS_ATTR_MTIME | HGFS_ATTR_MTIME_SET;
|
mask |= HGFS_ATTR_MTIME | HGFS_ATTR_MTIME_SET;
|
||||||
if (attr->a_mask & HGFS_ATTR_CTIME) mask |= HGFS_ATTR_CTIME;
|
if (attr->a_mask & SFFS_ATTR_CTIME) mask |= HGFS_ATTR_CTIME;
|
||||||
|
|
||||||
RPC_NEXT8 = mask;
|
RPC_NEXT8 = mask;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
int hgfs_opendir(path, handle)
|
int hgfs_opendir(path, handle)
|
||||||
char *path;
|
char *path;
|
||||||
hgfs_dir_t *handle;
|
sffs_dir_t *handle;
|
||||||
{
|
{
|
||||||
/* Open a directory. Store a directory handle upon success.
|
/* Open a directory. Store a directory handle upon success.
|
||||||
*/
|
*/
|
||||||
|
@ -20,7 +20,7 @@ hgfs_dir_t *handle;
|
||||||
if ((r = rpc_query()) != OK)
|
if ((r = rpc_query()) != OK)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
*handle = (hgfs_dir_t)RPC_NEXT32;
|
*handle = (sffs_dir_t)RPC_NEXT32;
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
@ -29,11 +29,11 @@ hgfs_dir_t *handle;
|
||||||
* hgfs_readdir *
|
* hgfs_readdir *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
int hgfs_readdir(handle, index, buf, size, attr)
|
int hgfs_readdir(handle, index, buf, size, attr)
|
||||||
hgfs_dir_t handle;
|
sffs_dir_t handle;
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
char *buf;
|
char *buf;
|
||||||
size_t size;
|
size_t size;
|
||||||
struct hgfs_attr *attr;
|
struct sffs_attr *attr;
|
||||||
{
|
{
|
||||||
/* Read a directory entry from an open directory, using a zero-based index
|
/* Read a directory entry from an open directory, using a zero-based index
|
||||||
* number. Upon success, the resulting path name is stored in the given buffer
|
* number. Upon success, the resulting path name is stored in the given buffer
|
||||||
|
@ -67,7 +67,7 @@ struct hgfs_attr *attr;
|
||||||
* hgfs_closedir *
|
* hgfs_closedir *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
int hgfs_closedir(handle)
|
int hgfs_closedir(handle)
|
||||||
hgfs_dir_t handle;
|
sffs_dir_t handle;
|
||||||
{
|
{
|
||||||
/* Close an open directory.
|
/* Close an open directory.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -12,7 +12,7 @@ int hgfs_open(path, flags, mode, handle)
|
||||||
char *path; /* path name to open */
|
char *path; /* path name to open */
|
||||||
int flags; /* open flags to use */
|
int flags; /* open flags to use */
|
||||||
int mode; /* mode to create (user bits only) */
|
int mode; /* mode to create (user bits only) */
|
||||||
hgfs_file_t *handle; /* place to store resulting handle */
|
sffs_file_t *handle; /* place to store resulting handle */
|
||||||
{
|
{
|
||||||
/* Open a file. Store a file handle upon success.
|
/* Open a file. Store a file handle upon success.
|
||||||
*/
|
*/
|
||||||
|
@ -42,7 +42,7 @@ hgfs_file_t *handle; /* place to store resulting handle */
|
||||||
if ((r = rpc_query()) != OK)
|
if ((r = rpc_query()) != OK)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
*handle = (hgfs_file_t)RPC_NEXT32;
|
*handle = (sffs_file_t)RPC_NEXT32;
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
@ -50,8 +50,8 @@ hgfs_file_t *handle; /* place to store resulting handle */
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* hgfs_read *
|
* hgfs_read *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
int hgfs_read(handle, buf, size, off)
|
ssize_t hgfs_read(handle, buf, size, off)
|
||||||
hgfs_file_t handle; /* handle to open file */
|
sffs_file_t handle; /* handle to open file */
|
||||||
char *buf; /* data buffer or NULL */
|
char *buf; /* data buffer or NULL */
|
||||||
size_t size; /* maximum number of bytes to read */
|
size_t size; /* maximum number of bytes to read */
|
||||||
u64_t off; /* file offset */
|
u64_t off; /* file offset */
|
||||||
|
@ -84,8 +84,8 @@ u64_t off; /* file offset */
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* hgfs_write *
|
* hgfs_write *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
int hgfs_write(handle, buf, len, off)
|
ssize_t hgfs_write(handle, buf, len, off)
|
||||||
hgfs_file_t handle; /* handle to open file */
|
sffs_file_t handle; /* handle to open file */
|
||||||
char *buf; /* data buffer or NULL */
|
char *buf; /* data buffer or NULL */
|
||||||
size_t len; /* number of bytes to write */
|
size_t len; /* number of bytes to write */
|
||||||
u64_t off; /* file offset */
|
u64_t off; /* file offset */
|
||||||
|
@ -116,7 +116,7 @@ u64_t off; /* file offset */
|
||||||
* hgfs_close *
|
* hgfs_close *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
int hgfs_close(handle)
|
int hgfs_close(handle)
|
||||||
hgfs_file_t handle; /* handle to open file */
|
sffs_file_t handle; /* handle to open file */
|
||||||
{
|
{
|
||||||
/* Close an open file.
|
/* Close an open file.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2,18 +2,48 @@
|
||||||
|
|
||||||
#include "inc.h"
|
#include "inc.h"
|
||||||
|
|
||||||
|
struct sffs_table hgfs_table = {
|
||||||
|
.t_open = hgfs_open,
|
||||||
|
.t_read = hgfs_read,
|
||||||
|
.t_write = hgfs_write,
|
||||||
|
.t_close = hgfs_close,
|
||||||
|
|
||||||
|
.t_readbuf = hgfs_readbuf,
|
||||||
|
.t_writebuf = hgfs_writebuf,
|
||||||
|
|
||||||
|
.t_opendir = hgfs_opendir,
|
||||||
|
.t_readdir = hgfs_readdir,
|
||||||
|
.t_closedir = hgfs_closedir,
|
||||||
|
|
||||||
|
.t_getattr = hgfs_getattr,
|
||||||
|
.t_setattr = hgfs_setattr,
|
||||||
|
|
||||||
|
.t_mkdir = hgfs_mkdir,
|
||||||
|
.t_unlink = hgfs_unlink,
|
||||||
|
.t_rmdir = hgfs_rmdir,
|
||||||
|
.t_rename = hgfs_rename,
|
||||||
|
|
||||||
|
.t_queryvol = hgfs_queryvol,
|
||||||
|
};
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* hgfs_init *
|
* hgfs_init *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
int hgfs_init()
|
int hgfs_init(const struct sffs_table **tablep)
|
||||||
{
|
{
|
||||||
/* Initialize the library. Return OK on success, or a negative error code
|
/* Initialize the library. Return OK on success, or a negative error code
|
||||||
* otherwise. If EAGAIN is returned, shared folders are disabled.
|
* otherwise. If EAGAIN is returned, shared folders are disabled.
|
||||||
*/
|
*/
|
||||||
|
int r;
|
||||||
|
|
||||||
time_init();
|
time_init();
|
||||||
|
|
||||||
return rpc_open();
|
r = rpc_open();
|
||||||
|
|
||||||
|
if (r == OK)
|
||||||
|
*tablep = &hgfs_table;
|
||||||
|
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -26,3 +56,4 @@ void hgfs_cleanup()
|
||||||
|
|
||||||
rpc_close();
|
rpc_close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,7 @@
|
||||||
/* Part of libhgfs - (c) 2009, D.C. van Moolenbroek */
|
/* Part of libhgfs - (c) 2009, D.C. van Moolenbroek */
|
||||||
|
|
||||||
#ifndef __NBSD_LIBC
|
#include <minix/drivers.h>
|
||||||
#define _POSIX_SOURCE 1 /* need PATH_MAX */
|
#include <minix/sffs.h>
|
||||||
#endif
|
|
||||||
#define _SYSTEM 1 /* need negative error codes */
|
|
||||||
|
|
||||||
#include <minix/config.h>
|
|
||||||
#include <minix/const.h>
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include <minix/hgfs.h>
|
#include <minix/hgfs.h>
|
||||||
|
|
||||||
#define PREFIX(x) __libhgfs_##x
|
#define PREFIX(x) __libhgfs_##x
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
|
|
||||||
/* attr.c */
|
/* attr.c */
|
||||||
#define attr_get PREFIX(attr_get)
|
#define attr_get PREFIX(attr_get)
|
||||||
void attr_get(struct hgfs_attr *attr);
|
void attr_get(struct sffs_attr *attr);
|
||||||
|
int hgfs_getattr(char *path, struct sffs_attr *attr);
|
||||||
|
int hgfs_setattr(char *path, struct sffs_attr *attr);
|
||||||
|
|
||||||
/* backdoor.s */
|
/* backdoor.s */
|
||||||
#define backdoor PREFIX(backdoor)
|
#define backdoor PREFIX(backdoor)
|
||||||
|
@ -22,10 +24,33 @@ void channel_close(struct channel *ch);
|
||||||
int channel_send(struct channel *ch, char *buf, int len);
|
int channel_send(struct channel *ch, char *buf, int len);
|
||||||
int channel_recv(struct channel *ch, char *buf, int max);
|
int channel_recv(struct channel *ch, char *buf, int max);
|
||||||
|
|
||||||
|
/* dir.c */
|
||||||
|
int hgfs_opendir(char *path, sffs_dir_t *handle);
|
||||||
|
int hgfs_readdir(sffs_dir_t handle, unsigned int index, char *buf, size_t size,
|
||||||
|
struct sffs_attr *attr);
|
||||||
|
int hgfs_closedir(sffs_dir_t handle);
|
||||||
|
|
||||||
/* error.c */
|
/* error.c */
|
||||||
#define error_convert PREFIX(error_convert)
|
#define error_convert PREFIX(error_convert)
|
||||||
int error_convert(int err);
|
int error_convert(int err);
|
||||||
|
|
||||||
|
/* file.c */
|
||||||
|
int hgfs_open(char *path, int flags, int mode, sffs_file_t *handle);
|
||||||
|
ssize_t hgfs_read(sffs_file_t handle, char *buf, size_t size, u64_t offset);
|
||||||
|
ssize_t hgfs_write(sffs_file_t handle, char *buf, size_t len, u64_t offset);
|
||||||
|
int hgfs_close(sffs_file_t handle);
|
||||||
|
size_t hgfs_readbuf(char **ptr);
|
||||||
|
size_t hgfs_writebuf(char **ptr);
|
||||||
|
|
||||||
|
/* info.c */
|
||||||
|
int hgfs_queryvol(char *path, u64_t *free, u64_t *total);
|
||||||
|
|
||||||
|
/* link.c */
|
||||||
|
int hgfs_mkdir(char *path, int mode);
|
||||||
|
int hgfs_unlink(char *path);
|
||||||
|
int hgfs_rmdir(char *path);
|
||||||
|
int hgfs_rename(char *opath, char *npath);
|
||||||
|
|
||||||
/* path.c */
|
/* path.c */
|
||||||
#define path_put PREFIX(path_put)
|
#define path_put PREFIX(path_put)
|
||||||
#define path_get PREFIX(path_get)
|
#define path_get PREFIX(path_get)
|
||||||
|
|
9
lib/libsffs/Makefile
Normal file
9
lib/libsffs/Makefile
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# Makefile for libsffs
|
||||||
|
.include <bsd.own.mk>
|
||||||
|
|
||||||
|
LIB= sffs
|
||||||
|
|
||||||
|
SRCS= dentry.c handle.c inode.c link.c lookup.c main.c misc.c mount.c \
|
||||||
|
name.c path.c read.c stat.c table.c util.c verify.c write.c
|
||||||
|
|
||||||
|
.include <bsd.lib.mk>
|
|
@ -1,3 +1,5 @@
|
||||||
|
#ifndef _SFFS_CONST_H
|
||||||
|
#define _SFFS_CONST_H
|
||||||
|
|
||||||
/* Number of inodes. */
|
/* Number of inodes. */
|
||||||
/* The following number must not exceed 16. The i_num field is only a short. */
|
/* The following number must not exceed 16. The i_num field is only a short. */
|
||||||
|
@ -10,3 +12,5 @@
|
||||||
* Also used by getdents. This is not the underlying data transfer unit size.
|
* Also used by getdents. This is not the underlying data transfer unit size.
|
||||||
*/
|
*/
|
||||||
#define BLOCK_SIZE 4096
|
#define BLOCK_SIZE 4096
|
||||||
|
|
||||||
|
#endif /* _SFFS_CONST_H */
|
|
@ -177,7 +177,7 @@ char *name;
|
||||||
unsigned int val;
|
unsigned int val;
|
||||||
char buf[NAME_MAX+1], *p;
|
char buf[NAME_MAX+1], *p;
|
||||||
|
|
||||||
dprintf(("HGFS: hash_dentry for '%s'\n", name));
|
dprintf(("%s: hash_dentry for '%s'\n", sffs_name, name));
|
||||||
|
|
||||||
normalize_name(buf, name);
|
normalize_name(buf, name);
|
||||||
|
|
19
lib/libsffs/glo.h
Normal file
19
lib/libsffs/glo.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef _SFFS_GLO_H
|
||||||
|
#define _SFFS_GLO_H
|
||||||
|
|
||||||
|
#ifdef _TABLE
|
||||||
|
#undef EXTERN
|
||||||
|
#define EXTERN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EXTERN char *sffs_name; /* file server name */
|
||||||
|
EXTERN const struct sffs_table *sffs_table; /* call table */
|
||||||
|
EXTERN struct sffs_params *sffs_params; /* parameters */
|
||||||
|
|
||||||
|
EXTERN message m_in; /* request message */
|
||||||
|
EXTERN message m_out; /* reply message */
|
||||||
|
EXTERN struct state state; /* global state */
|
||||||
|
|
||||||
|
extern int(*call_vec[]) (void);
|
||||||
|
|
||||||
|
#endif /* _SFFS_GLO_H */
|
|
@ -31,17 +31,17 @@ struct inode *ino;
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (IS_DIR(ino)) {
|
if (IS_DIR(ino)) {
|
||||||
r = hgfs_opendir(path, &ino->i_dir);
|
r = sffs_table->t_opendir(path, &ino->i_dir);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!state.read_only)
|
if (!state.s_read_only)
|
||||||
r = hgfs_open(path, O_RDWR, 0, &ino->i_file);
|
r = sffs_table->t_open(path, O_RDWR, 0, &ino->i_file);
|
||||||
|
|
||||||
/* Protection or mount status might prevent us from writing. With the
|
/* Protection or mount status might prevent us from writing. With the
|
||||||
* information that we have available, this is the best we can do..
|
* information that we have available, this is the best we can do..
|
||||||
*/
|
*/
|
||||||
if (state.read_only || r != OK)
|
if (state.s_read_only || r != OK)
|
||||||
r = hgfs_open(path, O_RDONLY, 0, &ino->i_file);
|
r = sffs_table->t_open(path, O_RDONLY, 0, &ino->i_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r != OK)
|
if (r != OK)
|
||||||
|
@ -67,12 +67,13 @@ struct inode *ino;
|
||||||
|
|
||||||
/* We ignore any errors here, because we can't deal with them anyway. */
|
/* We ignore any errors here, because we can't deal with them anyway. */
|
||||||
if (IS_DIR(ino))
|
if (IS_DIR(ino))
|
||||||
r = hgfs_closedir(ino->i_dir);
|
r = sffs_table->t_closedir(ino->i_dir);
|
||||||
else
|
else
|
||||||
r = hgfs_close(ino->i_file);
|
r = sffs_table->t_close(ino->i_file);
|
||||||
|
|
||||||
if (r != OK)
|
if (r != OK)
|
||||||
printf("HGFS: put_handle: handle close operation returned %d\n", r);
|
printf("%s: put_handle: handle close operation returned %d\n",
|
||||||
|
sffs_name, r);
|
||||||
|
|
||||||
ino->i_flags &= ~I_HANDLE;
|
ino->i_flags &= ~I_HANDLE;
|
||||||
}
|
}
|
24
lib/libsffs/inc.h
Normal file
24
lib/libsffs/inc.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef _SFFS_INC_H
|
||||||
|
#define _SFFS_INC_H
|
||||||
|
|
||||||
|
#include <minix/drivers.h>
|
||||||
|
#include <minix/vfsif.h>
|
||||||
|
#include <minix/optset.h>
|
||||||
|
#include <minix/sffs.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
#define dprintf(x) printf x
|
||||||
|
#else
|
||||||
|
#define dprintf(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "type.h"
|
||||||
|
#include "const.h"
|
||||||
|
#include "proto.h"
|
||||||
|
#include "glo.h"
|
||||||
|
#include "inode.h"
|
||||||
|
|
||||||
|
#endif /* _SFFS_INC_H */
|
|
@ -34,8 +34,8 @@ struct inode *init_inode()
|
||||||
|
|
||||||
TAILQ_INIT(&free_list);
|
TAILQ_INIT(&free_list);
|
||||||
|
|
||||||
dprintf(("HGFS: %d inodes, %u bytes each, equals %u bytes\n",
|
dprintf(("%s: %d inodes, %u bytes each, equals %u bytes\n",
|
||||||
NUM_INODES, sizeof(struct inode), sizeof(inodes)));
|
sffs_name, NUM_INODES, sizeof(struct inode), sizeof(inodes)));
|
||||||
|
|
||||||
/* Mark all inodes except the root inode as free. */
|
/* Mark all inodes except the root inode as free. */
|
||||||
for (index = 1; index < NUM_INODES; index++) {
|
for (index = 1; index < NUM_INODES; index++) {
|
||||||
|
@ -76,7 +76,7 @@ ino_t ino_nr;
|
||||||
/* Inode 0 (= index -1) is not a valid inode number. */
|
/* Inode 0 (= index -1) is not a valid inode number. */
|
||||||
index = INODE_INDEX(ino_nr);
|
index = INODE_INDEX(ino_nr);
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
printf("HGFS: VFS passed invalid inode number!\n");
|
printf("%s: VFS passed invalid inode number!\n", sffs_name);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -87,14 +87,14 @@ ino_t ino_nr;
|
||||||
|
|
||||||
/* Make sure the generation number matches. */
|
/* Make sure the generation number matches. */
|
||||||
if (INODE_GEN(ino_nr) != ino->i_gen) {
|
if (INODE_GEN(ino_nr) != ino->i_gen) {
|
||||||
printf("HGFS: VFS passed outdated inode number!\n");
|
printf("%s: VFS passed outdated inode number!\n", sffs_name);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The VFS/FS protocol only uses referenced inodes. */
|
/* The VFS/FS protocol only uses referenced inodes. */
|
||||||
if (ino->i_ref == 0)
|
if (ino->i_ref == 0)
|
||||||
printf("HGFS: VFS passed unused inode!\n");
|
printf("%s: VFS passed unused inode!\n", sffs_name);
|
||||||
|
|
||||||
return ino;
|
return ino;
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,7 @@ struct inode *ino;
|
||||||
* count were zero before, remove the inode from the free list.
|
* count were zero before, remove the inode from the free list.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
dprintf(("HGFS: get_inode(%p) ['%s']\n", ino, ino->i_name));
|
dprintf(("%s: get_inode(%p) ['%s']\n", sffs_name, ino, ino->i_name));
|
||||||
|
|
||||||
/* (INUSE, CACHED) -> INUSE */
|
/* (INUSE, CACHED) -> INUSE */
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ struct inode *ino;
|
||||||
* reached zero, mark the inode as cached or free.
|
* reached zero, mark the inode as cached or free.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
dprintf(("HGFS: put_inode(%p) ['%s']\n", ino, ino->i_name));
|
dprintf(("%s: put_inode(%p) ['%s']\n", sffs_name, ino, ino->i_name));
|
||||||
|
|
||||||
assert(ino != NULL);
|
assert(ino != NULL);
|
||||||
assert(ino->i_ref > 0);
|
assert(ino->i_ref > 0);
|
||||||
|
@ -223,7 +223,7 @@ struct inode *get_free_inode()
|
||||||
|
|
||||||
/* If there are no inodes on the free list, we cannot satisfy the request. */
|
/* If there are no inodes on the free list, we cannot satisfy the request. */
|
||||||
if (TAILQ_EMPTY(&free_list)) {
|
if (TAILQ_EMPTY(&free_list)) {
|
||||||
printf("HGFS: out of inodes!\n");
|
printf("%s: out of inodes!\n", sffs_name);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef _INODE_H
|
#ifndef _SFFS_INODE_H
|
||||||
#define _INODE_H
|
#define _SFFS_INODE_H
|
||||||
|
|
||||||
/* We cannot use inode number 0, so to be able to use bitmasks to combine
|
/* We cannot use inode number 0, so to be able to use bitmasks to combine
|
||||||
* inode and generation numbers, we have to use one fewer than the maximum of
|
* inode and generation numbers, we have to use one fewer than the maximum of
|
||||||
|
@ -62,17 +62,13 @@ struct inode {
|
||||||
unsigned short i_ref; /* VFS reference count */
|
unsigned short i_ref; /* VFS reference count */
|
||||||
unsigned short i_flags; /* any combination of I_* flags */
|
unsigned short i_flags; /* any combination of I_* flags */
|
||||||
union {
|
union {
|
||||||
TAILQ_ENTRY(inode) u_free; /* free list chain entry */
|
TAILQ_ENTRY(inode) i_free; /* free list chain entry */
|
||||||
hgfs_file_t u_file; /* handle to open file */
|
sffs_file_t i_file; /* handle to open file */
|
||||||
hgfs_dir_t u_dir; /* handle to open directory */
|
sffs_dir_t i_dir; /* handle to open directory */
|
||||||
} i_u;
|
};
|
||||||
char i_name[NAME_MAX+1]; /* entry name in parent directory */
|
char i_name[NAME_MAX+1]; /* entry name in parent directory */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define i_free i_u.u_free
|
|
||||||
#define i_file i_u.u_file
|
|
||||||
#define i_dir i_u.u_dir
|
|
||||||
|
|
||||||
#define I_DIR 0x01 /* this inode represents a directory */
|
#define I_DIR 0x01 /* this inode represents a directory */
|
||||||
#define I_HANDLE 0x02 /* this inode has an open handle */
|
#define I_HANDLE 0x02 /* this inode has an open handle */
|
||||||
|
|
||||||
|
@ -89,4 +85,4 @@ struct inode {
|
||||||
|
|
||||||
#define MODE_TO_DIRFLAG(m) (S_ISDIR(m) ? I_DIR : 0)
|
#define MODE_TO_DIRFLAG(m) (S_ISDIR(m) ? I_DIR : 0)
|
||||||
|
|
||||||
#endif /* _INODE_H */
|
#endif /* _SFFS_INODE_H */
|
|
@ -26,12 +26,12 @@ int do_create()
|
||||||
*/
|
*/
|
||||||
char path[PATH_MAX], name[NAME_MAX+1];
|
char path[PATH_MAX], name[NAME_MAX+1];
|
||||||
struct inode *parent, *ino;
|
struct inode *parent, *ino;
|
||||||
struct hgfs_attr attr;
|
struct sffs_attr attr;
|
||||||
hgfs_file_t handle;
|
sffs_file_t handle;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
/* We cannot create files on a read-only file system. */
|
/* We cannot create files on a read-only file system. */
|
||||||
if (state.read_only)
|
if (state.s_read_only)
|
||||||
return EROFS;
|
return EROFS;
|
||||||
|
|
||||||
/* Get path, name, parent inode and possibly inode for the given path. */
|
/* Get path, name, parent inode and possibly inode for the given path. */
|
||||||
|
@ -59,7 +59,8 @@ int do_create()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform the actual create call. */
|
/* Perform the actual create call. */
|
||||||
r = hgfs_open(path, O_CREAT | O_EXCL | O_RDWR, m_in.REQ_MODE, &handle);
|
r = sffs_table->t_open(path, O_CREAT | O_EXCL | O_RDWR, m_in.REQ_MODE,
|
||||||
|
&handle);
|
||||||
|
|
||||||
if (r != OK) {
|
if (r != OK) {
|
||||||
/* Let's not try to be too clever with error codes here. If something
|
/* Let's not try to be too clever with error codes here. If something
|
||||||
|
@ -73,17 +74,17 @@ int do_create()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the created file's attributes. */
|
/* Get the created file's attributes. */
|
||||||
attr.a_mask = HGFS_ATTR_MODE | HGFS_ATTR_SIZE;
|
attr.a_mask = SFFS_ATTR_MODE | SFFS_ATTR_SIZE;
|
||||||
r = hgfs_getattr(path, &attr);
|
r = sffs_table->t_getattr(path, &attr);
|
||||||
|
|
||||||
/* If this fails, or returns a directory, we have a problem. This
|
/* If this fails, or returns a directory, we have a problem. This
|
||||||
* scenario is in fact possible with race conditions.
|
* scenario is in fact possible with race conditions.
|
||||||
* Simulate a close and return a somewhat appropriate error.
|
* Simulate a close and return a somewhat appropriate error.
|
||||||
*/
|
*/
|
||||||
if (r != OK || S_ISDIR(attr.a_mode)) {
|
if (r != OK || S_ISDIR(attr.a_mode)) {
|
||||||
printf("HGFS: lost file after creation!\n");
|
printf("%s: lost file after creation!\n", sffs_name);
|
||||||
|
|
||||||
hgfs_close(handle);
|
sffs_table->t_close(handle);
|
||||||
|
|
||||||
if (ino != NULL) {
|
if (ino != NULL) {
|
||||||
del_dentry(ino);
|
del_dentry(ino);
|
||||||
|
@ -94,7 +95,7 @@ int do_create()
|
||||||
return (r == OK) ? EEXIST : r;
|
return (r == OK) ? EEXIST : r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We do assume that the HGFS open(O_CREAT|O_EXCL) did its job.
|
/* We do assume that the underlying open(O_CREAT|O_EXCL) call did its job.
|
||||||
* If we previousy found an inode, get rid of it now. It's old.
|
* If we previousy found an inode, get rid of it now. It's old.
|
||||||
*/
|
*/
|
||||||
if (ino != NULL) {
|
if (ino != NULL) {
|
||||||
|
@ -118,8 +119,8 @@ int do_create()
|
||||||
m_out.RES_MODE = get_mode(ino, attr.a_mode);
|
m_out.RES_MODE = get_mode(ino, attr.a_mode);
|
||||||
m_out.RES_FILE_SIZE_HI = ex64hi(attr.a_size);
|
m_out.RES_FILE_SIZE_HI = ex64hi(attr.a_size);
|
||||||
m_out.RES_FILE_SIZE_LO = ex64lo(attr.a_size);
|
m_out.RES_FILE_SIZE_LO = ex64lo(attr.a_size);
|
||||||
m_out.RES_UID = opt.uid;
|
m_out.RES_UID = sffs_params->p_uid;
|
||||||
m_out.RES_GID = opt.gid;
|
m_out.RES_GID = sffs_params->p_gid;
|
||||||
m_out.RES_DEV = NO_DEV;
|
m_out.RES_DEV = NO_DEV;
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
|
@ -137,7 +138,7 @@ int do_mkdir()
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
/* We cannot create directories on a read-only file system. */
|
/* We cannot create directories on a read-only file system. */
|
||||||
if (state.read_only)
|
if (state.s_read_only)
|
||||||
return EROFS;
|
return EROFS;
|
||||||
|
|
||||||
/* Get the path string and possibly an inode for the given path. */
|
/* Get the path string and possibly an inode for the given path. */
|
||||||
|
@ -153,7 +154,7 @@ int do_mkdir()
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
/* Perform the actual mkdir call. */
|
/* Perform the actual mkdir call. */
|
||||||
r = hgfs_mkdir(path, m_in.REQ_MODE);
|
r = sffs_table->t_mkdir(path, m_in.REQ_MODE);
|
||||||
|
|
||||||
if (r != OK) {
|
if (r != OK) {
|
||||||
if (ino != NULL)
|
if (ino != NULL)
|
||||||
|
@ -181,50 +182,50 @@ static int force_remove(path, dir)
|
||||||
char *path; /* path to file or directory */
|
char *path; /* path to file or directory */
|
||||||
int dir; /* TRUE iff directory */
|
int dir; /* TRUE iff directory */
|
||||||
{
|
{
|
||||||
/* Remove a file or directory. Wrapper around hgfs_unlink and hgfs_rmdir that
|
/* Remove a file or directory. Wrapper around unlink and rmdir that makes the
|
||||||
* makes the target temporarily writable if the operation fails with an access
|
* target temporarily writable if the operation fails with an access denied
|
||||||
* denied error. On Windows hosts, read-only files or directories cannot be
|
* error. On Windows hosts, read-only files or directories cannot be removed
|
||||||
* removed (even though they can be renamed). In general, the HGFS server
|
* (even though they can be renamed). In general, the SFFS library follows the
|
||||||
* follows the behavior of the host file system, but this case just confuses
|
* behavior of the host file system, but this case just confuses the hell out
|
||||||
* the hell out of the MINIX userland..
|
* of the MINIX userland..
|
||||||
*/
|
*/
|
||||||
struct hgfs_attr attr;
|
struct sffs_attr attr;
|
||||||
int r, r2;
|
int r, r2;
|
||||||
|
|
||||||
/* First try to remove the target. */
|
/* First try to remove the target. */
|
||||||
if (dir)
|
if (dir)
|
||||||
r = hgfs_rmdir(path);
|
r = sffs_table->t_rmdir(path);
|
||||||
else
|
else
|
||||||
r = hgfs_unlink(path);
|
r = sffs_table->t_unlink(path);
|
||||||
|
|
||||||
if (r != EACCES) return r;
|
if (r != EACCES) return r;
|
||||||
|
|
||||||
/* If this fails with an access error, retrieve the target's mode. */
|
/* If this fails with an access error, retrieve the target's mode. */
|
||||||
attr.a_mask = HGFS_ATTR_MODE;
|
attr.a_mask = SFFS_ATTR_MODE;
|
||||||
|
|
||||||
r2 = hgfs_getattr(path, &attr);
|
r2 = sffs_table->t_getattr(path, &attr);
|
||||||
|
|
||||||
if (r2 != OK || (attr.a_mode & S_IWUSR)) return r;
|
if (r2 != OK || (attr.a_mode & S_IWUSR)) return r;
|
||||||
|
|
||||||
/* If the target is not writable, temporarily set it to writable. */
|
/* If the target is not writable, temporarily set it to writable. */
|
||||||
attr.a_mode |= S_IWUSR;
|
attr.a_mode |= S_IWUSR;
|
||||||
|
|
||||||
r2 = hgfs_setattr(path, &attr);
|
r2 = sffs_table->t_setattr(path, &attr);
|
||||||
|
|
||||||
if (r2 != OK) return r;
|
if (r2 != OK) return r;
|
||||||
|
|
||||||
/* Then try the original operation again. */
|
/* Then try the original operation again. */
|
||||||
if (dir)
|
if (dir)
|
||||||
r = hgfs_rmdir(path);
|
r = sffs_table->t_rmdir(path);
|
||||||
else
|
else
|
||||||
r = hgfs_unlink(path);
|
r = sffs_table->t_unlink(path);
|
||||||
|
|
||||||
if (r == OK) return r;
|
if (r == OK) return r;
|
||||||
|
|
||||||
/* If the operation still fails, unset the writable bit again. */
|
/* If the operation still fails, unset the writable bit again. */
|
||||||
attr.a_mode &= ~S_IWUSR;
|
attr.a_mode &= ~S_IWUSR;
|
||||||
|
|
||||||
hgfs_setattr(path, &attr);
|
sffs_table->t_setattr(path, &attr);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -241,7 +242,7 @@ int do_unlink()
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
/* We cannot delete files on a read-only file system. */
|
/* We cannot delete files on a read-only file system. */
|
||||||
if (state.read_only)
|
if (state.s_read_only)
|
||||||
return EROFS;
|
return EROFS;
|
||||||
|
|
||||||
/* Get the path string and possibly preexisting inode for the given path. */
|
/* Get the path string and possibly preexisting inode for the given path. */
|
||||||
|
@ -288,7 +289,7 @@ int do_rmdir()
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
/* We cannot remove directories on a read-only file system. */
|
/* We cannot remove directories on a read-only file system. */
|
||||||
if (state.read_only)
|
if (state.s_read_only)
|
||||||
return EROFS;
|
return EROFS;
|
||||||
|
|
||||||
/* Get the path string and possibly preexisting inode for the given path. */
|
/* Get the path string and possibly preexisting inode for the given path. */
|
||||||
|
@ -338,7 +339,7 @@ int do_rename()
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
/* We cannot do rename on a read-only file system. */
|
/* We cannot do rename on a read-only file system. */
|
||||||
if (state.read_only)
|
if (state.s_read_only)
|
||||||
return EROFS;
|
return EROFS;
|
||||||
|
|
||||||
/* Get path strings, names, directory inodes and possibly preexisting inodes
|
/* Get path strings, names, directory inodes and possibly preexisting inodes
|
||||||
|
@ -368,7 +369,7 @@ int do_rename()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform the actual rename call. */
|
/* Perform the actual rename call. */
|
||||||
r = hgfs_rename(old_path, new_path);
|
r = sffs_table->t_rename(old_path, new_path);
|
||||||
|
|
||||||
/* If we failed, or if we have nothing further to do: both inodes are
|
/* If we failed, or if we have nothing further to do: both inodes are
|
||||||
* NULL, or they both refer to the same file.
|
* NULL, or they both refer to the same file.
|
|
@ -10,13 +10,13 @@
|
||||||
#include "inc.h"
|
#include "inc.h"
|
||||||
|
|
||||||
static int get_mask(vfs_ucred_t *ucred);
|
static int get_mask(vfs_ucred_t *ucred);
|
||||||
static int access_as_dir(struct inode *ino, struct hgfs_attr *attr, int
|
static int access_as_dir(struct inode *ino, struct sffs_attr *attr, int
|
||||||
uid, int mask);
|
uid, int mask);
|
||||||
static int next_name(char **ptr, char **start, char name[NAME_MAX+1]);
|
static int next_name(char **ptr, char **start, char name[NAME_MAX+1]);
|
||||||
static int go_up(char path[PATH_MAX], struct inode *ino, struct inode
|
static int go_up(char path[PATH_MAX], struct inode *ino, struct inode
|
||||||
**res_ino, struct hgfs_attr *attr);
|
**res_ino, struct sffs_attr *attr);
|
||||||
static int go_down(char path[PATH_MAX], struct inode *ino, char *name,
|
static int go_down(char path[PATH_MAX], struct inode *ino, char *name,
|
||||||
struct inode **res_ino, struct hgfs_attr *attr);
|
struct inode **res_ino, struct sffs_attr *attr);
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* get_mask *
|
* get_mask *
|
||||||
|
@ -29,12 +29,12 @@ vfs_ucred_t *ucred; /* credentials of the caller */
|
||||||
*/
|
*/
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (ucred->vu_uid == opt.uid) return S_IXUSR;
|
if (ucred->vu_uid == sffs_params->p_uid) return S_IXUSR;
|
||||||
|
|
||||||
if (ucred->vu_gid == opt.gid) return S_IXGRP;
|
if (ucred->vu_gid == sffs_params->p_gid) return S_IXGRP;
|
||||||
|
|
||||||
for (i = 0; i < ucred->vu_ngroups; i++)
|
for (i = 0; i < ucred->vu_ngroups; i++)
|
||||||
if (ucred->vu_sgroups[i] == opt.gid) return S_IXGRP;
|
if (ucred->vu_sgroups[i] == sffs_params->p_gid) return S_IXGRP;
|
||||||
|
|
||||||
return S_IXOTH;
|
return S_IXOTH;
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ vfs_ucred_t *ucred; /* credentials of the caller */
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
static int access_as_dir(ino, attr, uid, mask)
|
static int access_as_dir(ino, attr, uid, mask)
|
||||||
struct inode *ino; /* the inode to test */
|
struct inode *ino; /* the inode to test */
|
||||||
struct hgfs_attr *attr; /* attributes of the inode */
|
struct sffs_attr *attr; /* attributes of the inode */
|
||||||
int uid; /* UID of the caller */
|
int uid; /* UID of the caller */
|
||||||
int mask; /* search access mask of the caller */
|
int mask; /* search access mask of the caller */
|
||||||
{
|
{
|
||||||
|
@ -53,7 +53,7 @@ int mask; /* search access mask of the caller */
|
||||||
*/
|
*/
|
||||||
mode_t mode;
|
mode_t mode;
|
||||||
|
|
||||||
assert(attr->a_mask & HGFS_ATTR_MODE);
|
assert(attr->a_mask & SFFS_ATTR_MODE);
|
||||||
|
|
||||||
/* The inode must be a directory to begin with. */
|
/* The inode must be a directory to begin with. */
|
||||||
if (!IS_DIR(ino)) return ENOTDIR;
|
if (!IS_DIR(ino)) return ENOTDIR;
|
||||||
|
@ -106,7 +106,7 @@ static int go_up(path, ino, res_ino, attr)
|
||||||
char path[PATH_MAX]; /* path to take the last part from */
|
char path[PATH_MAX]; /* path to take the last part from */
|
||||||
struct inode *ino; /* inode of the current directory */
|
struct inode *ino; /* inode of the current directory */
|
||||||
struct inode **res_ino; /* place to store resulting inode */
|
struct inode **res_ino; /* place to store resulting inode */
|
||||||
struct hgfs_attr *attr; /* place to store inode attributes */
|
struct sffs_attr *attr; /* place to store inode attributes */
|
||||||
{
|
{
|
||||||
/* Given an inode, progress into the parent directory.
|
/* Given an inode, progress into the parent directory.
|
||||||
*/
|
*/
|
||||||
|
@ -136,7 +136,7 @@ char path[PATH_MAX]; /* path to add the name to */
|
||||||
struct inode *parent; /* inode of the current directory */
|
struct inode *parent; /* inode of the current directory */
|
||||||
char *name; /* name of the directory entry */
|
char *name; /* name of the directory entry */
|
||||||
struct inode **res_ino; /* place to store resulting inode */
|
struct inode **res_ino; /* place to store resulting inode */
|
||||||
struct hgfs_attr *attr; /* place to store inode attributes */
|
struct sffs_attr *attr; /* place to store inode attributes */
|
||||||
{
|
{
|
||||||
/* Given a directory inode and a name, progress into a directory entry.
|
/* Given a directory inode and a name, progress into a directory entry.
|
||||||
*/
|
*/
|
||||||
|
@ -146,18 +146,18 @@ struct hgfs_attr *attr; /* place to store inode attributes */
|
||||||
if ((r = push_path(path, name)) != OK)
|
if ((r = push_path(path, name)) != OK)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
dprintf(("HGFS: go_down: name '%s', path now '%s'\n", name, path));
|
dprintf(("%s: go_down: name '%s', path now '%s'\n", sffs_name, name, path));
|
||||||
|
|
||||||
ino = lookup_dentry(parent, name);
|
ino = lookup_dentry(parent, name);
|
||||||
|
|
||||||
dprintf(("HGFS: lookup_dentry('%s') returned %p\n", name, ino));
|
dprintf(("%s: lookup_dentry('%s') returned %p\n", sffs_name, name, ino));
|
||||||
|
|
||||||
if (ino != NULL)
|
if (ino != NULL)
|
||||||
r = verify_path(path, ino, attr, &stale);
|
r = verify_path(path, ino, attr, &stale);
|
||||||
else
|
else
|
||||||
r = hgfs_getattr(path, attr);
|
r = sffs_table->t_getattr(path, attr);
|
||||||
|
|
||||||
dprintf(("HGFS: path query returned %d\n", r));
|
dprintf(("%s: path query returned %d\n", sffs_name, r));
|
||||||
|
|
||||||
if (r != OK) {
|
if (r != OK) {
|
||||||
if (ino != NULL) {
|
if (ino != NULL) {
|
||||||
|
@ -170,13 +170,13 @@ struct hgfs_attr *attr; /* place to store inode attributes */
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
dprintf(("HGFS: name '%s'\n", name));
|
dprintf(("%s: name '%s'\n", sffs_name, name));
|
||||||
|
|
||||||
if (ino == NULL) {
|
if (ino == NULL) {
|
||||||
if ((ino = get_free_inode()) == NULL)
|
if ((ino = get_free_inode()) == NULL)
|
||||||
return ENFILE;
|
return ENFILE;
|
||||||
|
|
||||||
dprintf(("HGFS: inode %p ref %d\n", ino, ino->i_ref));
|
dprintf(("%s: inode %p ref %d\n", sffs_name, ino, ino->i_ref));
|
||||||
|
|
||||||
ino->i_flags = MODE_TO_DIRFLAG(attr->a_mode);
|
ino->i_flags = MODE_TO_DIRFLAG(attr->a_mode);
|
||||||
|
|
||||||
|
@ -197,7 +197,7 @@ int do_lookup()
|
||||||
ino_t dir_ino_nr, root_ino_nr;
|
ino_t dir_ino_nr, root_ino_nr;
|
||||||
struct inode *cur_ino, *root_ino;
|
struct inode *cur_ino, *root_ino;
|
||||||
struct inode *next_ino = NULL;
|
struct inode *next_ino = NULL;
|
||||||
struct hgfs_attr attr;
|
struct sffs_attr attr;
|
||||||
char buf[PATH_MAX], path[PATH_MAX];
|
char buf[PATH_MAX], path[PATH_MAX];
|
||||||
char name[NAME_MAX+1];
|
char name[NAME_MAX+1];
|
||||||
char *ptr, *last;
|
char *ptr, *last;
|
||||||
|
@ -221,7 +221,7 @@ int do_lookup()
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (buf[len-1] != 0) {
|
if (buf[len-1] != 0) {
|
||||||
printf("HGFS: VFS did not zero-terminate path!\n");
|
printf("%s: VFS did not zero-terminate path!\n", sffs_name);
|
||||||
|
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -231,7 +231,7 @@ int do_lookup()
|
||||||
*/
|
*/
|
||||||
if (m_in.REQ_FLAGS & PATH_GET_UCRED) {
|
if (m_in.REQ_FLAGS & PATH_GET_UCRED) {
|
||||||
if (m_in.REQ_UCRED_SIZE != sizeof(ucred)) {
|
if (m_in.REQ_UCRED_SIZE != sizeof(ucred)) {
|
||||||
printf("HGFS: bad credential structure size\n");
|
printf("%s: bad credential structure size\n", sffs_name);
|
||||||
|
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -251,12 +251,12 @@ int do_lookup()
|
||||||
mask = get_mask(&ucred);
|
mask = get_mask(&ucred);
|
||||||
|
|
||||||
/* Start the actual lookup. */
|
/* Start the actual lookup. */
|
||||||
dprintf(("HGFS: lookup: got query '%s'\n", buf));
|
dprintf(("%s: lookup: got query '%s'\n", sffs_name, buf));
|
||||||
|
|
||||||
if ((cur_ino = find_inode(dir_ino_nr)) == NULL)
|
if ((cur_ino = find_inode(dir_ino_nr)) == NULL)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
|
||||||
attr.a_mask = HGFS_ATTR_MODE | HGFS_ATTR_SIZE;
|
attr.a_mask = SFFS_ATTR_MODE | SFFS_ATTR_SIZE;
|
||||||
|
|
||||||
if ((r = verify_inode(cur_ino, path, &attr)) != OK)
|
if ((r = verify_inode(cur_ino, path, &attr)) != OK)
|
||||||
return r;
|
return r;
|
||||||
|
@ -279,7 +279,7 @@ int do_lookup()
|
||||||
if ((r = next_name(&ptr, &last, name)) != OK)
|
if ((r = next_name(&ptr, &last, name)) != OK)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
dprintf(("HGFS: lookup: next name '%s'\n", name));
|
dprintf(("%s: lookup: next name '%s'\n", sffs_name, name));
|
||||||
|
|
||||||
if (!strcmp(name, ".") ||
|
if (!strcmp(name, ".") ||
|
||||||
(cur_ino == root_ino && !strcmp(name, "..")))
|
(cur_ino == root_ino && !strcmp(name, "..")))
|
||||||
|
@ -304,7 +304,7 @@ int do_lookup()
|
||||||
cur_ino = next_ino;
|
cur_ino = next_ino;
|
||||||
}
|
}
|
||||||
|
|
||||||
dprintf(("HGFS: lookup: result %d\n", r));
|
dprintf(("%s: lookup: result %d\n", sffs_name, r));
|
||||||
|
|
||||||
if (r != OK) {
|
if (r != OK) {
|
||||||
put_inode(cur_ino);
|
put_inode(cur_ino);
|
||||||
|
@ -324,8 +324,8 @@ int do_lookup()
|
||||||
m_out.RES_MODE = get_mode(cur_ino, attr.a_mode);
|
m_out.RES_MODE = get_mode(cur_ino, attr.a_mode);
|
||||||
m_out.RES_FILE_SIZE_HI = ex64hi(attr.a_size);
|
m_out.RES_FILE_SIZE_HI = ex64hi(attr.a_size);
|
||||||
m_out.RES_FILE_SIZE_LO = ex64lo(attr.a_size);
|
m_out.RES_FILE_SIZE_LO = ex64lo(attr.a_size);
|
||||||
m_out.RES_UID = opt.uid;
|
m_out.RES_UID = sffs_params->p_uid;
|
||||||
m_out.RES_GID = opt.gid;
|
m_out.RES_GID = sffs_params->p_gid;
|
||||||
m_out.RES_DEV = NO_DEV;
|
m_out.RES_DEV = NO_DEV;
|
||||||
|
|
||||||
return OK;
|
return OK;
|
154
lib/libsffs/main.c
Normal file
154
lib/libsffs/main.c
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
/* This file contains the SFFS initialization code and message loop.
|
||||||
|
*
|
||||||
|
* The entry points into this file are:
|
||||||
|
* sffs_init initialization
|
||||||
|
* sffs_signal signal handler
|
||||||
|
* sffs_loop main message loop
|
||||||
|
*
|
||||||
|
* Created:
|
||||||
|
* April 2009 (D.C. van Moolenbroek)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "inc.h"
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* sffs_init *
|
||||||
|
*===========================================================================*/
|
||||||
|
int sffs_init(char *name, const struct sffs_table *table,
|
||||||
|
struct sffs_params *params)
|
||||||
|
{
|
||||||
|
/* Initialize this file server. Called at startup time.
|
||||||
|
*/
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Make sure that the given path prefix doesn't end with a slash. */
|
||||||
|
i = strlen(params->p_prefix);
|
||||||
|
while (i > 0 && params->p_prefix[i - 1] == '/') i--;
|
||||||
|
params->p_prefix[i] = 0;
|
||||||
|
|
||||||
|
state.s_mounted = FALSE;
|
||||||
|
state.s_signaled = FALSE;
|
||||||
|
|
||||||
|
sffs_name = name;
|
||||||
|
sffs_table = table;
|
||||||
|
sffs_params = params;
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* sffs_signal *
|
||||||
|
*===========================================================================*/
|
||||||
|
void sffs_signal(int signo)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Only check for termination signal, ignore anything else. */
|
||||||
|
if (signo != SIGTERM) return;
|
||||||
|
|
||||||
|
/* We can now terminate if we have also been unmounted. */
|
||||||
|
state.s_signaled = TRUE;
|
||||||
|
|
||||||
|
if (state.s_mounted) {
|
||||||
|
dprintf(("%s: got SIGTERM, still mounted\n", sffs_name));
|
||||||
|
} else {
|
||||||
|
dprintf(("%s: got SIGTERM, shutting down\n", sffs_name));
|
||||||
|
|
||||||
|
/* Break out of the main loop, giving the main program the chance to
|
||||||
|
* perform further cleanup. This causes sef_receive() to return with
|
||||||
|
* an EINTR error code.
|
||||||
|
*/
|
||||||
|
sef_cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* get_work *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int get_work(who_e)
|
||||||
|
endpoint_t *who_e;
|
||||||
|
{
|
||||||
|
/* Receive a request message from VFS. Return TRUE if a new message is ready
|
||||||
|
* to be processed, or FALSE if sef_stop() was called from the signal handler.
|
||||||
|
*/
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if ((r = sef_receive(ANY, &m_in)) != OK) {
|
||||||
|
if (r != EINTR)
|
||||||
|
panic("receive failed: %d", r);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*who_e = m_in.m_source;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* send_reply *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void send_reply(err, transid)
|
||||||
|
int err; /* resulting error code */
|
||||||
|
int transid;
|
||||||
|
{
|
||||||
|
/* Send a reply message to the requesting party, with the given error code.
|
||||||
|
*/
|
||||||
|
int r;
|
||||||
|
|
||||||
|
m_out.m_type = err;
|
||||||
|
if (IS_VFS_FS_TRANSID(transid)) {
|
||||||
|
/* If a transaction ID was set, reset it */
|
||||||
|
m_out.m_type = TRNS_ADD_ID(m_out.m_type, transid);
|
||||||
|
}
|
||||||
|
if ((r = send(m_in.m_source, &m_out)) != OK)
|
||||||
|
printf("%s: send failed (%d)\n", sffs_name, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* sffs_loop *
|
||||||
|
*===========================================================================*/
|
||||||
|
void sffs_loop(void)
|
||||||
|
{
|
||||||
|
/* The main function of this file server. After initializing, loop, receiving
|
||||||
|
* one request from VFS at a time, processing it, and sending a reply back to
|
||||||
|
* VFS. Termination occurs when we both have been unmounted and have received
|
||||||
|
* a termination signal.
|
||||||
|
*/
|
||||||
|
endpoint_t who_e;
|
||||||
|
int call_nr, err, transid;
|
||||||
|
|
||||||
|
while (state.s_mounted || !state.s_signaled) {
|
||||||
|
if (!get_work(&who_e))
|
||||||
|
continue; /* Recheck running conditions */
|
||||||
|
|
||||||
|
transid = TRNS_GET_ID(m_in.m_type);
|
||||||
|
m_in.m_type = TRNS_DEL_ID(m_in.m_type);
|
||||||
|
if (m_in.m_type == 0) {
|
||||||
|
assert(!IS_VFS_FS_TRANSID(transid));
|
||||||
|
m_in.m_type = transid; /* Backwards compat. */
|
||||||
|
transid = 0;
|
||||||
|
} else
|
||||||
|
assert(IS_VFS_FS_TRANSID(transid));
|
||||||
|
|
||||||
|
call_nr = m_in.m_type;
|
||||||
|
if (who_e != VFS_PROC_NR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.s_mounted || call_nr == REQ_READSUPER) {
|
||||||
|
call_nr -= VFS_BASE;
|
||||||
|
|
||||||
|
dprintf(("%s: call %d\n", sffs_name, call_nr));
|
||||||
|
|
||||||
|
if (call_nr >= 0 && call_nr < NREQS) {
|
||||||
|
err = (*call_vec[call_nr])();
|
||||||
|
} else {
|
||||||
|
err = ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf(("%s: call %d result %d\n", sffs_name, call_nr, err));
|
||||||
|
}
|
||||||
|
else err = EINVAL;
|
||||||
|
|
||||||
|
send_reply(err, transid);
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,7 +52,7 @@ int do_statvfs()
|
||||||
if ((r = verify_inode(ino, path, NULL)) != OK)
|
if ((r = verify_inode(ino, path, NULL)) != OK)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if ((r = hgfs_queryvol(path, &free, &total)) != OK)
|
if ((r = sffs_table->t_queryvol(path, &free, &total)) != OK)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
memset(&statvfs, 0, sizeof(statvfs));
|
memset(&statvfs, 0, sizeof(statvfs));
|
||||||
|
@ -68,8 +68,8 @@ int do_statvfs()
|
||||||
statvfs.f_files = 0;
|
statvfs.f_files = 0;
|
||||||
statvfs.f_ffree = 0;
|
statvfs.f_ffree = 0;
|
||||||
statvfs.f_favail = 0;
|
statvfs.f_favail = 0;
|
||||||
statvfs.f_fsid = state.dev;
|
statvfs.f_fsid = state.s_dev;
|
||||||
statvfs.f_flag = state.read_only ? ST_RDONLY : 0;
|
statvfs.f_flag = state.s_read_only ? ST_RDONLY : 0;
|
||||||
statvfs.f_flag |= ST_NOTRUNC;
|
statvfs.f_flag |= ST_NOTRUNC;
|
||||||
statvfs.f_namemax = NAME_MAX;
|
statvfs.f_namemax = NAME_MAX;
|
||||||
|
|
|
@ -19,35 +19,38 @@ int do_readsuper()
|
||||||
*/
|
*/
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
struct inode *ino;
|
struct inode *ino;
|
||||||
struct hgfs_attr attr;
|
struct sffs_attr attr;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
dprintf(("HGFS: readsuper (dev %x, flags %x)\n",
|
dprintf(("%s: readsuper (dev %x, flags %x)\n",
|
||||||
(dev_t) m_in.REQ_DEV, m_in.REQ_FLAGS));
|
sffs_name, (dev_t) m_in.REQ_DEV, m_in.REQ_FLAGS));
|
||||||
|
|
||||||
if (m_in.REQ_FLAGS & REQ_ISROOT) {
|
if (m_in.REQ_FLAGS & REQ_ISROOT) {
|
||||||
printf("HGFS: attempt to mount as root device\n");
|
printf("%s: attempt to mount as root device\n", sffs_name);
|
||||||
|
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.read_only = !!(m_in.REQ_FLAGS & REQ_RDONLY);
|
state.s_read_only = !!(m_in.REQ_FLAGS & REQ_RDONLY);
|
||||||
state.dev = m_in.REQ_DEV;
|
state.s_dev = m_in.REQ_DEV;
|
||||||
|
|
||||||
init_dentry();
|
init_dentry();
|
||||||
ino = init_inode();
|
ino = init_inode();
|
||||||
|
|
||||||
attr.a_mask = HGFS_ATTR_MODE | HGFS_ATTR_SIZE;
|
attr.a_mask = SFFS_ATTR_MODE | SFFS_ATTR_SIZE;
|
||||||
|
|
||||||
/* We cannot continue if we fail to get the properties of the root inode at
|
/* We cannot continue if we fail to get the properties of the root inode at
|
||||||
* all, because we cannot guess the details of the root node to return to
|
* all, because we cannot guess the details of the root node to return to
|
||||||
* VFS. Print a (hopefully) helpful error message, and abort the mount.
|
* VFS. Print a (hopefully) helpful error message, and abort the mount.
|
||||||
*/
|
*/
|
||||||
if ((r = verify_inode(ino, path, &attr)) != OK) {
|
if ((r = verify_inode(ino, path, &attr)) != OK) {
|
||||||
if (opt.prefix[0] && (r == ENOENT || r == EACCES))
|
if (r == EAGAIN)
|
||||||
printf("HGFS: unable to access the given prefix directory\n");
|
printf("%s: shared folders disabled\n", sffs_name);
|
||||||
|
else if (sffs_params->p_prefix[0] && (r == ENOENT || r == EACCES))
|
||||||
|
printf("%s: unable to access the given prefix directory\n",
|
||||||
|
sffs_name);
|
||||||
else
|
else
|
||||||
printf("HGFS: unable to access shared folders\n");
|
printf("%s: unable to access shared folders\n", sffs_name);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -56,13 +59,12 @@ int do_readsuper()
|
||||||
m_out.RES_MODE = get_mode(ino, attr.a_mode);
|
m_out.RES_MODE = get_mode(ino, attr.a_mode);
|
||||||
m_out.RES_FILE_SIZE_HI = ex64hi(attr.a_size);
|
m_out.RES_FILE_SIZE_HI = ex64hi(attr.a_size);
|
||||||
m_out.RES_FILE_SIZE_LO = ex64lo(attr.a_size);
|
m_out.RES_FILE_SIZE_LO = ex64lo(attr.a_size);
|
||||||
m_out.RES_UID = opt.uid;
|
m_out.RES_UID = sffs_params->p_uid;
|
||||||
m_out.RES_GID = opt.gid;
|
m_out.RES_GID = sffs_params->p_gid;
|
||||||
m_out.RES_DEV = NO_DEV;
|
m_out.RES_DEV = NO_DEV;
|
||||||
|
|
||||||
m_out.RES_CONREQS = 1; /* We can handle only 1 request at a time */
|
m_out.RES_CONREQS = 1; /* We can handle only 1 request at a time */
|
||||||
|
|
||||||
state.mounted = TRUE;
|
state.s_mounted = TRUE;
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
@ -76,7 +78,7 @@ int do_unmount()
|
||||||
*/
|
*/
|
||||||
struct inode *ino;
|
struct inode *ino;
|
||||||
|
|
||||||
dprintf(("HGFS: do_unmount\n"));
|
dprintf(("%s: do_unmount\n", sffs_name));
|
||||||
|
|
||||||
/* Decrease the reference count of the root inode. */
|
/* Decrease the reference count of the root inode. */
|
||||||
if ((ino = find_inode(ROOT_INODE_NR)) == NULL)
|
if ((ino = find_inode(ROOT_INODE_NR)) == NULL)
|
||||||
|
@ -86,9 +88,9 @@ int do_unmount()
|
||||||
|
|
||||||
/* There should not be any referenced inodes anymore now. */
|
/* There should not be any referenced inodes anymore now. */
|
||||||
if (have_used_inode())
|
if (have_used_inode())
|
||||||
printf("HGFS: in-use inodes left at unmount time!\n");
|
printf("%s: in-use inodes left at unmount time!\n", sffs_name);
|
||||||
|
|
||||||
state.mounted = FALSE;
|
state.s_mounted = FALSE;
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
|
@ -28,7 +28,7 @@ char *src;
|
||||||
|
|
||||||
assert(size <= NAME_MAX+1);
|
assert(size <= NAME_MAX+1);
|
||||||
|
|
||||||
if (opt.case_insens) {
|
if (sffs_params->p_case_insens) {
|
||||||
for (i = 0; i < size; i++)
|
for (i = 0; i < size; i++)
|
||||||
*dst++ = tolower(*src++);
|
*dst++ = tolower(*src++);
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ char *name2;
|
||||||
*/
|
*/
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (opt.case_insens)
|
if (sffs_params->p_case_insens)
|
||||||
r = strcasecmp(name1, name2);
|
r = strcasecmp(name1, name2);
|
||||||
else
|
else
|
||||||
r = strcmp(name1, name2);
|
r = strcmp(name1, name2);
|
|
@ -26,10 +26,11 @@ struct inode *ino;
|
||||||
p = &buf[sizeof(buf) - 1];
|
p = &buf[sizeof(buf) - 1];
|
||||||
p[0] = 0;
|
p[0] = 0;
|
||||||
|
|
||||||
dprintf(("HGFS: make_path: constructing path for inode %d\n", ino->i_num));
|
dprintf(("%s: make_path: constructing path for inode %d\n",
|
||||||
|
sffs_name, ino->i_num));
|
||||||
|
|
||||||
/* Get the length of the prefix, skipping any leading slashes. */
|
/* Get the length of the prefix, skipping any leading slashes. */
|
||||||
for (prefix = opt.prefix; prefix[0] == '/'; prefix++);
|
for (prefix = sffs_params->p_prefix; prefix[0] == '/'; prefix++);
|
||||||
plen = strlen(prefix);
|
plen = strlen(prefix);
|
||||||
|
|
||||||
/* Construct the path right-to-left in a temporary buffer first. */
|
/* Construct the path right-to-left in a temporary buffer first. */
|
||||||
|
@ -60,7 +61,7 @@ struct inode *ino;
|
||||||
strcpy(path, prefix);
|
strcpy(path, prefix);
|
||||||
strcpy(&path[plen], p);
|
strcpy(&path[plen], p);
|
||||||
|
|
||||||
dprintf(("HGFS: make_path: resulting path is '%s'\n", path));
|
dprintf(("%s: make_path: resulting path is '%s'\n", sffs_name, path));
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
#ifndef _SFFS_PROTO_H
|
||||||
|
#define _SFFS_PROTO_H
|
||||||
|
|
||||||
/* dentry.c */
|
/* dentry.c */
|
||||||
void init_dentry(void);
|
void init_dentry(void);
|
||||||
|
@ -67,13 +69,15 @@ int do_noop(void);
|
||||||
int no_sys(void);
|
int no_sys(void);
|
||||||
|
|
||||||
/* verify.c */
|
/* verify.c */
|
||||||
int verify_path(char *path, struct inode *ino, struct hgfs_attr *attr,
|
int verify_path(char *path, struct inode *ino, struct sffs_attr *attr,
|
||||||
int *stale);
|
int *stale);
|
||||||
int verify_inode(struct inode *ino, char path[PATH_MAX], struct
|
int verify_inode(struct inode *ino, char path[PATH_MAX],
|
||||||
hgfs_attr *attr);
|
struct sffs_attr *attr);
|
||||||
int verify_dentry(struct inode *parent, char name[NAME_MAX+1], char
|
int verify_dentry(struct inode *parent, char name[NAME_MAX+1],
|
||||||
path[PATH_MAX], struct inode **res_ino);
|
char path[PATH_MAX], struct inode **res_ino);
|
||||||
|
|
||||||
/* write.c */
|
/* write.c */
|
||||||
int do_write(void);
|
int do_write(void);
|
||||||
int do_ftrunc(void);
|
int do_ftrunc(void);
|
||||||
|
|
||||||
|
#endif /* _SFFS_PROTO_H */
|
|
@ -41,14 +41,14 @@ int do_read()
|
||||||
|
|
||||||
assert(count > 0);
|
assert(count > 0);
|
||||||
|
|
||||||
/* Use the buffer from libhgfs to eliminate extra copying. */
|
/* Use the buffer from below to eliminate extra copying. */
|
||||||
size = hgfs_readbuf(&ptr);
|
size = sffs_table->t_readbuf(&ptr);
|
||||||
off = 0;
|
off = 0;
|
||||||
|
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
chunk = MIN(count, size);
|
chunk = MIN(count, size);
|
||||||
|
|
||||||
if ((r = hgfs_read(ino->i_file, ptr, chunk, pos)) <= 0)
|
if ((r = sffs_table->t_read(ino->i_file, ptr, chunk, pos)) <= 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
chunk = r;
|
chunk = r;
|
||||||
|
@ -84,14 +84,14 @@ int do_getdents()
|
||||||
char name[NAME_MAX+1];
|
char name[NAME_MAX+1];
|
||||||
struct inode *ino, *child;
|
struct inode *ino, *child;
|
||||||
struct dirent *dent;
|
struct dirent *dent;
|
||||||
struct hgfs_attr attr;
|
struct sffs_attr attr;
|
||||||
size_t len, off, user_off, user_left;
|
size_t len, off, user_off, user_left;
|
||||||
off_t pos;
|
off_t pos;
|
||||||
int r;
|
int r;
|
||||||
/* must be at least sizeof(struct dirent) + NAME_MAX */
|
/* must be at least sizeof(struct dirent) + NAME_MAX */
|
||||||
static char buf[BLOCK_SIZE];
|
static char buf[BLOCK_SIZE];
|
||||||
|
|
||||||
attr.a_mask = HGFS_ATTR_MODE;
|
attr.a_mask = SFFS_ATTR_MODE;
|
||||||
|
|
||||||
if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL)
|
if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
@ -141,8 +141,8 @@ int do_getdents()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Any other entry, not being "." or "..". */
|
/* Any other entry, not being "." or "..". */
|
||||||
r = hgfs_readdir(ino->i_dir, pos - 2, name, sizeof(name),
|
r = sffs_table->t_readdir(ino->i_dir, pos - 2, name,
|
||||||
&attr);
|
sizeof(name), &attr);
|
||||||
|
|
||||||
if (r != OK) {
|
if (r != OK) {
|
||||||
/* No more entries? Then close the handle and stop. */
|
/* No more entries? Then close the handle and stop. */
|
|
@ -26,11 +26,11 @@ int mode;
|
||||||
mode = mode | (mode >> 3) | (mode >> 6);
|
mode = mode | (mode >> 3) | (mode >> 6);
|
||||||
|
|
||||||
if (IS_DIR(ino))
|
if (IS_DIR(ino))
|
||||||
mode = S_IFDIR | (mode & opt.dir_mask);
|
mode = S_IFDIR | (mode & sffs_params->p_dir_mask);
|
||||||
else
|
else
|
||||||
mode = S_IFREG | (mode & opt.file_mask);
|
mode = S_IFREG | (mode & sffs_params->p_file_mask);
|
||||||
|
|
||||||
if (state.read_only)
|
if (state.s_read_only)
|
||||||
mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
|
mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
|
||||||
|
|
||||||
return mode;
|
return mode;
|
||||||
|
@ -44,7 +44,7 @@ int do_stat()
|
||||||
/* Retrieve inode status.
|
/* Retrieve inode status.
|
||||||
*/
|
*/
|
||||||
struct inode *ino;
|
struct inode *ino;
|
||||||
struct hgfs_attr attr;
|
struct sffs_attr attr;
|
||||||
struct stat stat;
|
struct stat stat;
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
ino_t ino_nr;
|
ino_t ino_nr;
|
||||||
|
@ -56,19 +56,19 @@ int do_stat()
|
||||||
if ((ino = find_inode(ino_nr)) == NULL)
|
if ((ino = find_inode(ino_nr)) == NULL)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
|
||||||
attr.a_mask = HGFS_ATTR_MODE | HGFS_ATTR_SIZE | HGFS_ATTR_CRTIME |
|
attr.a_mask = SFFS_ATTR_MODE | SFFS_ATTR_SIZE | SFFS_ATTR_CRTIME |
|
||||||
HGFS_ATTR_ATIME | HGFS_ATTR_MTIME | HGFS_ATTR_CTIME;
|
SFFS_ATTR_ATIME | SFFS_ATTR_MTIME | SFFS_ATTR_CTIME;
|
||||||
|
|
||||||
if ((r = verify_inode(ino, path, &attr)) != OK)
|
if ((r = verify_inode(ino, path, &attr)) != OK)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
memset(&stat, 0, sizeof(struct stat));
|
memset(&stat, 0, sizeof(struct stat));
|
||||||
|
|
||||||
stat.st_dev = state.dev;
|
stat.st_dev = state.s_dev;
|
||||||
stat.st_ino = ino_nr;
|
stat.st_ino = ino_nr;
|
||||||
stat.st_mode = get_mode(ino, attr.a_mode);
|
stat.st_mode = get_mode(ino, attr.a_mode);
|
||||||
stat.st_uid = opt.uid;
|
stat.st_uid = sffs_params->p_uid;
|
||||||
stat.st_gid = opt.gid;
|
stat.st_gid = sffs_params->p_gid;
|
||||||
stat.st_rdev = NO_DEV;
|
stat.st_rdev = NO_DEV;
|
||||||
if (cmp64u(attr.a_size, LONG_MAX) > 0)
|
if (cmp64u(attr.a_size, LONG_MAX) > 0)
|
||||||
stat.st_size = LONG_MAX;
|
stat.st_size = LONG_MAX;
|
||||||
|
@ -109,10 +109,10 @@ int do_chmod()
|
||||||
*/
|
*/
|
||||||
struct inode *ino;
|
struct inode *ino;
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
struct hgfs_attr attr;
|
struct sffs_attr attr;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (state.read_only)
|
if (state.s_read_only)
|
||||||
return EROFS;
|
return EROFS;
|
||||||
|
|
||||||
if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL)
|
if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL)
|
||||||
|
@ -122,10 +122,10 @@ int do_chmod()
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
/* Set the new file mode. */
|
/* Set the new file mode. */
|
||||||
attr.a_mask = HGFS_ATTR_MODE;
|
attr.a_mask = SFFS_ATTR_MODE;
|
||||||
attr.a_mode = m_in.REQ_MODE; /* no need to convert in this direction */
|
attr.a_mode = m_in.REQ_MODE; /* no need to convert in this direction */
|
||||||
|
|
||||||
if ((r = hgfs_setattr(path, &attr)) != OK)
|
if ((r = sffs_table->t_setattr(path, &attr)) != OK)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
/* We have no idea what really happened. Query for the mode again. */
|
/* We have no idea what really happened. Query for the mode again. */
|
||||||
|
@ -146,10 +146,10 @@ int do_utime()
|
||||||
*/
|
*/
|
||||||
struct inode *ino;
|
struct inode *ino;
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
struct hgfs_attr attr;
|
struct sffs_attr attr;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (state.read_only)
|
if (state.s_read_only)
|
||||||
return EROFS;
|
return EROFS;
|
||||||
|
|
||||||
if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL)
|
if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL)
|
||||||
|
@ -158,11 +158,11 @@ int do_utime()
|
||||||
if ((r = verify_inode(ino, path, NULL)) != OK)
|
if ((r = verify_inode(ino, path, NULL)) != OK)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
attr.a_mask = HGFS_ATTR_ATIME | HGFS_ATTR_MTIME;
|
attr.a_mask = SFFS_ATTR_ATIME | SFFS_ATTR_MTIME;
|
||||||
attr.a_atime.tv_sec = m_in.REQ_ACTIME;
|
attr.a_atime.tv_sec = m_in.REQ_ACTIME;
|
||||||
attr.a_atime.tv_nsec = 0;
|
attr.a_atime.tv_nsec = 0;
|
||||||
attr.a_mtime.tv_sec = m_in.REQ_MODTIME;
|
attr.a_mtime.tv_sec = m_in.REQ_MODTIME;
|
||||||
attr.a_mtime.tv_nsec = 0;
|
attr.a_mtime.tv_nsec = 0;
|
||||||
|
|
||||||
return hgfs_setattr(path, &attr);
|
return sffs_table->t_setattr(path, &attr);
|
||||||
}
|
}
|
13
lib/libsffs/type.h
Normal file
13
lib/libsffs/type.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef _SFFS_TYPE_H
|
||||||
|
#define _SFFS_TYPE_H
|
||||||
|
|
||||||
|
/* Structure with global file system state. */
|
||||||
|
struct state {
|
||||||
|
int s_mounted; /* is the file system mounted? */
|
||||||
|
int s_signaled; /* have we received a SIGTERM? */
|
||||||
|
int s_read_only; /* is the file system mounted read-only? note,
|
||||||
|
* has no relation to the shared folder mode */
|
||||||
|
dev_t s_dev; /* device the file system is mounted on */
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _SFFS_TYPE_H */
|
|
@ -32,7 +32,7 @@ char name[NAME_MAX+1]; /* buffer in which store the result */
|
||||||
if (r != OK) return r;
|
if (r != OK) return r;
|
||||||
|
|
||||||
if (name[len-1] != 0) {
|
if (name[len-1] != 0) {
|
||||||
printf("HGFS: VFS did not zero-terminate path component!\n");
|
printf("%s: VFS did not zero-terminate path component!\n", sffs_name);
|
||||||
|
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
|
@ -17,7 +17,7 @@
|
||||||
int verify_path(path, ino, attr, stale)
|
int verify_path(path, ino, attr, stale)
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
struct inode *ino;
|
struct inode *ino;
|
||||||
struct hgfs_attr *attr;
|
struct sffs_attr *attr;
|
||||||
int *stale;
|
int *stale;
|
||||||
{
|
{
|
||||||
/* Given a path, and the inode associated with that path, verify if the inode
|
/* Given a path, and the inode associated with that path, verify if the inode
|
||||||
|
@ -32,11 +32,12 @@ int *stale;
|
||||||
*/
|
*/
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
attr->a_mask |= HGFS_ATTR_MODE;
|
attr->a_mask |= SFFS_ATTR_MODE;
|
||||||
|
|
||||||
r = hgfs_getattr(path, attr);
|
r = sffs_table->t_getattr(path, attr);
|
||||||
|
|
||||||
dprintf(("HGFS: verify_path: getattr('%s') returned %d\n", path, r));
|
dprintf(("%s: verify_path: getattr('%s') returned %d\n",
|
||||||
|
sffs_name, path, r));
|
||||||
|
|
||||||
if (r != OK) {
|
if (r != OK) {
|
||||||
/* If we are told that the path does not exist, delete the inode */
|
/* If we are told that the path does not exist, delete the inode */
|
||||||
|
@ -63,14 +64,14 @@ int *stale;
|
||||||
int verify_inode(ino, path, attr)
|
int verify_inode(ino, path, attr)
|
||||||
struct inode *ino; /* inode to verify */
|
struct inode *ino; /* inode to verify */
|
||||||
char path[PATH_MAX]; /* buffer in which to store the path */
|
char path[PATH_MAX]; /* buffer in which to store the path */
|
||||||
struct hgfs_attr *attr; /* buffer for attributes, or NULL */
|
struct sffs_attr *attr; /* buffer for attributes, or NULL */
|
||||||
{
|
{
|
||||||
/* Given an inode, construct a path identifying the inode, and check whether
|
/* Given an inode, construct a path identifying the inode, and check whether
|
||||||
* that path is still valid for that inode (as far as we can tell). As a side
|
* that path is still valid for that inode (as far as we can tell). As a side
|
||||||
* effect, store attributes in the given attribute structure if not NULL (its
|
* effect, store attributes in the given attribute structure if not NULL (its
|
||||||
* a_mask member must then be set).
|
* a_mask member must then be set).
|
||||||
*/
|
*/
|
||||||
struct hgfs_attr attr2;
|
struct sffs_attr attr2;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if ((r = make_path(path, ino)) != OK) return r;
|
if ((r = make_path(path, ino)) != OK) return r;
|
||||||
|
@ -104,13 +105,13 @@ struct inode **res_ino; /* pointer for addressed inode (or NULL) */
|
||||||
if ((r = verify_inode(parent, path, NULL)) != OK)
|
if ((r = verify_inode(parent, path, NULL)) != OK)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
dprintf(("HGFS: verify_dentry: given path is '%s', name '%s'\n", path,
|
dprintf(("%s: verify_dentry: given path is '%s', name '%s'\n",
|
||||||
name));
|
sffs_name, path, name));
|
||||||
|
|
||||||
if ((r = push_path(path, name)) != OK)
|
if ((r = push_path(path, name)) != OK)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
dprintf(("HGFS: verify_dentry: path now '%s'\n", path));
|
dprintf(("%s: verify_dentry: path now '%s'\n", sffs_name, path));
|
||||||
|
|
||||||
*res_ino = lookup_dentry(parent, name);
|
*res_ino = lookup_dentry(parent, name);
|
||||||
|
|
|
@ -41,8 +41,8 @@ cp_grant_id_t *grantp;
|
||||||
|
|
||||||
assert(count > 0);
|
assert(count > 0);
|
||||||
|
|
||||||
/* Use the buffer from libhgfs to eliminate extra copying. */
|
/* Use the buffer from below to eliminate extra copying. */
|
||||||
size = hgfs_writebuf(&ptr);
|
size = sffs_table->t_writebuf(&ptr);
|
||||||
off = 0;
|
off = 0;
|
||||||
|
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
|
@ -59,7 +59,7 @@ cp_grant_id_t *grantp;
|
||||||
memset(ptr, 0, chunk);
|
memset(ptr, 0, chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((r = hgfs_write(ino->i_file, ptr, chunk, pos)) <= 0)
|
if ((r = sffs_table->t_write(ino->i_file, ptr, chunk, pos)) <= 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
count -= r;
|
count -= r;
|
||||||
|
@ -89,7 +89,7 @@ int do_write()
|
||||||
cp_grant_id_t grant;
|
cp_grant_id_t grant;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (state.read_only)
|
if (state.s_read_only)
|
||||||
return EROFS;
|
return EROFS;
|
||||||
|
|
||||||
if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL)
|
if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL)
|
||||||
|
@ -122,12 +122,12 @@ int do_ftrunc()
|
||||||
*/
|
*/
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
struct inode *ino;
|
struct inode *ino;
|
||||||
struct hgfs_attr attr;
|
struct sffs_attr attr;
|
||||||
u64_t start, end, delta;
|
u64_t start, end, delta;
|
||||||
size_t count;
|
size_t count;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (state.read_only)
|
if (state.s_read_only)
|
||||||
return EROFS;
|
return EROFS;
|
||||||
|
|
||||||
if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL)
|
if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL)
|
||||||
|
@ -143,10 +143,10 @@ int do_ftrunc()
|
||||||
if ((r = verify_inode(ino, path, NULL)) != OK)
|
if ((r = verify_inode(ino, path, NULL)) != OK)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
attr.a_mask = HGFS_ATTR_SIZE;
|
attr.a_mask = SFFS_ATTR_SIZE;
|
||||||
attr.a_size = start;
|
attr.a_size = start;
|
||||||
|
|
||||||
r = hgfs_setattr(path, &attr);
|
r = sffs_table->t_setattr(path, &attr);
|
||||||
} else {
|
} else {
|
||||||
/* Write zeroes to the file. We can't create holes. */
|
/* Write zeroes to the file. We can't create holes. */
|
||||||
if (cmp64(end, start) <= 0) return EINVAL;
|
if (cmp64(end, start) <= 0) return EINVAL;
|
|
@ -1,11 +1,9 @@
|
||||||
# Makefile for VMware Host/Guest File System (HGFS) server
|
# Makefile for VMware Host/Guest File System (HGFS) server
|
||||||
PROG= hgfs
|
PROG= hgfs
|
||||||
SRCS= dentry.c handle.c inode.c link.c lookup.c main.c \
|
SRCS= hgfs.c
|
||||||
misc.c mount.c name.c path.c read.c stat.c table.c \
|
|
||||||
util.c verify.c write.c
|
|
||||||
|
|
||||||
DPADD+= ${LIBHGFS} ${LIBSYS}
|
DPADD+= ${LIBSFFS} ${LIBHGFS} ${LIBSYS}
|
||||||
LDADD+= -lhgfs -lsys
|
LDADD+= -lsffs -lhgfs -lsys
|
||||||
|
|
||||||
MAN=
|
MAN=
|
||||||
|
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
|
|
||||||
#ifdef _TABLE
|
|
||||||
#undef EXTERN
|
|
||||||
#define EXTERN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
EXTERN message m_in; /* request message */
|
|
||||||
EXTERN message m_out; /* reply message */
|
|
||||||
EXTERN struct state state; /* global state */
|
|
||||||
EXTERN struct opt opt; /* global options */
|
|
||||||
|
|
||||||
extern int(*call_vec[]) (void);
|
|
106
servers/hgfs/hgfs.c
Normal file
106
servers/hgfs/hgfs.c
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
/* This file contains the implementation of the HGFS file system server.
|
||||||
|
* The file system side is handled by libsffs, whereas the host communication
|
||||||
|
* is handled by libhgfs. This file mainly contains the glue between them.
|
||||||
|
*
|
||||||
|
* The entry points into this file are:
|
||||||
|
* main main program function
|
||||||
|
*
|
||||||
|
* Created:
|
||||||
|
* April 2009 (D.C. van Moolenbroek)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <minix/drivers.h>
|
||||||
|
#include <minix/sffs.h>
|
||||||
|
#include <minix/hgfs.h>
|
||||||
|
#include <minix/optset.h>
|
||||||
|
|
||||||
|
static struct sffs_params params;
|
||||||
|
|
||||||
|
static struct optset optset_table[] = {
|
||||||
|
{ "prefix", OPT_STRING, params.p_prefix, sizeof(params.p_prefix) },
|
||||||
|
{ "uid", OPT_INT, ¶ms.p_uid, 10 },
|
||||||
|
{ "gid", OPT_INT, ¶ms.p_gid, 10 },
|
||||||
|
{ "fmask", OPT_INT, ¶ms.p_file_mask, 8 },
|
||||||
|
{ "dmask", OPT_INT, ¶ms.p_dir_mask, 8 },
|
||||||
|
{ "icase", OPT_BOOL, ¶ms.p_case_insens, TRUE },
|
||||||
|
{ "noicase", OPT_BOOL, ¶ms.p_case_insens, FALSE },
|
||||||
|
{ NULL, 0, NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* sef_cb_init_fresh *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
|
||||||
|
{
|
||||||
|
/* Initialize this file server. Called at startup time.
|
||||||
|
*/
|
||||||
|
const struct sffs_table *table;
|
||||||
|
int i, r;
|
||||||
|
|
||||||
|
/* Defaults */
|
||||||
|
params.p_prefix[0] = 0;
|
||||||
|
params.p_uid = 0;
|
||||||
|
params.p_gid = 0;
|
||||||
|
params.p_file_mask = 0755;
|
||||||
|
params.p_dir_mask = 0755;
|
||||||
|
params.p_case_insens = FALSE;
|
||||||
|
|
||||||
|
/* If we have been given an options string, parse options from there. */
|
||||||
|
for (i = 1; i < env_argc - 1; i++)
|
||||||
|
if (!strcmp(env_argv[i], "-o"))
|
||||||
|
optset_parse(optset_table, env_argv[++i]);
|
||||||
|
|
||||||
|
/* Initialize the HGFS library. If this fails, exit immediately. */
|
||||||
|
if ((r = hgfs_init(&table)) != OK) {
|
||||||
|
if (r == EAGAIN)
|
||||||
|
printf("HGFS: shared folders are disabled\n");
|
||||||
|
else
|
||||||
|
printf("HGFS: unable to initialize HGFS library (%d)\n", r);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now initialize the SFFS library. */
|
||||||
|
if ((r = sffs_init("HGFS", table, ¶ms)) != OK) {
|
||||||
|
hgfs_cleanup();
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* sef_local_startup *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void sef_local_startup(void)
|
||||||
|
{
|
||||||
|
/* Local SEF initialization.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Register init callback. */
|
||||||
|
sef_setcb_init_fresh(sef_cb_init_fresh);
|
||||||
|
|
||||||
|
/* Register signal callback. SFFS handles this. */
|
||||||
|
sef_setcb_signal_handler(sffs_signal);
|
||||||
|
|
||||||
|
sef_startup();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* main *
|
||||||
|
*===========================================================================*/
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
/* The main function of this file server.
|
||||||
|
*/
|
||||||
|
|
||||||
|
env_setargs(argc, argv);
|
||||||
|
sef_local_startup();
|
||||||
|
|
||||||
|
sffs_loop();
|
||||||
|
|
||||||
|
hgfs_cleanup();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -1,39 +0,0 @@
|
||||||
|
|
||||||
#define _POSIX_SOURCE 1 /* for signal handling */
|
|
||||||
#define _SYSTEM 1 /* for negative error values */
|
|
||||||
#define _MINIX 1
|
|
||||||
|
|
||||||
#include <minix/config.h>
|
|
||||||
#include <minix/const.h>
|
|
||||||
#include <minix/type.h>
|
|
||||||
#include <minix/ipc.h>
|
|
||||||
#include <minix/com.h>
|
|
||||||
#include <minix/callnr.h>
|
|
||||||
#include <minix/safecopies.h>
|
|
||||||
#include <minix/vfsif.h>
|
|
||||||
#include <minix/syslib.h>
|
|
||||||
#include <minix/sysutil.h>
|
|
||||||
#include <minix/optset.h>
|
|
||||||
#include <sys/param.h>
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
#define dprintf(x) printf x
|
|
||||||
#else
|
|
||||||
#define dprintf(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/queue.h>
|
|
||||||
|
|
||||||
#include <minix/hgfs.h>
|
|
||||||
|
|
||||||
#include "type.h"
|
|
||||||
#include "const.h"
|
|
||||||
#include "proto.h"
|
|
||||||
#include "glo.h"
|
|
||||||
|
|
||||||
#include "inode.h"
|
|
|
@ -1,204 +0,0 @@
|
||||||
/* This file contains the main message loop of the HGFS file system server.
|
|
||||||
*
|
|
||||||
* The entry points into this file are:
|
|
||||||
* main main program function
|
|
||||||
*
|
|
||||||
* Created:
|
|
||||||
* April 2009 (D.C. van Moolenbroek)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "inc.h"
|
|
||||||
|
|
||||||
#include <signal.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
static void get_work(endpoint_t *who_e);
|
|
||||||
static void send_reply(int err, int transid);
|
|
||||||
|
|
||||||
static struct optset optset_table[] = {
|
|
||||||
{ "prefix", OPT_STRING, opt.prefix, sizeof(opt.prefix) },
|
|
||||||
{ "uid", OPT_INT, &opt.uid, 10 },
|
|
||||||
{ "gid", OPT_INT, &opt.gid, 10 },
|
|
||||||
{ "fmask", OPT_INT, &opt.file_mask, 8 },
|
|
||||||
{ "dmask", OPT_INT, &opt.dir_mask, 8 },
|
|
||||||
{ "icase", OPT_BOOL, &opt.case_insens, TRUE },
|
|
||||||
{ "noicase", OPT_BOOL, &opt.case_insens, FALSE },
|
|
||||||
{ NULL, 0, NULL, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
/* SEF functions and variables. */
|
|
||||||
static void sef_local_startup(void);
|
|
||||||
static int sef_cb_init_fresh(int type, sef_init_info_t *info);
|
|
||||||
static void sef_cb_signal_handler(int signo);
|
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* sef_cb_init_fresh *
|
|
||||||
*===========================================================================*/
|
|
||||||
static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
|
|
||||||
{
|
|
||||||
/* Initialize this file server. Called at startup time.
|
|
||||||
*/
|
|
||||||
int i, r;
|
|
||||||
|
|
||||||
/* Defaults */
|
|
||||||
opt.prefix[0] = 0;
|
|
||||||
opt.uid = 0;
|
|
||||||
opt.gid = 0;
|
|
||||||
opt.file_mask = 0755;
|
|
||||||
opt.dir_mask = 0755;
|
|
||||||
opt.case_insens = FALSE;
|
|
||||||
|
|
||||||
/* If we have been given an options string, parse options from there. */
|
|
||||||
for (i = 1; i < env_argc - 1; i++)
|
|
||||||
if (!strcmp(env_argv[i], "-o"))
|
|
||||||
optset_parse(optset_table, env_argv[++i]);
|
|
||||||
|
|
||||||
/* Make sure that the given path prefix doesn't end with a slash. */
|
|
||||||
for (i = strlen(opt.prefix); i > 0 && opt.prefix[i - 1] == '/'; i--);
|
|
||||||
opt.prefix[i] = 0;
|
|
||||||
|
|
||||||
/* Initialize the HGFS library. If this fails, exit immediately. */
|
|
||||||
r = hgfs_init();
|
|
||||||
if (r != OK) {
|
|
||||||
if (r == EAGAIN)
|
|
||||||
printf("HGFS: shared folders are disabled\n");
|
|
||||||
else
|
|
||||||
printf("HGFS: unable to initialize HGFS library (%d)\n", r);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.mounted = FALSE;
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* sef_cb_signal_handler *
|
|
||||||
*===========================================================================*/
|
|
||||||
static void sef_cb_signal_handler(int signo)
|
|
||||||
{
|
|
||||||
/* Only check for termination signal, ignore anything else. */
|
|
||||||
if (signo != SIGTERM) return;
|
|
||||||
|
|
||||||
if (state.mounted) {
|
|
||||||
dprintf(("HGFS: got SIGTERM, still mounted\n"));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
dprintf(("HGFS: got SIGTERM, shutting down\n"));
|
|
||||||
|
|
||||||
/* Pass on the cleanup request to the HGFS library. */
|
|
||||||
hgfs_cleanup();
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* sef_local_startup *
|
|
||||||
*===========================================================================*/
|
|
||||||
static void sef_local_startup(void)
|
|
||||||
{
|
|
||||||
/* Register init callbacks. */
|
|
||||||
sef_setcb_init_fresh(sef_cb_init_fresh);
|
|
||||||
sef_setcb_init_restart(sef_cb_init_fresh);
|
|
||||||
|
|
||||||
/* No live update support yet. */
|
|
||||||
|
|
||||||
/* Register signal callbacks. */
|
|
||||||
sef_setcb_signal_handler(sef_cb_signal_handler);
|
|
||||||
|
|
||||||
sef_startup();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* main *
|
|
||||||
*===========================================================================*/
|
|
||||||
int main(argc, argv)
|
|
||||||
int argc;
|
|
||||||
char *argv[];
|
|
||||||
{
|
|
||||||
/* The main function of this file server. After initializing, loop forever
|
|
||||||
* receiving one request from VFS at a time, processing it, and sending a
|
|
||||||
* reply back to VFS.
|
|
||||||
*/
|
|
||||||
endpoint_t who_e;
|
|
||||||
int call_nr, err, transid;
|
|
||||||
|
|
||||||
env_setargs(argc, argv);
|
|
||||||
sef_local_startup();
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
get_work(&who_e);
|
|
||||||
|
|
||||||
transid = TRNS_GET_ID(m_in.m_type);
|
|
||||||
m_in.m_type = TRNS_DEL_ID(m_in.m_type);
|
|
||||||
if (m_in.m_type == 0) {
|
|
||||||
assert(!IS_VFS_FS_TRANSID(transid));
|
|
||||||
m_in.m_type = transid; /* Backwards compat. */
|
|
||||||
transid = 0;
|
|
||||||
} else
|
|
||||||
assert(IS_VFS_FS_TRANSID(transid));
|
|
||||||
|
|
||||||
call_nr = m_in.m_type;
|
|
||||||
if (who_e != VFS_PROC_NR) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.mounted || call_nr == REQ_READSUPER) {
|
|
||||||
call_nr -= VFS_BASE;
|
|
||||||
|
|
||||||
dprintf(("HGFS: call %d\n", call_nr));
|
|
||||||
|
|
||||||
if (call_nr >= 0 && call_nr < NREQS) {
|
|
||||||
err = (*call_vec[call_nr])();
|
|
||||||
} else {
|
|
||||||
err = ENOSYS;
|
|
||||||
}
|
|
||||||
|
|
||||||
dprintf(("HGFS: call %d result %d\n", call_nr, err));
|
|
||||||
}
|
|
||||||
else err = EINVAL;
|
|
||||||
|
|
||||||
send_reply(err, transid);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* get_work *
|
|
||||||
*===========================================================================*/
|
|
||||||
static void get_work(who_e)
|
|
||||||
endpoint_t *who_e;
|
|
||||||
{
|
|
||||||
/* Receive a request message from VFS. Return the request call number.
|
|
||||||
*/
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if ((r = sef_receive(ANY, &m_in)) != OK)
|
|
||||||
panic("receive failed: %d", r);
|
|
||||||
|
|
||||||
*who_e = m_in.m_source;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*===========================================================================*
|
|
||||||
* send_reply *
|
|
||||||
*===========================================================================*/
|
|
||||||
static void send_reply(err, transid)
|
|
||||||
int err; /* resulting error code */
|
|
||||||
int transid;
|
|
||||||
{
|
|
||||||
/* Send a reply message to the requesting party, with the given error code.
|
|
||||||
*/
|
|
||||||
int r;
|
|
||||||
|
|
||||||
m_out.m_type = err;
|
|
||||||
if (IS_VFS_FS_TRANSID(transid)) {
|
|
||||||
/* If a transaction ID was set, reset it */
|
|
||||||
m_out.m_type = TRNS_ADD_ID(m_out.m_type, transid);
|
|
||||||
}
|
|
||||||
if ((r = send(m_in.m_source, &m_out)) != OK)
|
|
||||||
printf("HGFS: send failed (%d)\n", r);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
|
|
||||||
/* Structure with global file system state. */
|
|
||||||
struct state {
|
|
||||||
int mounted; /* is the file system mounted? */
|
|
||||||
int read_only; /* is the file system mounted read-only? note,
|
|
||||||
* has no relation to the shared folder mode */
|
|
||||||
dev_t dev; /* device the file system is mounted on */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Structure with options affecting global behavior. */
|
|
||||||
struct opt {
|
|
||||||
char prefix[PATH_MAX]; /* prefix for all paths used */
|
|
||||||
uid_t uid; /* UID that owns all files */
|
|
||||||
gid_t gid; /* GID that owns all files */
|
|
||||||
unsigned int file_mask; /* AND-mask to apply to file permissions */
|
|
||||||
unsigned int dir_mask; /* AND-mask to apply to directory perm's */
|
|
||||||
int case_insens; /* case insensitivity flag; has no relation
|
|
||||||
* to the hosts's shared folder naming */
|
|
||||||
};
|
|
|
@ -59,7 +59,7 @@ MKDEP_SUFFIXES?= .o .ln
|
||||||
# rumpfs_tmpfs rumpfs_udf rumpfs_ufs
|
# rumpfs_tmpfs rumpfs_udf rumpfs_ufs
|
||||||
.for _lib in \
|
.for _lib in \
|
||||||
c curses blockdriver chardriver netdriver edit end m sys timers util \
|
c curses blockdriver chardriver netdriver edit end m sys timers util \
|
||||||
bz2 l hgfs audiodriver exec ddekit devman usb elf bdev
|
bz2 l audiodriver exec ddekit devman usb elf bdev sffs hgfs
|
||||||
.ifndef LIB${_lib:tu}
|
.ifndef LIB${_lib:tu}
|
||||||
LIB${_lib:tu}= ${DESTDIR}/usr/lib/lib${_lib}.a
|
LIB${_lib:tu}= ${DESTDIR}/usr/lib/lib${_lib}.a
|
||||||
.MADE: ${LIB${_lib:tu}} # Note: ${DESTDIR} will be expanded
|
.MADE: ${LIB${_lib:tu}} # Note: ${DESTDIR} will be expanded
|
||||||
|
|
Loading…
Reference in a new issue