<repo_name>stnma7e/driver<file_sep>/src/filetree.rs
extern crate uuid;
extern crate rusqlite;

use crypto::md5::Md5;
use crypto::digest::Digest;

use std::io::prelude::*;
use std::fs::{File};
use std::path::{Path};
use std::collections::hash_map::HashMap;
use uuid::Uuid;

use time;
use fuse::FileAttr;

use types::*;

pub struct FileUpdates {
    pub new_files: Option<Vec<FileResponse>>,
    pub deleted_files: Option<Vec<FileResponse>>
}

pub trait FileDownloader {
    fn get_file_list(&mut self, root_folder: &uuid::Uuid) -> Result<FileUpdates, DriveError>;
    fn resolve_error(&mut self, resp_string: &str) -> Result<(), DriveError>;
    fn verify_checksum(&self, fd: &Uuid, checksum: Option<&str>) -> Result<FileCheckResponse, DriveError>;
    fn retreive_file(&mut self, uuid: &Uuid, parent_uuid: &Uuid) -> Result<u64, DriveError>;
    fn create_local_file(&mut self, parent_uuid: &Uuid, file_path: &Path) -> Result<Uuid, DriveError>;
    fn read_file(&self, uuid: &Uuid) -> Result<Vec<u8>, DriveError>;
    fn write_file(&self, uuid: &Uuid, data: &[u8], offset: u64) -> Result<u32, DriveError>;
    fn flush_file(&self, uuid: &Uuid) -> Result<(), DriveError>;
}

pub struct FileTree<'b> {
    pub child_map: HashMap<u64, Vec<u64>>,
    pub inode_map: HashMap<u64, FileData>,
    pub parent_map: HashMap<u64, u64>,
    pub current_inode: u64,

    pub file_downloader: &'b mut FileDownloader,
    pub conn: rusqlite::Connection,
}

impl<'b> FileTree<'b> {
    fn check_for_new_files(&mut self, parent_folder_id: &uuid::Uuid, parent_inode: u64) -> Result<(), DriveError> {
        println!("\n\n\n");
        let updates = try!(
            self.file_downloader.get_file_list(parent_folder_id)
            .or_else(|err| {
                println!("trying to resolve a getfilelist error");
                self.file_downloader.resolve_error(&err.response.expect(&format!("no response in errorrr: {:?}", err.kind)))
                .and(self.file_downloader.get_file_list(parent_folder_id))
                .or_else(|err| -> Result<FileUpdates, DriveError> {
                    println!("err: {:?}", err);
                    Err(err)
                })
            })
        );

        if let Some(new_files) = updates.new_files {
            for fr in new_files {
                let inode = self.current_inode;
                self.current_inode += 1;

                let kind = if fr.kind == FileType::Directory {
                    "directory"
                } else {
                    "regular"
                };

                let mut size = 0;
                {
                    let parent_ino = self.conn.query_row_named("SELECT ino FROM files WHERE uuid=:uuid"
                        , &[( ":uuid", &fr.parent_uuid.clone().as_bytes().to_vec() )]
                        , |row| -> u64 {
                            row.get::<i32, i64>(0) as u64
                        }
                    ).unwrap();
                    let parent = try!(self.inode_map.get(&parent_ino).ok_or(DriveError {
                        kind: DriveErrorType::NoSuchInode,
                        response: None,
                    }));

                    match self.file_downloader.retreive_file(&fr.uuid, &parent.id) {
                        Ok(s) => {
                            size = s;
                        },
                        Err(error) => {
                            println!("error when saving or downloading file: {:?}", error);
                            println!("deleting metadata, and trying a fresh save");
                            try!(
                                (match error.response {
                                    Some(ref resp) => {
                                        self.file_downloader.resolve_error(resp)
                                    },
                                    None => {
                                        println!("no response in error: {:?}", error.kind);
                                        Err(error)
                                    }
                                })
                                .and(self.file_downloader.retreive_file(&fr.uuid, &parent.id))
                                .or_else(|err| -> Result<u64, DriveError> {
                                    println!("error resolution failed. err2: {:?}", err);
                                    Ok(0)
                                })
                            );
                        }
                    }
                }

                self.conn.execute("INSERT INTO files (ino, uuid, parent_ino, name, size, kind)
                                   VALUES ($1, $2, $3, $4, $5, $6)",
                                   &[ &(inode as i64),
                                      &fr.uuid.clone().as_bytes().to_vec(),
                                      &(parent_inode as i64),
                                      &fr.name.clone(),
                                      &(size as i64),
                                      &kind,
                                    ]
                ).unwrap_or_else(|_| {
//                    println!("file already in filetree db: {}, err: {:?}", fr.name, err);
//                    println!("updating file information");

                    self.conn.execute("UPDATE files
                                       SET name=$1
                                       WHERE uuid=$3"
                        , &[ &fr.name.clone()
                           , &fr.uuid.clone().as_bytes().to_vec()
                           ]
                    ).unwrap_or_else(|err| {
                        println!("couldn't update file in filetree db, err: {:?}", err);
                        0
                    });
                    0
                });


            }
        }

        if let Some(del_files) = updates.deleted_files {
            for fr in del_files {
                self.conn.execute("DELETE FROM files WHERE uuid=:uuid"
                    , &[ &fr.uuid.clone().as_bytes().to_vec() ]
                ).unwrap_or_else(|err| {
                    println!("couldn't delte file: {}, err: {:?}", fr.name, err);
                    0
                });
            }
        }

        Ok(())

    }

