HGFS: move all VMware-specific code into libhgfs
This commit is contained in:
parent
060399d9dd
commit
09b327b042
17 changed files with 117 additions and 114 deletions
|
@ -26,22 +26,13 @@ struct hgfs_attr {
|
|||
#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 */
|
||||
#define HGFS_ATTR_ATIME_SET 0x40 /* set specific file access time */
|
||||
#define HGFS_ATTR_MTIME_SET 0x80 /* set specific file modify time */
|
||||
#define HGFS_ATTR_ALL \
|
||||
(HGFS_ATTR_SIZE | HGFS_ATTR_CRTIME | HGFS_ATTR_ATIME | \
|
||||
HGFS_ATTR_MTIME | HGFS_ATTR_CTIME | HGFS_ATTR_MODE | \
|
||||
HGFS_ATTR_ATIME_SET | HGFS_ATTR_MTIME_SET)
|
||||
|
||||
int hgfs_init(void);
|
||||
void hgfs_cleanup(void);
|
||||
|
||||
int hgfs_enabled(void);
|
||||
|
||||
int hgfs_open(char *path, int flags, int mode, hgfs_file_t *handle);
|
||||
int hgfs_read(hgfs_file_t handle, char *buf, size_t size, u64_t offset);
|
||||
int hgfs_write(hgfs_file_t handle, const char *buf, size_t len, u64_t
|
||||
offset, int append);
|
||||
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);
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
LIB= hgfs
|
||||
SRCS= backdoor.S attr.c channel.c dir.c error.c file.c \
|
||||
link.c misc.c path.c rpc.c time.c
|
||||
info.c link.c misc.c path.c rpc.c time.c
|
||||
|
||||
.include <bsd.lib.mk>
|
||||
|
|
|
@ -64,18 +64,34 @@ struct hgfs_attr *attr;
|
|||
{
|
||||
/* Set selected attributes of a file by path name.
|
||||
*/
|
||||
u8_t mask;
|
||||
|
||||
RPC_REQUEST(HGFS_REQ_SETATTR);
|
||||
|
||||
RPC_NEXT8 = (attr->a_mask & HGFS_ATTR_ALL);
|
||||
/* This library implements the HGFS v1 protocol, which is largely
|
||||
* path-oriented. This is the only method to set the file size, and thus,
|
||||
* truncating a deleted file is not possible. This has been fixed in later
|
||||
* HGFS protocol version (v2/v3).
|
||||
*/
|
||||
mask = 0;
|
||||
if (attr->a_mask & HGFS_ATTR_MODE) mask |= HGFS_ATTR_MODE;
|
||||
if (attr->a_mask & HGFS_ATTR_SIZE) mask |= HGFS_ATTR_SIZE;
|
||||
if (attr->a_mask & HGFS_ATTR_CRTIME) mask |= HGFS_ATTR_CRTIME;
|
||||
if (attr->a_mask & HGFS_ATTR_ATIME)
|
||||
mask |= HGFS_ATTR_ATIME | HGFS_ATTR_ATIME_SET;
|
||||
if (attr->a_mask & HGFS_ATTR_MTIME)
|
||||
mask |= HGFS_ATTR_MTIME | HGFS_ATTR_MTIME_SET;
|
||||
if (attr->a_mask & HGFS_ATTR_CTIME) mask |= HGFS_ATTR_CTIME;
|
||||
|
||||
RPC_NEXT8 = mask;
|
||||
|
||||
RPC_NEXT32 = !!(S_ISDIR(attr->a_mode));
|
||||
RPC_NEXT32 = ex64lo(attr->a_size);
|
||||
RPC_NEXT32 = ex64hi(attr->a_size);
|
||||
|
||||
time_put((attr->a_mask & HGFS_ATTR_CRTIME) ? &attr->a_crtime : NULL);
|
||||
time_put((attr->a_mask & HGFS_ATTR_ATIME_SET) ? &attr->a_atime : NULL);
|
||||
time_put((attr->a_mask & HGFS_ATTR_MTIME_SET) ? &attr->a_mtime : NULL);
|
||||
time_put((attr->a_mask & HGFS_ATTR_ATIME) ? &attr->a_atime : NULL);
|
||||
time_put((attr->a_mask & HGFS_ATTR_MTIME) ? &attr->a_mtime : NULL);
|
||||
time_put((attr->a_mask & HGFS_ATTR_CTIME) ? &attr->a_ctime : NULL);
|
||||
|
||||
RPC_NEXT8 = HGFS_MODE_TO_PERM(attr->a_mode);
|
||||
|
|
|
@ -60,3 +60,13 @@ enum {
|
|||
/* HGFS mode/perms conversion macros */
|
||||
#define HGFS_MODE_TO_PERM(m) (((m) & S_IRWXU) >> 6)
|
||||
#define HGFS_PERM_TO_MODE(p) (((p) << 6) & S_IRWXU)
|
||||
|
||||
/* HGFS attribute flags */
|
||||
#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 */
|
||||
#define HGFS_ATTR_ATIME_SET 0x40 /* set specific file access time */
|
||||
#define HGFS_ATTR_MTIME_SET 0x80 /* set specific file modify time */
|
||||
|
|
|
@ -39,7 +39,7 @@ struct hgfs_attr *attr;
|
|||
* number. Upon success, the resulting path name is stored in the given buffer
|
||||
* and the given attribute structure is filled selectively as requested. Upon
|
||||
* error, the contents of the path buffer and attribute structure are
|
||||
* undefined.
|
||||
* undefined. ENOENT is returned upon end of directory.
|
||||
*/
|
||||
int r;
|
||||
|
||||
|
@ -47,12 +47,20 @@ struct hgfs_attr *attr;
|
|||
RPC_NEXT32 = (u32_t)handle;
|
||||
RPC_NEXT32 = index;
|
||||
|
||||
/* EINVAL signifies end of directory. */
|
||||
if ((r = rpc_query()) != OK)
|
||||
return r;
|
||||
return (r == EINVAL) ? ENOENT : OK;
|
||||
|
||||
attr_get(attr);
|
||||
|
||||
return path_get(buf, size);
|
||||
if ((r = path_get(buf, size)) != OK)
|
||||
return r;
|
||||
|
||||
/* VMware Player 3 returns an empty name, instead of EINVAL, when reading
|
||||
* from an EOF position right after opening the directory handle. Seems to be
|
||||
* a newly introduced bug..
|
||||
*/
|
||||
return (!buf[0]) ? ENOENT : OK;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
|
|
@ -74,8 +74,8 @@ u64_t off; /* file offset */
|
|||
len = RPC_NEXT32;
|
||||
if (len > max) len = max; /* sanity check */
|
||||
|
||||
/* Only copy out data if we're requested to do so. */
|
||||
if (buf != NULL)
|
||||
/* Only copy out data if we're not operating directly on the RPC buffer. */
|
||||
if (buf != RPC_PTR)
|
||||
memcpy(buf, RPC_PTR, len);
|
||||
|
||||
return len;
|
||||
|
@ -84,12 +84,11 @@ u64_t off; /* file offset */
|
|||
/*===========================================================================*
|
||||
* hgfs_write *
|
||||
*===========================================================================*/
|
||||
int hgfs_write(handle, buf, len, off, append)
|
||||
int hgfs_write(handle, buf, len, off)
|
||||
hgfs_file_t handle; /* handle to open file */
|
||||
const char *buf; /* data buffer or NULL */
|
||||
char *buf; /* data buffer or NULL */
|
||||
size_t len; /* number of bytes to write */
|
||||
u64_t off; /* file offset */
|
||||
int append; /* if set, append to file (ignore offset) */
|
||||
{
|
||||
/* Write to an open file. Upon success, return the number of bytes written.
|
||||
*/
|
||||
|
@ -97,22 +96,13 @@ int append; /* if set, append to file (ignore offset) */
|
|||
|
||||
RPC_REQUEST(HGFS_REQ_WRITE);
|
||||
RPC_NEXT32 = (u32_t)handle;
|
||||
|
||||
if (append) {
|
||||
RPC_NEXT8 = 1;
|
||||
RPC_NEXT32 = 0;
|
||||
RPC_NEXT32 = 0;
|
||||
}
|
||||
else {
|
||||
RPC_NEXT8 = 0;
|
||||
RPC_NEXT32 = ex64lo(off);
|
||||
RPC_NEXT32 = ex64hi(off);
|
||||
}
|
||||
|
||||
RPC_NEXT8 = 0; /* append flag */
|
||||
RPC_NEXT32 = ex64lo(off);
|
||||
RPC_NEXT32 = ex64hi(off);
|
||||
RPC_NEXT32 = len;
|
||||
|
||||
/* Only copy in data if we're requested to do so. */
|
||||
if (buf != NULL)
|
||||
/* Only copy in data if we're not operating directly on the RPC buffer. */
|
||||
if (RPC_PTR != buf)
|
||||
memcpy(RPC_PTR, buf, len);
|
||||
RPC_ADVANCE(len);
|
||||
|
||||
|
|
38
lib/libhgfs/info.c
Normal file
38
lib/libhgfs/info.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/* Part of libhgfs - (c) 2009, D.C. van Moolenbroek */
|
||||
|
||||
#include "inc.h"
|
||||
|
||||
/*===========================================================================*
|
||||
* hgfs_queryvol *
|
||||
*===========================================================================*/
|
||||
int hgfs_queryvol(path, free, total)
|
||||
char *path;
|
||||
u64_t *free;
|
||||
u64_t *total;
|
||||
{
|
||||
/* Retrieve information about available and total volume space associated with
|
||||
* a given path.
|
||||
*/
|
||||
u32_t lo, hi;
|
||||
int r;
|
||||
|
||||
RPC_REQUEST(HGFS_REQ_QUERYVOL);
|
||||
|
||||
path_put(path);
|
||||
|
||||
/* It appears that this call always fails with EACCES ("permission denied")
|
||||
* on read-only folders. As far as I can tell, this is a VMware bug.
|
||||
*/
|
||||
if ((r = rpc_query()) != OK)
|
||||
return r;
|
||||
|
||||
lo = RPC_NEXT32;
|
||||
hi = RPC_NEXT32;
|
||||
*free = make64(lo, hi);
|
||||
|
||||
lo = RPC_NEXT32;
|
||||
hi = RPC_NEXT32;
|
||||
*total = make64(lo, hi);
|
||||
|
||||
return OK;
|
||||
}
|
|
@ -8,8 +8,7 @@
|
|||
int hgfs_init()
|
||||
{
|
||||
/* Initialize the library. Return OK on success, or a negative error code
|
||||
* otherwise. If EAGAIN is returned, shared folders are disabled; in that
|
||||
* case, other operations may be tried (and possibly succeed).
|
||||
* otherwise. If EAGAIN is returned, shared folders are disabled.
|
||||
*/
|
||||
|
||||
time_init();
|
||||
|
@ -27,47 +26,3 @@ void hgfs_cleanup()
|
|||
|
||||
rpc_close();
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* hgfs_enabled *
|
||||
*===========================================================================*/
|
||||
int hgfs_enabled()
|
||||
{
|
||||
/* Check if shared folders are enabled. Return OK if so, EAGAIN if not, and
|
||||
* another negative error code on error.
|
||||
*/
|
||||
|
||||
return rpc_test();
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* hgfs_queryvol *
|
||||
*===========================================================================*/
|
||||
int hgfs_queryvol(path, free, total)
|
||||
char *path;
|
||||
u64_t *free;
|
||||
u64_t *total;
|
||||
{
|
||||
/* Retrieve information about available and total volume space associated with
|
||||
* a given path.
|
||||
*/
|
||||
u32_t lo, hi;
|
||||
int r;
|
||||
|
||||
RPC_REQUEST(HGFS_REQ_QUERYVOL);
|
||||
|
||||
path_put(path);
|
||||
|
||||
if ((r = rpc_query()) != OK)
|
||||
return r;
|
||||
|
||||
lo = RPC_NEXT32;
|
||||
hi = RPC_NEXT32;
|
||||
*free = make64(lo, hi);
|
||||
|
||||
lo = RPC_NEXT32;
|
||||
hi = RPC_NEXT32;
|
||||
*total = make64(lo, hi);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,8 @@ static struct channel rpc_chan;
|
|||
int rpc_open()
|
||||
{
|
||||
/* Open a HGFS RPC backdoor channel to the VMware host, and make sure that it
|
||||
* is working. Return OK upon success, or a negative error code otherwise.
|
||||
* is working. Return OK upon success, or a negative error code otherwise; in
|
||||
* particular, return EAGAIN if shared folders are disabled.
|
||||
*/
|
||||
int r;
|
||||
|
||||
|
@ -22,7 +23,7 @@ int rpc_open()
|
|||
|
||||
r = rpc_test();
|
||||
|
||||
if (r != OK && r != EAGAIN)
|
||||
if (r != OK)
|
||||
channel_close(&rpc_chan);
|
||||
|
||||
return r;
|
||||
|
|
|
@ -7,6 +7,6 @@
|
|||
#define NUM_HASH_SLOTS 1023
|
||||
|
||||
/* Arbitrary block size constant returned by fstatfs and statvfs.
|
||||
* Also used by getdents. This is not the actual HGFS data transfer unit size.
|
||||
* Also used by getdents. This is not the underlying data transfer unit size.
|
||||
*/
|
||||
#define BLOCK_SIZE 4096
|
||||
|
|
|
@ -20,10 +20,11 @@
|
|||
* modifications on the host system are not part of the protocol, so sometimes
|
||||
* the server may discover that some files do not exist anymore. In that case,
|
||||
* they are marked as DELETED in the inode table. Such files may still be used
|
||||
* because of open file handles, but cannot be referenced by path anymore.
|
||||
* Unfortunately the HGFS v1 protocol is largely path-oriented, so even
|
||||
* truncating a deleted file is not possible. This has been fixed in v2/v3, but
|
||||
* we currently use the v1 protocol for VMware backwards compatibility reasons.
|
||||
* because of open file handles, but cannot be referenced by path anymore. The
|
||||
* underlying protocol may not support truncation of open files anyway. Since
|
||||
* we currently cannot guarantee that a file is actually opened before it is
|
||||
* deleted (as this would consistute opening every file being looked up), we
|
||||
* effectively do not properly support open deleted files at all anyway.
|
||||
*
|
||||
* An inode is REFERENCED iff it has a reference count > 0 *or* has children.
|
||||
* An inode is LINKED IN iff it has a parent.
|
||||
|
@ -62,8 +63,8 @@ struct inode {
|
|||
unsigned short i_flags; /* any combination of I_* flags */
|
||||
union {
|
||||
TAILQ_ENTRY(inode) u_free; /* free list chain entry */
|
||||
hgfs_file_t u_file; /* handle to open HGFS file */
|
||||
hgfs_dir_t u_dir; /* handle to open HGFS directory */
|
||||
hgfs_file_t u_file; /* handle to open file */
|
||||
hgfs_dir_t u_dir; /* handle to open directory */
|
||||
} i_u;
|
||||
char i_name[NAME_MAX+1]; /* entry name in parent directory */
|
||||
};
|
||||
|
|
|
@ -60,8 +60,11 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
|
|||
|
||||
/* Initialize the HGFS library. If this fails, exit immediately. */
|
||||
r = hgfs_init();
|
||||
if (r != OK && r != EAGAIN) {
|
||||
printf("HGFS: unable to initialize HGFS library (%d)\n", r);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,8 @@ int do_statvfs()
|
|||
|
||||
/* Unfortunately, we cannot be any more specific than this, because we are
|
||||
* not given an inode number. Statistics of individual shared folders can
|
||||
* only be obtained by using the "prefix=" option when mounting.
|
||||
* only be obtained by making sure that the root of the file system is an
|
||||
* actual share, and not a list of available shares.
|
||||
*/
|
||||
if ((ino = find_inode(ROOT_INODE_NR)) == NULL)
|
||||
return EINVAL;
|
||||
|
@ -51,9 +52,6 @@ int do_statvfs()
|
|||
if ((r = verify_inode(ino, path, NULL)) != OK)
|
||||
return r;
|
||||
|
||||
/* It appears that this call always fails with EACCES ("permission denied")
|
||||
* on read-only folders. As far as I can tell, this is a VMware bug.
|
||||
*/
|
||||
if ((r = hgfs_queryvol(path, &free, &total)) != OK)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -44,9 +44,7 @@ int do_readsuper()
|
|||
* VFS. Print a (hopefully) helpful error message, and abort the mount.
|
||||
*/
|
||||
if ((r = verify_inode(ino, path, &attr)) != OK) {
|
||||
if (r == EAGAIN)
|
||||
printf("HGFS: shared folders disabled\n");
|
||||
else if (opt.prefix[0] && (r == ENOENT || r == EACCES))
|
||||
if (opt.prefix[0] && (r == ENOENT || r == EACCES))
|
||||
printf("HGFS: unable to access the given prefix directory\n");
|
||||
else
|
||||
printf("HGFS: unable to access shared folders\n");
|
||||
|
|
|
@ -48,7 +48,7 @@ int do_read()
|
|||
while (count > 0) {
|
||||
chunk = MIN(count, size);
|
||||
|
||||
if ((r = hgfs_read(ino->i_file, NULL, chunk, pos)) <= 0)
|
||||
if ((r = hgfs_read(ino->i_file, ptr, chunk, pos)) <= 0)
|
||||
break;
|
||||
|
||||
chunk = r;
|
||||
|
@ -117,7 +117,7 @@ int do_getdents()
|
|||
*/
|
||||
for (pos = m_in.REQ_SEEK_POS_LO; ; pos++) {
|
||||
/* Determine which inode and name to use for this entry.
|
||||
* We have no idea whether the HGFS host will give us "." and/or "..",
|
||||
* We have no idea whether the host will give us "." and/or "..",
|
||||
* so generate our own and skip those from the host.
|
||||
*/
|
||||
if (pos == 0) {
|
||||
|
@ -144,14 +144,9 @@ int do_getdents()
|
|||
r = hgfs_readdir(ino->i_dir, pos - 2, name, sizeof(name),
|
||||
&attr);
|
||||
|
||||
if (r != OK || !name[0]) {
|
||||
if (r != OK) {
|
||||
/* No more entries? Then close the handle and stop. */
|
||||
/* VMware Player 3 returns an empty name, instead of
|
||||
* EINVAL, when reading from an EOF position right
|
||||
* after opening the directory handle. Seems to be a
|
||||
* newly introduced bug..
|
||||
*/
|
||||
if (r == EINVAL || !name[0]) {
|
||||
if (r == ENOENT) {
|
||||
put_handle(ino);
|
||||
|
||||
break;
|
||||
|
|
|
@ -19,7 +19,7 @@ mode_t get_mode(ino, mode)
|
|||
struct inode *ino;
|
||||
int mode;
|
||||
{
|
||||
/* Return the mode for an inode, given the inode and the HGFS retrieved mode.
|
||||
/* Return the mode for an inode, given the inode and the retrieved mode.
|
||||
*/
|
||||
|
||||
mode &= S_IRWXU;
|
||||
|
@ -31,7 +31,7 @@ int mode;
|
|||
mode = S_IFREG | (mode & opt.file_mask);
|
||||
|
||||
if (state.read_only)
|
||||
mode &= ~0222;
|
||||
mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
@ -158,8 +158,7 @@ int do_utime()
|
|||
if ((r = verify_inode(ino, path, NULL)) != OK)
|
||||
return r;
|
||||
|
||||
attr.a_mask = HGFS_ATTR_ATIME | HGFS_ATTR_MTIME | HGFS_ATTR_ATIME_SET |
|
||||
HGFS_ATTR_MTIME_SET;
|
||||
attr.a_mask = HGFS_ATTR_ATIME | HGFS_ATTR_MTIME;
|
||||
attr.a_atime.tv_sec = m_in.REQ_ACTIME;
|
||||
attr.a_atime.tv_nsec = 0;
|
||||
attr.a_mtime.tv_sec = m_in.REQ_MODTIME;
|
||||
|
|
|
@ -59,7 +59,7 @@ cp_grant_id_t *grantp;
|
|||
memset(ptr, 0, chunk);
|
||||
}
|
||||
|
||||
if ((r = hgfs_write(ino->i_file, NULL, chunk, pos, FALSE)) <= 0)
|
||||
if ((r = hgfs_write(ino->i_file, ptr, chunk, pos)) <= 0)
|
||||
break;
|
||||
|
||||
count -= r;
|
||||
|
|
Loading…
Reference in a new issue