files.rs 4.4 KB
Newer Older
B
Bartek Iwańczuk 已提交
1
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
B
Bartek Iwańczuk 已提交
2
use super::dispatch_json::{Deserialize, JsonOp, Value};
3
use crate::deno_error::bad_resource;
4 5
use crate::deno_error::DenoError;
use crate::deno_error::ErrorKind;
B
Bartek Iwańczuk 已提交
6
use crate::fs as deno_fs;
7
use crate::ops::json_op;
8 9
use crate::resources;
use crate::resources::CliResource;
B
Bartek Iwańczuk 已提交
10 11 12
use crate::state::ThreadSafeState;
use deno::*;
use futures::Future;
13
use futures::Poll;
B
Bartek Iwańczuk 已提交
14 15
use std;
use std::convert::From;
16
use std::io::SeekFrom;
B
Bartek Iwańczuk 已提交
17 18
use tokio;

19 20 21 22 23 24
pub fn init(i: &mut Isolate, s: &ThreadSafeState) {
  i.register_op("open", s.core_op(json_op(s.stateful_op(op_open))));
  i.register_op("close", s.core_op(json_op(s.stateful_op(op_close))));
  i.register_op("seek", s.core_op(json_op(s.stateful_op(op_seek))));
}

B
Bartek Iwańczuk 已提交
25 26 27 28 29 30 31 32
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct OpenArgs {
  promise_id: Option<u64>,
  filename: String,
  mode: String,
}

33
fn op_open(
B
Bartek Iwańczuk 已提交
34
  state: &ThreadSafeState,
B
Bartek Iwańczuk 已提交
35 36 37 38 39 40
  args: Value,
  _zero_copy: Option<PinnedBuf>,
) -> Result<JsonOp, ErrBox> {
  let args: OpenArgs = serde_json::from_value(args)?;
  let (filename, filename_) = deno_fs::resolve_from_cwd(&args.filename)?;
  let mode = args.mode.as_ref();
41

B
Bartek Iwańczuk 已提交
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
  let mut open_options = tokio::fs::OpenOptions::new();

  match mode {
    "r" => {
      open_options.read(true);
    }
    "r+" => {
      open_options.read(true).write(true);
    }
    "w" => {
      open_options.create(true).write(true).truncate(true);
    }
    "w+" => {
      open_options
        .read(true)
        .create(true)
        .write(true)
        .truncate(true);
    }
    "a" => {
      open_options.create(true).append(true);
    }
    "a+" => {
      open_options.read(true).create(true).append(true);
    }
    "x" => {
      open_options.create_new(true).write(true);
    }
    "x+" => {
      open_options.create_new(true).read(true).write(true);
    }
    &_ => {
      panic!("Unknown file open mode.");
    }
  }

  match mode {
    "r" => {
      state.check_read(&filename_)?;
    }
    "w" | "a" | "x" => {
      state.check_write(&filename_)?;
    }
    &_ => {
      state.check_read(&filename_)?;
      state.check_write(&filename_)?;
    }
  }

B
Bartek Iwańczuk 已提交
91
  let is_sync = args.promise_id.is_none();
B
Bartek Iwańczuk 已提交
92 93
  let op = open_options.open(filename).map_err(ErrBox::from).and_then(
    move |fs_file| {
94
      let rid = resources::add_fs_file(fs_file);
95
      futures::future::ok(json!(rid))
B
Bartek Iwańczuk 已提交
96 97
    },
  );
B
Bartek Iwańczuk 已提交
98 99

  if is_sync {
B
Bartek Iwańczuk 已提交
100
    let buf = op.wait()?;
B
Bartek Iwańczuk 已提交
101
    Ok(JsonOp::Sync(buf))
B
Bartek Iwańczuk 已提交
102
  } else {
B
Bartek Iwańczuk 已提交
103
    Ok(JsonOp::Async(Box::new(op)))
B
Bartek Iwańczuk 已提交
104 105 106
  }
}

B
Bartek Iwańczuk 已提交
107 108 109 110 111
#[derive(Deserialize)]
struct CloseArgs {
  rid: i32,
}

112
fn op_close(
113
  _state: &ThreadSafeState,
B
Bartek Iwańczuk 已提交
114 115 116 117 118
  args: Value,
  _zero_copy: Option<PinnedBuf>,
) -> Result<JsonOp, ErrBox> {
  let args: CloseArgs = serde_json::from_value(args)?;

119
  let mut table = resources::lock_resource_table();
120
  table.close(args.rid as u32).ok_or_else(bad_resource)?;
121
  Ok(JsonOp::Sync(json!({})))
B
Bartek Iwańczuk 已提交
122 123
}

124
#[derive(Debug)]
125 126 127 128 129 130 131 132 133 134
pub struct SeekFuture {
  seek_from: SeekFrom,
  rid: ResourceId,
}

impl Future for SeekFuture {
  type Item = u64;
  type Error = ErrBox;

  fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
135
    let mut table = resources::lock_resource_table();
136
    let resource = table
137
      .get_mut::<CliResource>(self.rid)
138 139 140
      .ok_or_else(bad_resource)?;

    let tokio_file = match resource {
141
      CliResource::FsFile(ref mut file) => file,
142 143 144 145 146 147 148
      _ => return Err(bad_resource()),
    };

    tokio_file.poll_seek(self.seek_from).map_err(ErrBox::from)
  }
}

B
Bartek Iwańczuk 已提交
149 150 151 152 153 154 155 156 157
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct SeekArgs {
  promise_id: Option<u64>,
  rid: i32,
  offset: i32,
  whence: i32,
}

158
fn op_seek(
159
  _state: &ThreadSafeState,
B
Bartek Iwańczuk 已提交
160 161 162 163
  args: Value,
  _zero_copy: Option<PinnedBuf>,
) -> Result<JsonOp, ErrBox> {
  let args: SeekArgs = serde_json::from_value(args)?;
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
  let rid = args.rid as u32;
  let offset = args.offset;
  let whence = args.whence as u32;
  // Translate seek mode to Rust repr.
  let seek_from = match whence {
    0 => SeekFrom::Start(offset as u64),
    1 => SeekFrom::Current(i64::from(offset)),
    2 => SeekFrom::End(i64::from(offset)),
    _ => {
      return Err(ErrBox::from(DenoError::new(
        ErrorKind::InvalidSeekMode,
        format!("Invalid seek mode: {}", whence),
      )));
    }
  };

180
  let fut = SeekFuture { seek_from, rid };
B
Bartek Iwańczuk 已提交
181

182
  let op = fut.and_then(move |_| futures::future::ok(json!({})));
183 184 185 186 187
  if args.promise_id.is_none() {
    let buf = op.wait()?;
    Ok(JsonOp::Sync(buf))
  } else {
    Ok(JsonOp::Async(Box::new(op)))
B
Bartek Iwańczuk 已提交
188 189
  }
}