    pub fn get_files(&mut self, parent_folder_path: &Path, parent_folder_id: &uuid::Uuid, parent_inode: u64) -> Result<(), DriveError> {
        try!(self.check_for_new_files(parent_folder_id, parent_inode));
        println!("Populating FUSE fs...


        ");
        self._get_files(parent_folder_path, parent_folder_id, parent_inode)
    }

    fn _get_files(&mut self, parent_folder_path: &Path, parent_folder_id: &uuid::Uuid, parent_inode: u64) -> Result<(), DriveError> {
        let files = {
            let mut stmt = try!(self.conn.prepare("SELECT uuid, ino, name, kind, size FROM files
                                                   WHERE parent_ino=:parent_ino"));
            let rows = try!(stmt.query_map_named(&[(":parent_ino", &(parent_inode as i64))]
                , |row| -> FileData {
                    let uuid = Uuid::from_bytes(&row.get::<i32, Vec<u8>>(0)).unwrap();
                    let ino  = row.get::<i32, i64>(1) as u64;
                    let name = row.get::<i32, String>(2);
                    let str_kind = row.get::<i32, String>(3);
                    let size = row.get::<i32, i64>(4) as u64;
                    let ts = time::now().to_timespec();

                    let mut fadsf = FileType::RegularFile;
                    if str_kind == "directory" {
                        fadsf = FileType::Directory;
                    }

                    let mut new_path = parent_folder_path.to_owned();
                    new_path.push(name.clone());

                    FileData {
                        id: uuid,
                        path: new_path,
                        parent_inode: parent_inode,
                        attr: FileAttr {
                            ino: ino,
                            size: size,
                            blocks: size/512,
                            atime: ts,
                            mtime: ts,
                            ctime: ts,
                            crtime: ts,
                            kind: fadsf,
                            perm: 0o777,
                            nlink: 0,
                            uid: 1000,
                            gid: 1000,
                            rdev: 0,
                            flags: 0,
                        },
                        source_data: SourceData::CreatedFile,
                    }
                }
            ));

            let mut files = Vec::new();
            for i in rows {
                files.push(i.unwrap())
            }
            files.clone()
        };

        for fd in files {
            //println!("found parent {}, adding new child {:?}, inode: {}", parent_folder_id, fd.path, fd.attr.ino);

            self.inode_map.entry(fd.attr.ino).or_insert(fd.clone());
            self.child_map.entry(fd.attr.ino).or_insert(Vec::new());
            self.parent_map.entry(fd.attr.ino).or_insert(parent_inode);
            self.child_map.entry(parent_inode).or_insert(Vec::new())
                .push(fd.attr.ino);

            // then recurse to retrieve children files
            if fd.attr.kind == FileType::Directory
            && fd.attr.ino  != 1 {
                try!(self._get_files(&fd.path, &fd.id, fd.attr.ino));
            }
        }

        Ok(())
    }
}

pub fn get_file_checksum(file_path: &Path) -> Result<String, DriveError> {
    let mut f = try!(File::open(file_path));
    let mut f_str = Vec::<u8>::new();

    try!(f.read_to_end(&mut f_str));

    let mut md5 = Md5::new();
    md5.input(&f_str);

    Ok(md5.result_str())
}
<file_sep>/src/types.rs
#![allow(non_snake_case)] // to simplify json decoding for the Response types

extern crate hyper;
extern crate rustc_serialize;
extern crate libc;
extern crate std;
extern crate uuid;
extern crate rusqlite;

use rustc_serialize::json::{Json, ToJson};
use std::collections::BTreeMap;
use std::path::{PathBuf};
pub use fuse::FileType;
use fuse::FileAttr;

#[derive (RustcDecodable, Debug, Clone)]
pub struct TokenResponse {
    pub access_token: String,
    pub token_type: String,
    pub expires_in: u32,
    pub id_token: String,
    pub refresh_token: String,
}

impl ToJson for TokenResponse {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("access_token".to_string(),  self.access_token.to_json());
        d.insert("token_type".to_string(),    self.token_type.to_json());
        d.insert("expires_in".to_string(),    self.expires_in.to_json());
        d.insert("id_token".to_string(),      self.id_token.to_json());
        d.insert("refresh_token".to_string(), self.refresh_token.to_json());
        Json::Object(d)
    }
}

#[derive (RustcDecodable, Debug, Clone)]
pub struct DriveFileResponse {
    pub kind: String, // essentially unused, will ostensibly always be "drive#file"
    pub id: String,
    pub name: String,
    pub mimeType: String,
    pub parents: Vec<String>,
    pub path: Option<PathBuf>,
}

#[derive (Debug, Clone)]
pub enum SourceData {
    CreatedFile,
    Drive(DriveFileResponse),
}

#[derive (Debug, Clone)]
pub struct FileResponse {
    pub uuid: uuid::Uuid,
    pub parent_uuid: uuid::Uuid,
    pub kind: FileType,
    pub name: String,
    pub source_data: SourceData,
}

#[derive (Debug, Clone)]
pub struct FileData {
    pub id: uuid::Uuid,
    pub parent_inode: u64,
    pub path: PathBuf,
    pub attr: FileAttr,
    pub source_data: SourceData,
}

impl ToJson for DriveFileResponse {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        // All standard types implement `to_json()`, so use it
        d.insert("kind".to_string(),     self.kind.to_json());
        d.insert("id".to_string(),       self.id.to_json());
        d.insert("name".to_string(),     self.name.to_json());
        d.insert("mimeType".to_string(), self.mimeType.to_json());
        Json::Object(d)
    }
}

#[derive (RustcDecodable, Debug, Clone)]
pub struct ErrorDetailsResponse {
    pub domain: String,
    pub reason: String,
    pub message: String,
}

#[derive (RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct FileCheckResponse {
    pub md5Checksum: String,
    pub size: u64,
}

#[derive (Clone)]
pub struct AuthData {
    pub tr: TokenResponse,
    pub client_id: String,
    pub client_secret: String,
    // maybe this can be converted to a std::path::Path later?
    pub cache_file_path: String,
}

#[derive (Debug)]
pub enum DriveErrorType {
    Hyper(hyper::error::Error),
    Rusqlite(rusqlite::Error),
    JsonDecodeFileList,
    JsonReadError(rustc_serialize::json::BuilderError),
    JsonObjectify,
    JsonInvalidAttribute,
    JsonCannotConvertToArray,
    JsonCannotDecode(rustc_serialize::json::DecoderError),
    JsonCannotEncode(rustc_serialize::json::EncoderError),
    Io(std::io::Error),
    UnsupportedDocumentType,
    FailedChecksum,
    FailedToChecksumExistingFile,
    Tester,
    NoFileName,
    FailedUuidLookup,
    NoSuchInode,
    NoPathForParent,
    FileNotYetDownloaded,
    WrongSourceDataType,
}

#[derive (Debug)]
pub struct DriveError {
    pub kind: DriveErrorType,
    pub response: Option<String>,
}

impl From<hyper::error::Error> for DriveError {
    fn from(err: hyper::error::Error) -> DriveError {
        DriveError {
            kind: DriveErrorType::Hyper(err),
            response: None
        }
    }
}

impl From<rusqlite::Error> for DriveError {
    fn from(err: rusqlite::Error) -> DriveError {
        DriveError {
            kind: DriveErrorType::Rusqlite(err),
            response: None
        }
    }
}

impl From<rustc_serialize::json::BuilderError> for DriveError {
    fn from(err: rustc_serialize::json::BuilderError) -> DriveError {
        DriveError {
            kind: DriveErrorType::JsonReadError(err),
            response: None
        }
    }
}

impl From<rustc_serialize::json::DecoderError> for DriveError {
    fn from(err: rustc_serialize::json::DecoderError) -> DriveError {
        DriveError {
            kind: DriveErrorType::JsonCannotDecode(err),
            response: None
        }
    }
}

impl From<std::io::Error> for DriveError {
    fn from(err: std::io::Error) -> DriveError {
        DriveError {
            kind: DriveErrorType::Io(err),
            response: None
        }
    }
}

impl From<rustc_serialize::json::EncoderError> for DriveError {
    fn from(err: rustc_serialize::json::EncoderError) -> DriveError {
        DriveError {
            kind: DriveErrorType::JsonCannotEncode(err),
            response: None,
        }
    }
}
<file_sep>/src/fs.rs
#![allow(unused_variables)]

extern crate uuid;

use std::path::Path;
use libc::{ENOENT, ENOSYS};
use time;
use time::Timespec;
use fuse::{FileAttr, Filesystem, Request, ReplyAttr, ReplyEntry, ReplyDirectory, ReplyData, ReplyOpen, ReplyEmpty, ReplyWrite, ReplyStatfs, ReplyCreate, ReplyLock, ReplyBmap};
use std::ffi::OsStr;

use std::fs::{File};
use std::os::unix::io::{IntoRawFd, FromRawFd};
use uuid::Uuid;

use filetree::*;
use types::*;

impl<'b> Filesystem for FileTree<'b> {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        println!("getattr(ino={})", ino);

