ceph/branches/sage/pgs/client/ldceph.cc
sageweil 9213a23f14 eek
git-svn-id: https://ceph.svn.sf.net/svnroot/ceph@1138 29311d96-e01e-0410-9327-a35deaab8ce9
2007-02-28 18:42:55 +00:00

298 lines
7.1 KiB
C++

// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
/*
* Ceph - scalable distributed file system
*
* Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
*
* This is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software
* Foundation. See file COPYING.
*
*/
#include <iostream>
using namespace std;
// ceph stuff
#include "config.h"
#include "client/Client.h"
#include "msg/TCPMessenger.h"
// syscall fun
#include <sys/syscall.h>
#include <unistd.h>
#include <sys/types.h>
//#include <sys/stat.h>
#define _FCNTL_H
#include <bits/fcntl.h>
#define CEPH_FD_OFF 50000
/****** startup etc *******/
class LdCeph {
public:
// globals
bool started;
char *mount_point;
char *mount_point_parent;
int mount_point_len;
Client *client;
filepath fp_mount_point;
filepath cwd;
bool cwd_above_mp, cwd_in_mp;
const char *get_ceph_path(const char *orig, char *buf) {
if (!started) return 0;
// relative path? BUG: this won't catch "blah/../../asdf"
if (orig[0] &&
orig[0] != '/' &&
!(orig[0] == '.' && orig[1] == '.')) {
if (cwd_in_mp) return orig; // inside mount point, definitely ceph
if (!cwd_above_mp) return 0; // not above mount point, definitely not ceph
// relative, above mp.
filepath o = orig;
filepath p = cwd;
for (unsigned b = 0; b < o.depth(); b++) {
if (o[b] == "..")
p.pop_dentry();
else
p.add_dentry(o[b]);
}
// FIXME rewrite
if (strncmp(p.c_str(), mount_point, mount_point_len) == 0) {
if (p.c_str()[mount_point_len] == 0)
return "/";
if (p.c_str()[mount_point_len] == '/') {
strcpy(buf, p.c_str() + mount_point_len);
return buf;
}
}
return 0;
} else {
// absolute
if (strncmp(orig, mount_point, mount_point_len) == 0) {
if (orig[mount_point_len] == 0)
return "/";
if (orig[mount_point_len] == '/')
return orig + mount_point_len;
}
return 0;
}
}
void refresh_cwd() {
char buf[255];
syscall(SYS_getcwd, buf, 255);
cwd = buf;
if (strncmp(buf, mount_point, mount_point_len) == 0 &&
(buf[mount_point_len] == 0 ||
buf[mount_point_len] == '/'))
cwd_in_mp = true;
else {
if (cwd.depth() > fp_mount_point.depth())
cwd_above_mp = false;
else {
cwd_above_mp = true;
for (unsigned i=0; i<cwd.depth(); i++) {
if (cwd[i] != fp_mount_point[i]) {
cwd_above_mp = false;
break;
}
}
}
}
//cout << "refresh_cwd '" << cwd << "', above=" << cwd_above_mp << ", in=" << cwd_in_mp << endl;
}
LdCeph() :
started(false),
mount_point(0), mount_point_parent(0),
mount_point_len(0),
cwd_above_mp(false), cwd_in_mp(false) {
// args
vector<char *> args;
env_to_vec(args);
parse_config_options(args);
tcpaddr_t nsa;
if (tcpmessenger_findns(nsa) < 0)
return;
tcpmessenger_init();
tcpmessenger_start();
tcpmessenger_start_rankserver(nsa);
client = new Client(new TCPMessenger(MSG_ADDR_CLIENT_NEW));
client->init();
int r = client->mount();
if (r < 0) {
// failure
cerr << "ldceph init: mount failed " << r << endl;
delete client;
client = 0;
} else {
// success
started = true;
mount_point = "/ceph";
mount_point_parent = "/";
mount_point_len = 5;
fp_mount_point = mount_point;
cerr << "ldceph init: mounted on " << mount_point << " as " << client->get_myaddr() << endl;
refresh_cwd();
}
}
~LdCeph() {
cout << "ldceph fini" << endl;
if (false && client) {
client->unmount();
client->shutdown();
delete client;
client = 0;
tcpmessenger_wait();
tcpmessenger_shutdown();
}
}
} ldceph;
/****** original functions ****/
/****** captured functions ****/
#define MYFD(f) ((fd) > CEPH_FD_OFF && ldceph.started)
#define TO_FD(fd) (fd > 0 ? fd+CEPH_FD_OFF:fd)
#define FROM_FD(fd) (fd - CEPH_FD_OFF)
extern "C" {
// open/close
//int open(const char *pathname, int flags) {
int open(const char *pathname, int flags, mode_t mode) {
char buf[255];
if (const char *c = ldceph.get_ceph_path(pathname, buf))
return TO_FD(ldceph.client->open(c, flags));
else
return syscall(SYS_open, pathname, flags, mode);
}
int creat(const char *pathname, mode_t mode) {
return open(pathname, O_CREAT|O_WRONLY|O_TRUNC, mode);
}
int close(int fd) {
if (MYFD(fd))
return ldceph.client->close(FROM_FD(fd));
else
return syscall(SYS_close, fd);
}
// read/write
ssize_t write(int fd, const void *buf, size_t count) {
if (MYFD(fd))
return ldceph.client->write(FROM_FD(fd), (char*)buf, count);
else
return syscall(SYS_write, fd, buf, count);
}
ssize_t read(int fd, void *buf, size_t count) {
if (MYFD(fd))
return ldceph.client->read(FROM_FD(fd), (char*)buf, count);
else
return syscall(SYS_read, fd, buf, count);
}
//int fsync(int fd);
//int fdatasync(int fd);
// namespace
int rmdir(const char *pathname) {
char buf[255];
if (const char *c = ldceph.get_ceph_path(pathname, buf))
return ldceph.client->rmdir(c);
else
return syscall(SYS_rmdir, pathname);
}
int mkdir(const char *pathname, mode_t mode) {
char buf[255];
if (const char *c = ldceph.get_ceph_path(pathname, buf))
return ldceph.client->mkdir(c, mode);
else
return syscall(SYS_mkdir, pathname, mode);
}
int unlink(const char *pathname) {
char buf[255];
if (const char *c = ldceph.get_ceph_path(pathname, buf))
return ldceph.client->unlink(c);
else
return syscall(SYS_unlink, pathname);
}
int stat(const char *pathname, struct stat *st) {
//int __xstat64(int __ver, const char *pathname, struct stat64 *st64) { // stoopid GLIBC
//struct stat *st = (struct stat*)st64;
char buf[255];
if (const char *c = ldceph.get_ceph_path(pathname, buf))
return ldceph.client->lstat(c, st); // FIXME
else
return syscall(SYS_stat, pathname, st);
}
//int fstat(int filedes, struct stat *buf);
//int lstat(const char *file_name, struct stat *buf);
int chdir(const char *pathname) {
char buf[255];
if (const char *c = ldceph.get_ceph_path(pathname, buf)) {
int r = ldceph.client->chdir(c);
if (r == 0) {
if (!ldceph.cwd_in_mp)
syscall(SYS_chdir, ldceph.mount_point_parent);
ldceph.cwd_in_mp = true;
ldceph.cwd_above_mp = false;
ldceph.cwd = ldceph.mount_point;
filepath fpc = c;
ldceph.cwd.append(fpc);
}
return r;
} else {
int r = syscall(SYS_chdir, pathname);
if (r) {
ldceph.refresh_cwd();
}
return r;
}
}
char *getcwd(char *buf, size_t size) {
strncpy(buf, ldceph.cwd.c_str(), size);
return buf;
}
//int fchdir(int fd);
}