        if let Some(path) = self.inode_map.get(&ino) {
            let ttl = time::now().to_timespec();
            reply.attr(&ttl, &path.attr);
            return
        } else {
            println!("erro in getattr, ino={}", ino);
            reply.error(ENOSYS);
            return
        }
    }

    fn lookup(&mut self, _req: &Request, parent: u64, name: &Path, reply: ReplyEntry) {
        if let Some(children) = self.child_map.get(&parent) {
            for i in children {
                if let Some(child) = self.inode_map.get(&i) {
                    let path = child.path.clone();
                    if path.file_name().expect(&format!("no file_name {:?}", child)) == name {
                        let ttl = time::now().to_timespec();
                        reply.entry(&ttl, &child.attr, 0);
                        return
                    }
                }
            }
        }

        reply.error(ENOENT)
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        println!("readdir(ino={}, fh={}, offset={})", ino, fh, offset);
        if offset == 0 {
            reply.add(ino, 0, FileType::Directory, &Path::new("."));
            reply.add(*self.parent_map.get(&ino).expect(&format!("no parent inode for {}", ino)), 1, FileType::Directory, &Path::new(".."));

            let mut new_offest = 1;
            if let Some(children) = self.child_map.get(&ino) {
                new_offest += 1;

                for child_inode in children {
                    if let Some(child) = self.inode_map.get(&child_inode) {
                        reply.add(*child_inode, new_offest, child.attr.kind, &child.path.file_name().expect(&format!("no file_name {:?}", child)));
                    } else {
                        println!("no inode for child {:?}, parent {:?}", child_inode, children);
                        panic!()
                    }
                }

                reply.ok();
                return
            } else {
                println!("fdasd");
            }
        }

        reply.error(ENOENT);
    }

    fn read(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, size: u32, reply: ReplyData) {
        println!("read(ino={}, fh={}, offset={}, size={})", ino, fh, offset, size);

        if let Some(fd) = self.inode_map.get(&ino) {
            match self.file_downloader.read_file(&fd.id) {
                Ok(data) => {
                    let offset = if offset >= data.len() as u64 {
                        println!("offset change: {} -> {}", offset, data.len());
                        (data.len() - 1) as u64
                    } else {
                        offset
                    };

                    let real_size: usize = if size as u64 + offset >= data.len() as u64 {
                        (data.len() - offset as usize) as usize
                    } else {
                        size as usize
                    };
                    let d  = data[offset as usize..(offset + real_size as u64) as usize].to_vec();

                    println!("{}", d.len());

                    reply.data(&d);
                    return
                },
                Err(err) => {
                    println!("err when reading file, id: {}: {:?}", ino, err)
                }
            }
        } else {
            println!("no inode found in map, {}", ino);
        }

        reply.error(ENOENT);
    }

    // implement open flags with file handle later
    fn open(&mut self, _req: &Request, ino: u64, flags: u32, reply: ReplyOpen) {
        println!("open(ino={})", ino);

        let uuid = self.conn.query_row_named("SELECT uuid FROM files WHERE ino=:ino"
            , &[( ":ino", &(ino as i64) )]
            , |row| -> Uuid {
                Uuid::from_bytes(&row.get::<i32, Vec<u8>>(0)).unwrap()
            }
        ).unwrap();
        match self.file_downloader.verify_checksum(&uuid, None) {
            Ok(_) => reply.opened(0, flags),
            Err(err) => {
                println!("err in validating checksum of local file, err: {:?}", err);
                reply.error(0)
            }
        }
    }

    fn forget(&mut self, _req: &Request, _ino: u64, _nlookup: u64) {
        println!("forget(ino={})", _ino);
    }
    fn setattr(&mut self, _req: &Request, _ino: u64, _mode: Option<u32>, _uid: Option<u32>, _gid: Option<u32>, _size: Option<u64>, _atime: Option<Timespec>, _mtime: Option<Timespec>, _fh: Option<u64>, _crtime: Option<Timespec>, _chgtime: Option<Timespec>, _bkuptime: Option<Timespec>, _flags: Option<u32>, reply: ReplyAttr) {
        println!("setattr(ino={}, mode={:?}, uid={:?})", _ino, _mode, _uid);
        if let Some(path) = self.inode_map.get(&_ino) {
            let ts = time::now().to_timespec();
            reply.attr(&ts, &path.attr);
            return
        }

        reply.error(ENOENT)
    }
    fn readlink(&mut self, _req: &Request, _ino: u64, reply: ReplyData) { unimplemented!() }
    fn mknod(&mut self, _req: &Request, _parent: u64, _name: &Path, _mode: u32, _rdev: u32, reply: ReplyEntry) {
        println!("mknod(name={:?}, parent={}, mode={})", _name, _parent, _mode);
        reply.error(ENOENT)
    }
    fn mkdir(&mut self, _req: &Request, _parent: u64, _name: &Path, _mode: u32, reply: ReplyEntry) { unimplemented!() }
    fn unlink(&mut self, _req: &Request, _parent: u64, _name: &Path, reply: ReplyEmpty) { unimplemented!() }
    fn rmdir(&mut self, _req: &Request, _parent: u64, _name: &Path, reply: ReplyEmpty) { unimplemented!() }
    fn symlink(&mut self, _req: &Request, _parent: u64, _name: &Path, _link: &Path, reply: ReplyEntry) { unimplemented!() }
    fn rename(&mut self, _req: &Request, _parent: u64, _name: &Path, _newparent: u64, _newname: &Path, reply: ReplyEmpty) { unimplemented!() }
    fn link(&mut self, _req: &Request, _ino: u64, _newparent: u64, _newname: &Path, reply: ReplyEntry) { unimplemented!() }
    fn write(&mut self, _req: &Request, _ino: u64, _fh: u64, _offset: u64, _data: &[u8], _flags: u32, reply: ReplyWrite) {
        println!("write(ino={}, fh={}, offset={}, len={})", _ino, _fh, _offset, _data.len());

        let uuid = self.conn.query_row_named("SELECT uuid FROM files WHERE ino=:ino"
            , &[( ":ino", &(_ino as i64) )]
            , |row| -> Uuid {
                Uuid::from_bytes(&row.get::<i32, Vec<u8>>(0)).unwrap()
            }
        ).unwrap();

        reply.written(self.file_downloader.write_file(&uuid, _data, _offset).unwrap())
    }
    fn flush(&mut self, _req: &Request, _ino: u64, _fh: u64, _lock_owner: u64, reply: ReplyEmpty) {
        println!("flush(ino={}, fh={})", _ino, _fh);

        let uuid = self.conn.query_row_named("SELECT uuid FROM files WHERE ino=:ino"
            , &[( ":ino", &(_ino as i64) )]
            , |row| -> Uuid {
                Uuid::from_bytes(&row.get::<i32, Vec<u8>>(0)).unwrap()
            }
        ).unwrap();

        match self.file_downloader.flush_file(&uuid) {
            Ok(_) => reply.ok(),
            Err(err) => {
                println!("error while flushing {}, {:?}", _ino, err);
                reply.error(-1);
            }
        }
    }
    fn release(&mut self, _req: &Request, _ino: u64, _fh: u64, _flags: u32, _lock_owner: u64, _flush: bool, reply: ReplyEmpty) {
        println!("release(ino={}, fh={}, flush={:?})", _ino, _fh, _flush);

        unsafe {
            let _: File = FromRawFd::from_raw_fd(_fh as i32);
            // when fd goes out of scope, it will close the file?
        }

        reply.ok();
    }
    fn fsync(&mut self, _req: &Request, _ino: u64, _fh: u64, _datasync: bool, reply: ReplyEmpty) { unimplemented!() }
    fn opendir(&mut self, _req: &Request, ino: u64, _flags: u32, reply: ReplyOpen) {
        println!("opendir(ino={})", ino);

        if ino == 1 {
            match File::open("random asas place") {
                Ok(handle) => {
                    let h = handle.into_raw_fd();
                    reply.opened(h as u64, _flags);
                    return
                }
                Err(_) => { }
            }
        }

        if let Some(fd) = self.inode_map.get(&ino) {
            match File::open(&fd.path) {
                Ok(handle) => {
                    let h = handle.into_raw_fd();
                    reply.opened(h as u64, _flags);
                    return
                }
                Err(error) => {
                    //println!("no downloaded folder for {}, err: {:?}", fd.path.to_string_lossy(), error);
                }
            }
        } else {
            println!("no inode found in map, {}", ino);
        }

//         reply.error(ENOENT);
        reply.opened(0, _flags)
    }

    fn releasedir(&mut self, _req: &Request, _ino: u64, _fh: u64, _flags: u32, reply: ReplyEmpty) {
        println!("releasedir(ino={}, fh={})", _ino, _fh);

        unsafe {
            let _: File = FromRawFd::from_raw_fd(_fh as i32);
            // when fd goes out of scope, it will close the file?
        }

        reply.ok()
    }
    fn fsyncdir(&mut self, _req: &Request, _ino: u64, _fh: u64, _datasync: bool, reply: ReplyEmpty) { unimplemented!() }
    fn statfs(&mut self, _req: &Request, _ino: u64, reply: ReplyStatfs) {
        println!("statfs(ino={})", _ino);
        reply.error(ENOENT)
    }
    fn setxattr(&mut self, _req: &Request, _ino: u64, _name: &OsStr, _value: &[u8], _flags: u32, _position: u32, reply: ReplyEmpty) { unimplemented!() }
    fn getxattr(&mut self, _req: &Request, _ino: u64, _name: &OsStr, reply: ReplyData) {
        println!("getxattr(ino={}, name={:?})", _ino, _name);
    }
    fn listxattr(&mut self, _req: &Request, _ino: u64, reply: ReplyEmpty) { unimplemented!() }
    fn removexattr(&mut self, _req: &Request, _ino: u64, _name: &OsStr, reply: ReplyEmpty) { unimplemented!() }
    fn access(&mut self, _req: &Request, _ino: u64, _mask: u32, reply: ReplyEmpty) {
        println!("access(ino={})", _ino);
        if self.inode_map.contains_key(&_ino) {
            reply.ok()
        } else {
            reply.error(ENOENT)
        }
    }
    fn create(&mut self, _req: &Request, parent_inode: u64, _name: &Path, _mode: u32, _flags: u32, reply: ReplyCreate) {
        println!("create(name{:?}, parent={}, mode={}, flags={})", _name, parent_inode, _mode, _flags);

        let inode = self.conn.query_row("SELECT MAX(ino) FROM files"
            , &[], |row| -> u64 {
                row.get::<i32, i64>(0) as u64
            }
        ).unwrap() + 1;
        let (parent_uuid, parent_path) = self.conn.query_row_named("SELECT uuid, path FROM files WHERE parent_ino=:parent_ino"
            , &[ (":parent_ino", &(parent_inode as i64)) ]
            , |row| -> (Uuid, String) {
                ( Uuid::from_bytes(&row.get::<i32, Vec<u8>>(0)).unwrap()
                , row.get(1)
                )
            }
        ).unwrap();

        let ts = time::now().to_timespec();
        let uuid = self.file_downloader.create_local_file(&parent_uuid, _name).unwrap();

        let path = Path::new(&(parent_path + &_name.to_str().unwrap())).to_owned();
        let fd = FileData {
            id: uuid,
            parent_inode: parent_inode,
            path: path,
            attr: FileAttr {
                ino: inode,
                size: 0,
                blocks: 0,
                atime: ts,
                mtime: ts,
                ctime: ts,
                crtime: ts,
                kind: FileType::RegularFile,
                perm: 0o777,
                nlink: 0,
                uid: 1000,
                gid: 1000,
                rdev: 0,
                flags: 0,
            },
            source_data: SourceData::CreatedFile,
        };

        self.child_map.entry(parent_inode).or_insert(Vec::new())
            .push(inode);
        self.inode_map.entry(inode).or_insert(fd.clone());
        self.child_map.entry(inode).or_insert(Vec::new());
        self.parent_map.entry(inode).or_insert(parent_inode);

        self.conn.execute("INSERT INTO files (ino, uuid, parent_ino, name, size, kind)
                           VALUES ($1, $2, $3, $4, $5, $6)"
           , &[ &(inode as i64),
                &uuid.clone().as_bytes().to_vec(),
                &(parent_inode as i64),
                &(_name.to_str().expect("nilfalsdfs")),
                &(0 as i64),
              ]
        ).unwrap();

        reply.created(&ts, &fd.attr, fd.attr.ino, 0, 0)
    }
    fn getlk(&mut self, _req: &Request, _ino: u64, _fh: u64, _lock_owner: u64, _start: u64, _end: u64, _typ: u32, _pid: u32, reply: ReplyLock) { unimplemented!() }
    fn setlk(&mut self, _req: &Request, _ino: u64, _fh: u64, _lock_owner: u64, _start: u64, _end: u64, _typ: u32, _pid: u32, _sleep: bool, reply: ReplyEmpty) { unimplemented!() }
    fn bmap(&mut self, _req: &Request, _ino: u64, _blocksize: u32, _idx: u64, reply: ReplyBmap) { unimplemented!() }
}
<file_sep>/src/main.rs
#![allow(non_snake_case)]
#![allow(dead_code)]
#![allow(unused_variables)]

extern crate hyper;
extern crate rustc_serialize;
extern crate driver;
extern crate fuse;
extern crate uuid;
extern crate time;
extern crate rusqlite;

use std::collections::hash_map::HashMap;
use std::path::Path;
use uuid::Uuid;
use fuse::FileAttr;

use driver::types::*;
use driver::filetree::*;
use driver::drive::*;

fn main() {
//    let root_folder = (vec![], "0B7TtU3YsiIjTTS1oUE5wZFpsYVk");
    let root_folder_name = ".drive_files2";
    let root_folder_path = Path::new(root_folder_name);
//    let root_folder_id =  "0B7TtU3YsiIjTWjBOM0YwYkVBa1U";
//    let root_folder_id =  "0B7TtU3YsiIjTaEd3WlVSMGRERlk";
//    let root_folder_id =  "root";
    let root_folder_id = "0B7TtU3YsiIjTeW1vTGc0a1Y1MFE";
    let root_folder_inode = 1;
//    let root_folder = (vec!["rot".to_string()], "0B7TtU3YsiIjTeHJGR1VKMHB3cWs");

    let conn = rusqlite::Connection::open("files.db").unwrap();
    let root_folder_uuid = {
        conn.query_row("SELECT uuid FROM files WHERE ino=1", &[]
        , |row| -> Uuid {
            Uuid::from_bytes(&row.get::<i32, Vec<u8>>(0)).expect("Fdafkn")
        }).unwrap_or(Uuid::new_v4())
    };
    let last_ino = {
        conn.query_row("SELECT ino FROM FILES
                        WHERE ino = (SELECT MAX(ino) FROM files)"
            , &[] , |row| -> u64 { (row.get::<i32, i64>(0) + 1) as u64 }
        ).unwrap_or(root_folder_inode)
    };

    let mut fd = DriveFileDownloader::new(
        root_folder_uuid,
        root_folder_id.to_string(),
        Path::new(root_folder_name).to_owned(),
        rusqlite::Connection::open("drive.db").unwrap()
    ).expect("failure in reading access file");

    let mut ft = FileTree {
        inode_map: HashMap::new(),
        child_map: HashMap::new(),
        parent_map: HashMap::new(),
        current_inode: last_ino,
        file_downloader: &mut fd,
        conn: conn,
    };

    ft.conn.execute("INSERT INTO files (ino, uuid, parent_ino, name, size, kind)
                       VALUES ($1, $2, $3, $4, $5, $6)",
                       &[ &(1 as i64)
                        , &root_folder_uuid.clone().as_bytes().to_vec()
                        , &(1 as i64)
                        , &"root".to_string()
                        , &(0 as i64)
                        , &"directory"
                       ]
    ).unwrap_or(0);

    let ts = time::now().to_timespec();
    ft.inode_map.entry(root_folder_inode).or_insert(FileData {
        id: root_folder_uuid.clone(),
        path: root_folder_path.to_owned(),
        parent_inode: root_folder_inode,
        attr: FileAttr {
            ino: root_folder_inode,
            size: 0,
            blocks: 0,
            atime: ts,
            mtime: ts,
            ctime: ts,
            crtime: ts,
            kind: FileType::Directory,
            perm: 0o777,
            nlink: 0,
            uid: 1000,
            gid: 1000,
            rdev: 0,
            flags: 0,
        },
        source_data: SourceData::CreatedFile,
    });
    ft.child_map.entry(ft.current_inode).or_insert(Vec::new());
    ft.parent_map.entry(ft.current_inode).or_insert(ft.current_inode);
    ft.current_inode += 1;

    ft.get_files(Path::new(""), &root_folder_uuid, root_folder_inode)
        .expect("this shit fucked up");

//    println!("{:?}\n", ft.inode_map);
//    println!("{:?}", ft.child_map);

    fuse::mount(ft, &"root.2", &[]);
}
<file_sep>/src/drive.rs
extern crate uuid;
extern crate std;
extern crate rusqlite;

use std::borrow::Cow;

use url::percent_encoding::{utf8_percent_encode, QUERY_ENCODE_SET};
use time;
use time::{Timespec, Tm};

use std::str;

use hyper::{Client};
use hyper::header::{ContentType, Authorization, Bearer};
use hyper::client::{Body};
use mime::{Mime, TopLevel, SubLevel};

use std::collections::hash_map::HashMap;
use rustc_serialize::json::{Json, ToJson, Decoder, as_pretty_json};
use rustc_serialize::{json, Decodable};
use std::io;
use std::io::SeekFrom;
use std::io::prelude::*;
use std::fs::{File, DirBuilder,OpenOptions};

use crypto::md5::Md5;
use crypto::digest::Digest;

use std::path::{Path, PathBuf};

use uuid::Uuid;

use types::*;
use filetree::*;

pub struct DriveFileDownloader {
    pub client: Client,
    pub auth_data: AuthData,

    uuid_map: HashMap<Uuid, DriveFileResponse>,
    conn: rusqlite::Connection,
}

const CACHE_FILE: &'static str = "access";
const CLIENT_ID: &'static str = "460434421766-0sktb0rkbvbko8omj8vhu8vv83giraao.apps.googleusercontent.com";
const CLIENT_SECRET: &'static str = "<KEY>";

struct DownloadedFileInformation {
    size: u64,
    checksum: String,
    path: PathBuf,
}

impl DriveFileDownloader {
    pub fn new(root_uuid: Uuid, root_id: String, file_path: PathBuf, db_conn: rusqlite::Connection) -> Result<DriveFileDownloader, DriveError> {
        let c = Client::new();

        let mut handle = try!(OpenOptions::new()
                            .read(true)
                            .write(true)
                            .create(true)
                            .open(CACHE_FILE));
        let mut access_string = String::new();
        try!(handle.read_to_string(&mut access_string));
        println!("{}", access_string);
        let tr: TokenResponse = match json::decode(&access_string) {
            Ok(tr) => tr,
            Err(_) => {
                let tr = try!(request_new_access_code(&c));
                println!("{}", tr.clone().to_json().to_string());
                try!(handle.write_all(tr.to_json().pretty().to_string().as_bytes()));
                tr
            }
        };

        db_conn.execute("INSERT INTO files (id, uuid, path)
                         VALUES ($1, $2, $3)"
            , &[ &root_id,
                 &root_uuid.clone().as_bytes().to_vec(),
                 &file_path.to_str().unwrap()
               ]
        ).unwrap_or_else(| err| {
                println!("root probably already in drive db, err: {:?}", err);
                0
            }
        );

        let mut uuid_map = HashMap::new();
        uuid_map.insert(root_uuid, DriveFileResponse {
            kind: "drive#file".to_string(),
            id: root_id.clone(),
            name: "".to_string(),
            mimeType: "application/vnd.google-apps.folder".to_string(),
            parents: vec!(root_id),
            path: Some(file_path),
        });

        Ok(DriveFileDownloader {
            client: c,
            auth_data: AuthData {
                tr: tr,
                client_id: CLIENT_ID.to_string(),
                client_secret: CLIENT_SECRET.to_string(),
                cache_file_path: CACHE_FILE.to_string(),
            },
            uuid_map: uuid_map,
            conn: db_conn,
        })
    }

    fn download_file(&self, uuid: &Uuid, parent_uuid: &Uuid) -> Result<DownloadedFileInformation, DriveError> {
        let fr = try!(self.uuid_map.get(uuid).ok_or(DriveError {
            kind: DriveErrorType::FailedUuidLookup,
            response: None,
        })).clone();
        let parent_path = try!(self.uuid_map.get(parent_uuid).ok_or(DriveError {
            kind: DriveErrorType::FailedUuidLookup,
            response: None,
        })).path.clone();

        if fr.mimeType == "application/vnd.google-apps.document"
        || fr.mimeType == "application/vnd.google-apps.form"
        || fr.mimeType == "application/vnd.google-apps.drawing"
        || fr.mimeType == "application/vnd.google-apps.fusiontable"
        || fr.mimeType == "application/vnd.google-apps.map"
        || fr.mimeType == "application/vnd.google-apps.presentation"
        || fr.mimeType == "application/vnd.google-apps.spreadsheet"
        || fr.mimeType == "application/vnd.google-apps.sites" {
            println!("unsupported google filetype");
            return Err(DriveError {
                kind: DriveErrorType::UnsupportedDocumentType,
                response: None
            })
        }

        let mut file_path = try!(parent_path.ok_or(DriveError {
            kind: DriveErrorType::NoPathForParent,
            response: None,
        }));
        file_path.push(fr.name.clone());

        // we'll checksum the file (if we have it) on the system, and compare it to the
        // server, if all is OK, create a new metadata file
        let (maybe_checksum, maybe_path) = try!(self.conn.query_row_named("SELECT checksum, path FROM files
                                                                           WHERE uuid=:uuid"
            , &[(":uuid", &uuid.clone().as_bytes().to_vec())]
            , |row| -> (Option<String>, Option<PathBuf>) {
                ( row.get(0)
                , if let Some(path) = row.get::<i32, Option<String>>(1) {
                    Some(Path::new(&path).to_owned())
                } else { None } )
            }
        ));

        let fn_download_file = |file_path: PathBuf| {
            // the file data doesn't yet exist, so we'll download it from scratch
            println!("downloading new file, creating new file: {:?}", file_path);

            let mut f = try!(File::create(file_path.clone()));
            let mut resp = try!(self.client.get(&format!("https://www.googleapis.com/drive/v3/files/{}\
                        ?alt=media", fr.id.clone()))
                                 .header(Authorization(Bearer{token: self.auth_data.tr.access_token.clone()}))
                                 .send());

            let check_response = try!(self.verify_checksum(uuid, None));
            let size = check_response.size;

            println!("md5: {}, size: {}", check_response.md5Checksum, size);
            self.conn.execute("UPDATE files
                               SET checksum=$1, size=$2
                               WHERE uuid=$3",
                            &[ &check_response.md5Checksum,
                               &(check_response.size as i64),
                               &uuid.clone().as_bytes().to_vec(),
                             ]).unwrap();

            Ok(DownloadedFileInformation {
                size: size,
                checksum: check_response.md5Checksum,
                path: file_path,
            })
        };

        if let Some(checksum) = maybe_checksum {
            // if the checksum matches that from Drive, then file is downloaded
            // correctly, and all we need to do is cache the checksum
            self.verify_checksum(uuid, Some(&checksum))
            .and_then(|check_response| {
                Ok(DownloadedFileInformation {
                    size: check_response.size,
                    path: file_path.clone(),
                    checksum: checksum,
                })
            }).or_else(|_| {
                fn_download_file(file_path.clone())
            })
        } else if let Some(path) = maybe_path {
            // if we have a path for the file, we can chcek to see if any local data is
            // already valid
            get_file_checksum(&path).and_then(|ck| {
                // check with Drive for a the valid checksum
                self.verify_checksum(uuid, Some(&ck))
                .and_then(|check_response| {
                    Ok(DownloadedFileInformation {
                        size: check_response.size,
                        path: file_path.clone(),
                        checksum: ck,
                    })
                })
            }).or_else(|_| {
                fn_download_file(file_path.clone())
            })
        } else {
            // we have neither a path for local data, nor a local checksum
            fn_download_file(file_path.clone())
        }
    }
}

define_encode_set! {
    /// This encode set is used in the URL parser for query strings.
    pub DRIVE_QUERY_ENCODE_SET = [QUERY_ENCODE_SET] | {':'}
}

impl FileDownloader for DriveFileDownloader {
    fn get_file_list(&mut self, root_folder_uuid: &uuid::Uuid) -> Result<FileUpdates, DriveError> {
        let uuid_vec = root_folder_uuid.clone().as_bytes().to_vec();
        let (parent_id, parent_path) = try!(self.conn.query_row_named("SELECT id, path FROM files WHERE uuid=:uuid"
            , &[(":uuid", &uuid_vec)]
            , |row| -> (String, PathBuf) {
                ( row.get(0)
                , Path::new(&row.get::<i32, String>(1)).to_owned()
                )
            }
        ));
        println!("getting file list for parent ID: {}", parent_id);

        let lastdate = self.conn.query_row_named("SELECT MAX(last_update) FROM meta
                                                  WHERE uuid = :uuid"
            , &[(":uuid", &uuid_vec)]
            , |row| -> Timespec { row.get(0) }
        ).unwrap_or(Timespec::new(0,0));
        println!("{:?}", convert_timespec_to_tm(lastdate));

        // date from which modified files should be updated
        // older ones should be locally valid
        let lastdate = format!("{}", convert_timespec_to_tm(lastdate).rfc3339());
        let lastdate_encoded = utf8_percent_encode(&lastdate, DRIVE_QUERY_ENCODE_SET{});

        let query = format!("https://www.googleapis.com/drive/v3/files\
                                ?corpus=domain\
                                &pageSize=1000\
                                &fields=files\
                                &q=%27{}%27+in+parents\
                                +and+modifiedTime%3E'{}'\
                                +and+trashed+%3D+"
                                , parent_id
                                , lastdate_encoded);
        println!("{}", query);
        let new_resp = {
            println!("{}", parent_id);
            try!(self.client.get(&(query.clone()+"false"))
                            .header(Authorization(Bearer{token: self.auth_data.tr.access_token.clone()}))
                            .send())
        };
        let del_resp = {
            println!("{}", parent_id);
            try!(self.client.get(&(query+"true"))
                            .header(Authorization(Bearer{token: self.auth_data.tr.access_token.clone()}))
                            .send())
        };

        let mut resps = vec!(new_resp, del_resp);
        let mut files = vec!(Vec::new(), Vec::new());
        for (resp, files_list) in resps.iter_mut().zip(files.iter_mut()) {

            // convert the response to a string, then to a JSON object
            let mut resp_string = String::new();
            try!(resp.read_to_string(&mut resp_string));
            println!("{}", resp_string);
            let fr_obj = try!((Json::from_str(&resp_string)).map_err(From::from)
                .and_then(|fr_data: Json| -> Result<json::Object, DriveError> {
                    fr_data.into_object()
                    .ok_or(DriveError {
                        kind: DriveErrorType::JsonObjectify,
                        response: Some(resp_string.clone())
                    })
                }).or_else(|err| {
                    println!("there's probably something wrong with the get_file_list response, err: {:?}", err);
                    Err(err)
                })
            );

            //println!("{}", resp_string);

            let files = try!(fr_obj.get("files")
                                   .ok_or(DriveError {
                                        kind: DriveErrorType::JsonInvalidAttribute,
                                        response: Some(resp_string.clone())
                                    }));
            let files_array = try!(files.as_array()
                                        .ok_or(DriveError {
                                            kind: DriveErrorType::JsonCannotConvertToArray,
                                            response: Some(resp_string.clone())
                                        }));

            for i in files_array.into_iter() {
                // we'll try to decode each file's metadata JSON object in memory to a DriveFileResponse struct
                let mut decoder = Decoder::new(i.clone());
                let fr: DriveFileResponse = try!(Decodable::decode(&mut decoder));

                let kind = if fr.mimeType == "application/vnd.google-apps.folder" {
                    FileType::Directory
                } else {
                    FileType::RegularFile
                };

                let mut path = parent_path.clone();
                path.push(fr.name.clone());


                let uuid = self.conn.query_row_named("SELECT uuid FROM files WHERE id=:id"
                    , &[(":id", &fr.id)]
                    , |row| -> Uuid {
                        Uuid::from_bytes(&row.get::<i32, Vec<u8>>(0)).expect("failed to parse Uuid from drive db storage")
                    }
                ).and_then(|uuid| -> Result<Uuid, rusqlite::Error> {
                    self.conn.execute("UPDATE files
                                       SET path=$1, mimetype=$2
                                       WHERE uuid=$3"
                        , &[ &(path.to_str().expect("nilfalsdfs"))
                           , &fr.mimeType
                           , &uuid.clone().as_bytes().to_vec()
                           ]
                    ).unwrap_or_else(|err| {
                        println!("couldn't update file in drive db, err: {:?}", err);
                        0
                    });

                    Ok(uuid)
                }).unwrap_or_else(|_| {
                    let uuid = Uuid::new_v4();
                    self.conn.execute("INSERT INTO files (uuid, id, mimetype, path)
                                       VALUES ($1, $2, $3, $4)"
                        , &[ &uuid.clone().as_bytes().to_vec()
                           , &fr.id
                           , &fr.mimeType
                           , &(path.to_str().expect("fadsfnjfsad"))
                           ]
                    ).unwrap_or_else(|_| {
                        println!("file already in drive db: {}", fr.name);
                        0
                    });

                    uuid
                });

                {
                    self.uuid_map.insert(uuid, fr.clone());
                }

                assert!(fr.parents.len() == 1);
                let parent_uuid = self.conn.query_row_named("SELECT uuid FROM files WHERE id=:id"
                    , &[( ":id", &fr.parents[0] )]
                    , |row| -> Uuid {
                        Uuid::from_bytes(&row.get::<i32, Vec<u8>>(0)).expect("failed to parse parent Uuid from drive db storage")
                    }
                ).unwrap();

    //            println!("drive adding path: {:?} {:?}", uuid.clone().as_bytes().to_vec(), path);
                files_list.push(FileResponse {
                    uuid: uuid,
                    parent_uuid: parent_uuid,
                    kind: kind,
                    name: fr.name.clone(),
                    source_data: SourceData::Drive(fr)
                });
            }

            try!(self.conn.execute("INSERT INTO meta (uuid, last_update, num_files_updated)
                                    VALUES ($1, $2, $3)",
                                 &[ &uuid_vec,
                                    &time::now().to_timespec(),
                                    &(files_list.len() as i64)
                                  ]
            ));
        }

        for ref fr in &files[1] {
            self.conn.execute("DELETE FROM files WHERE uuid=:uuid"
                , &[ &fr.uuid.clone().as_bytes().to_vec() ]
            ).unwrap_or_else(|err| {
                println!("couldn't delte file: {}, err: {:?}", fr.name, err);
                0
            });
        }

        Ok(FileUpdates{
            new_files: Some(files[0].clone()),
            deleted_files: Some(files[1].clone())
        })
    }

    fn retreive_file(&mut self, uuid: &Uuid, parent_uuid: &Uuid) -> Result<u64, DriveError> {
        let fr = try!(self.uuid_map.get(uuid).ok_or(DriveError {
            kind: DriveErrorType::FailedUuidLookup,
            response: None,
        })).clone();
        let parent_path = try!(self.uuid_map.get(parent_uuid).ok_or(DriveError {
            kind: DriveErrorType::FailedUuidLookup,
            response: None,
        })).path.clone();

        let mut file_path = try!(parent_path.ok_or(DriveError {
            kind: DriveErrorType::NoPathForParent,
            response: None,
        }));
        file_path.push(fr.name.clone());

//        let (path, mimeType) = try!(self.conn.query_row_named("SELECT path, mimetype FROM files WHERE uuid=:uuid"
//            , &[(":uuid", &uuid.clone().as_bytes().to_vec())]
//            , |row| -> (Option<PathBuf>, Option<String>)
//        ));

        {
            let fr = self.uuid_map.get_mut(uuid).unwrap();
            fr.path = Some(file_path.clone());
            if fr.mimeType == "application/vnd.google-apps.folder" {
                let mut dir_builder = DirBuilder::new();
                dir_builder.recursive(true);
                // create the directory in the system filesystem
                try!(dir_builder.create(&file_path.clone()));
                return Ok(0)
            }
        }

        let (id, maybe_checksum) = try!(self.conn.query_row_named("SELECT id, checksum FROM files WHERE uuid=:uuid"
            , &[(":uuid", &uuid.clone().as_bytes().to_vec())]
            , |row| -> (String, Option<String>) {
                (row.get(0), row.get(1))
            }
        ));
        println!("{:?}, {:?}", id, maybe_checksum);

        let info = if let Some(checksum) = maybe_checksum {
            try!(self.verify_checksum(uuid, Some(&checksum))
            .or_else(|_| -> Result<FileCheckResponse, DriveError> {
                // if the checksum fails, we need to redownload it
                println!("updating metadata for {:?}", file_path);
                let dfi = try!(self.download_file(uuid, parent_uuid));

                self.conn.execute("UPDATE files
                                   SET checksum=$1, size=$2
                                   WHERE uuid=$3",
                                &[ &dfi.checksum,
                                   &(dfi.size as i64),
                                   &uuid.clone().as_bytes().to_vec(),
                                 ]).unwrap();

                self.verify_checksum(uuid, Some(&dfi.checksum))
            }))
        } else {
            // if the checksum fails, we need to redownload it
            println!("updating metadata for {:?}", file_path);
            let dfi = try!(self.download_file(uuid, parent_uuid));

            self.conn.execute("UPDATE files
                               SET checksum=$1, size=$2
                               WHERE uuid=$3",
                            &[ &dfi.checksum,
                               &(dfi.size as i64),
                               &uuid.clone().as_bytes().to_vec(),
                             ]).unwrap();

            try!(self.verify_checksum(uuid, Some(&dfi.checksum)))
        };

        println!("shpu;d ne updating");

        Ok(info.size)
    }

    fn create_local_file(&mut self, parent_uuid: &Uuid, name: &Path) -> Result<Uuid, DriveError> {
        let parent_path = self.conn.query_row_named("SELECT path FROM files WHERE uuid=:uuid"
            , &[ (":uuid", &parent_uuid.as_bytes().to_vec()) ]
            , |row| -> String {
                row.get(0)
            }
        ).unwrap();
        let file_path = parent_path + &name.to_str().unwrap();

        try!(File::create(&file_path));
        let uuid = Uuid::new_v4();

        let id_from_drive = String::new();

        self.conn.execute("INSERT INTO files (id, uuid, path)
                           VALUES ($1, $2, $3)"
            , &[ &id_from_drive,
                 &uuid.clone().as_bytes().to_vec(),
                 &file_path
               ]
        ).unwrap();

        Ok(uuid)
    }

    fn read_file(&self, uuid: &Uuid) -> Result<Vec<u8>, DriveError> {
        let path = self.conn.query_row_named("SELECT path FROM files WHERE uuid=:uuid",
            &[(":uuid", &uuid.clone().as_bytes().to_vec())]
            , |row| -> String { row.get(0) }
        ).expect("failure in retrieve_file sql");

        let mut handle = try!(File::open(&path));
        let mut data = Vec::<u8>::new();
        match handle.read_to_end(&mut data) {
            Ok(_) => (),
            Err(error) => println!("couldnt read file handle, {}: error, {}", path, error),
        };

        Ok(data)
    }

    fn write_file(&self, uuid: &Uuid, data: &[u8], offset: u64) -> Result<u32, DriveError> {
        let path = self.conn.query_row_named("SELECT path FROM files WHERE uuid=:uuid"
            , &[( ":uuid", &uuid.clone().as_bytes().to_vec() )]
            , |row| -> String {
                row.get(0)
            }
        ).unwrap();

        let mut fh = OpenOptions::new()
            .write(true)
            .truncate(false)
            .create(false)
            .open(path)
            .unwrap();
        try!(fh.seek(SeekFrom::Start(offset)));
        try!(fh.write_all(data));
        try!(fh.set_len(offset+(data.len() as u64)));

        Ok(data.len() as u32)
    }

    fn flush_file(&self, uuid: &Uuid) -> Result<(), DriveError> {
        let (fid, path) = self.conn.query_row_named("SELECT id, path FROM files WHERE uuid=:uuid"
            , &[( ":uuid", &uuid.clone().as_bytes().to_vec() )]
            , |row| -> (String, String) {
                (row.get(0),
                 row.get(1)
                )
            }
        ).unwrap();

        let mut fh = OpenOptions::new()
            .read(true)
            .write(false)
            .open(path)
            .unwrap();
        let mut data = Vec::<u8>::new();
        try!(fh.read_to_end(&mut data));

        let resp = try!(self.client
            .patch(&format!("https://www.googleapis.com/upload/drive/v3/files/{}", fid))
            .body(&data as &[u8])
            .header(Authorization(Bearer{token: self.auth_data.tr.access_token.clone()}))
            .send());

        let fcr = try!(self.verify_checksum(&uuid, None));
        self.conn.execute("UPDATE files
                           SET checksum=$1, size=$2
                           WHERE uuid=$3",
            &[ &fcr.md5Checksum,
               &(fcr.size as i64),
               &uuid.clone().as_bytes().to_vec(),
             ]
         ).unwrap();

        Ok(())
    }

    fn verify_checksum<'a>(&self, uuid: &Uuid, checksum: Option<&'a str>) -> Result<FileCheckResponse, DriveError> {
        let (fid, path) = self.conn.query_row_named("SELECT id, path FROM files WHERE uuid=:uuid"
            , &[( ":uuid", &uuid.clone().as_bytes().to_vec() )]
            , |row| -> (String, String) {
                (row.get(0),
                 row.get(1)
                )
            }
        ).unwrap();

        let checksum: Cow<'a, str> = match checksum {
            Some(sum) => Cow::Borrowed(sum),
            None => {
                let mut fh = try!(File::open(&path));
                let mut file_string = Vec::<u8>::new();
                try!(fh.read_to_end(&mut file_string));

                Cow::Owned({
                    let mut md5 = Md5::new();
                    md5.input(&file_string);
                    md5.result_str()
                })
            }
        };

        let mut resp = try!(self.client
            .get(&format!(
                "https://www.googleapis.com/drive/v3/files/{}\
                ?fields=md5Checksum%2Csize"
                , fid.clone()))
            .header(Authorization(Bearer{token: self.auth_data.tr.access_token.clone()}))
            .send());

        let mut resp_string = String::new();
        try!(resp.read_to_string(&mut resp_string));
        let fcr: FileCheckResponse = try!(json::decode(&resp_string));
        let same = &checksum == &fcr.md5Checksum;
        if !same {
            println!("{} =? {}", checksum, fcr.md5Checksum);
            println!("same?: {:?}", same);
            println!("size: {}", fcr.size);
            return Err(DriveError {
                kind: DriveErrorType::FailedChecksum,
                response: Some(resp_string)
            })
        }

        Ok(fcr)
    }

    fn resolve_error(&mut self, resp_string: &str) -> Result<(), DriveError> {
        println!("attempting to resolve error response: {}", resp_string);

        let err_data = try!(Json::from_str(&resp_string));
        let err_obj  = try!(err_data.as_object()
                                    .ok_or(DriveError {
                                        kind: DriveErrorType::JsonObjectify,
                                        response: Some(resp_string.to_string())
                                    }));

        let error = try!(err_obj.get("error")
                                .ok_or(DriveError {
                                    kind: DriveErrorType::JsonInvalidAttribute,
                                    response: Some(resp_string.to_string())
                                }));
        let errors = try!(error.as_object()
                                    .ok_or(DriveError {
                                        kind: DriveErrorType::JsonObjectify,
                                        response: Some(resp_string.to_string())
                                    })
                                .and_then(|err_obj| err_obj.get("errors")
                                    .ok_or(DriveError {
                                        kind: DriveErrorType::JsonInvalidAttribute,
                                        response: Some(resp_string.to_string())
                                    }))
                                .and_then(|errors| errors.as_array()
                                    .ok_or(DriveError {
                                        kind: DriveErrorType::JsonInvalidAttribute,
                                            response: Some(resp_string.to_string())
                                    })));
        for i in errors {
            let mut decoder = Decoder::new(i.clone());
            let err: ErrorDetailsResponse = match Decodable::decode(&mut decoder) {
                Ok(err) => err,
                Err(error) => {
                    println!("could not decode errorDetailsResponse, error: {}, attempted edr: {}", error, i);
                    return Err(From::from(error))
                }
            };

            if err.reason   == "authError"           &&
               err.message  == "Invalid Credentials" {
                let mut resp = try!(self.client.post("https://www.googleapis.com/oauth2/v3/token")
                                      .header(ContentType(Mime(TopLevel::Application, SubLevel::WwwFormUrlEncoded, vec![])))
                                      //.header(Host{hostname: "www.googleapis.com".to_owned(), port: None})
                                      .body(&format!("&client_id={}\
                                            &client_secret={}\
                                            &refresh_token={}\
                                            &grant_type=refresh_token", self.auth_data.client_id, self.auth_data.client_secret, self.auth_data.tr.refresh_token))
                                      .send());

                self.auth_data.tr.access_token = {
                    let mut ref_string = String::new();
                    try!(resp.read_to_string(&mut ref_string));
                    let ref_data = try!(Json::from_str(&ref_string));
                    let ref_obj  = try!(ref_data.as_object()
                                                .ok_or(DriveError {
                                                    kind: DriveErrorType::JsonObjectify,
                                                    response: Some(ref_string.clone())
                                                }));
                    try!(ref_obj.get("access_token")
                                .ok_or(DriveError {
                                    kind: DriveErrorType::JsonInvalidAttribute,
                                    response: Some(ref_string.clone())
                                })
                                .and_then(|acc| {
                                    acc.as_string()
                                       .ok_or(DriveError {
                                           kind: DriveErrorType::JsonInvalidAttribute,
                                           response: Some(ref_string)
                                       })
                                })).to_string()
                };

                // we'll open our access_cache file to read its current contents
                let mut f = try!(File::open(self.auth_data.cache_file_path.clone()));
                let mut access_string = String::new();
                try!(f.read_to_string(&mut access_string).map_err(From::from).and_then(|_| -> Result<(), DriveError> {
                    // if the current access file reads as it should, we'll copy the
                    // current token response and edit the   access_token field for later use
                    let mut tr: TokenResponse = try!(json::decode(&access_string));
                    tr.access_token = self.auth_data.tr.access_token.clone();
                    let tr_json = tr.to_json();
                    let tr_str = format!("{}", as_pretty_json(&tr_json));

                    // then we'll truncate the file and paste in the updated token response
                    // preserving all the other unused data
                    let mut f: File = try!(File::create(self.auth_data.cache_file_path.clone()).map_err(From::from) as Result<File, DriveError>);
                    f.write_all(tr_str.as_bytes()).map_err(From::from)
                }))
            } else if err.reason  == "userRateLimitExceeded" &&
                      err.message ==  "User Rate Limit Exceeded" {
                          ()
            }
        }

        // for loop returns (), so a value for the function is needed
        Ok(())
    }
}

pub fn request_new_access_code(c: &Client) -> Result<TokenResponse, DriveError> {
    // the space after client_id={} is necessary to seperate the link from the rest of the
    // prompt
    println!("Visit https://accounts.google.com/o/oauth2/v2/auth\
                    ?scope=email%20profile%20https://www.googleapis.com/auth/drive\
                    &redirect_uri=urn:ietf:wg:oauth:2.0:oob\
                    &response_type=code\
                    &client_id={} \
             to receive the access code.", CLIENT_ID);
    let mut code_string = String::new();
    try!(io::stdin().read_line(&mut code_string));

    let mut resp = c.post("https://accounts.google.com/o/oauth2/token")
        .header(ContentType(Mime(TopLevel::Application, SubLevel::WwwFormUrlEncoded, vec![])))
        .body(&format!("code={}\
               &client_id={}\
               &client_secret={}\
               &redirect_uri=urn:ietf:wg:oauth:2.0:oob\
               &grant_type=authorization_code"
               , code_string, CLIENT_ID, CLIENT_SECRET))
        .send()
        .unwrap();
    print!("{}\n{}\n{}\n\n", resp.url, resp.status, resp.headers);

    let mut resp_string = String::new();
    try!(resp.read_to_string(&mut resp_string));
    json::decode(&resp_string).map_err(From::from)
}

pub fn convert_timespec_to_tm(ts: Timespec) -> Tm {
    let time_duration = ts - Timespec::new(0,0);
    Tm {
        tm_sec:    0,
        tm_min:    0,
        tm_hour:   0,
        tm_mday:   1, // days of the month start at 1, not 0
        tm_mon:    1,
        tm_year:   70, // for difference b/w UNIX epoch and 1900
        tm_wday:   0,
        tm_yday:   0,
        tm_isdst:  0,
        tm_utcoff: 0,
        tm_nsec:   0,
    } + time_duration
}
<file_sep>/Cargo.toml
[package]
name = "driver"
version = "0.1.0"
authors = ["<NAME> <<EMAIL>>"]

[dependencies]
hyper           = "0.9.6"
mime            = "0.2.0"
itertools       = "0.4"
rust-crypto     = "^0.2"
fuse            = "0.2.7"
time            = "0.1.35"
libc            = "0.2.11"
rusqlite        = "0.7.3"

[dependencies.url]
git = "https://github.com/servo/rust-url"

[dependencies.rustc-serialize]
git = "https://github.com/rust-lang-nursery/rustc-serialize"

[dependencies.uuid]
version = "0.2"
features = ["v4"]
<file_sep>/README.md
tool to syncronize Google drive via a FUSE filesystem
<file_sep>/src/lib.rs
extern crate hyper;
extern crate rustc_serialize;
extern crate fuse;
extern crate libc;
extern crate time;
extern crate itertools;
extern crate mime;
extern crate crypto;
extern crate uuid;
extern crate rusqlite;
#[macro_use] extern crate url;

pub mod types;
pub mod fs;
pub mod filetree;
pub mod drive;
