1ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <errno.h>
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <fcntl.h>
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <pthread.h>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <sys/stat.h>
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <map>
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <string>
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "nacl_io/kernel_handle.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "nacl_io/kernel_object.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "nacl_io/mount.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "nacl_io/path.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "gtest/gtest.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochusing namespace nacl_io;
21ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass MountNodeRefMock : public MountNode {
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  MountNodeRefMock(Mount* mnt) : MountNode(mnt) {}
27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass MountRefMock : public Mount {
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public:
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  MountRefMock() {}
32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ~MountRefMock() {}
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Error Access(const Path& path, int a_mode) { return ENOSYS; }
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Error Open(const Path& path, int mode, ScopedMountNode* out_node) {
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    out_node->reset(NULL);
38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return ENOSYS;
39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Error Unlink(const Path& path) { return 0; }
41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Error Mkdir(const Path& path, int permissions) { return 0; }
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Error Rmdir(const Path& path) { return 0; }
43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Error Remove(const Path& path) { return 0; }
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class KernelHandleRefMock : public KernelHandle {
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  KernelHandleRefMock(const ScopedMount& mnt, const ScopedMountNode& node)
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      : KernelHandle(mnt, node) {}
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ~KernelHandleRefMock() {}
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class KernelObjectTest : public ::testing::Test {
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  KernelObjectTest() {
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    proxy = new KernelObject;
58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    mnt.reset(new MountRefMock());
59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    node.reset(new MountNodeRefMock(mnt.get()));
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ~KernelObjectTest() {
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // mnt is ref-counted, it doesn't need to be explicitly deleted.
64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    node.reset(NULL);
65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    mnt.reset(NULL);
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delete proxy;
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  KernelObject* proxy;
70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ScopedMount mnt;
71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ScopedMountNode node;
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <nacl_io/mount_mem.h>
77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <nacl_io/mount_http.h>
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochTEST_F(KernelObjectTest, Referencing) {
80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // The mount and node should have 1 ref count at this point
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(1, mnt->RefCount());
82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(1, node->RefCount());
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Pass the mount and node into a KernelHandle
85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  KernelHandle* raw_handle = new KernelHandleRefMock(mnt, node);
86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ScopedKernelHandle handle_a(raw_handle);
87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // The mount and node should have 1 ref count at this point
89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(1, handle_a->RefCount());
90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, mnt->RefCount());
91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, node->RefCount());
92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ScopedKernelHandle handle_b = handle_a;
94eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
95eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // There should be two references to the KernelHandle, the mount and node
96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // should be unchanged.
97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, handle_a->RefCount());
98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, handle_b->RefCount());
99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(handle_a.get(), handle_b.get());
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(2, mnt->RefCount());
101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, node->RefCount());
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Allocating an FD should cause the KernelProxy to ref the handle and
104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // the node and mount should be unchanged.
105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int fd1 = proxy->AllocateFD(handle_a);
106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(3, handle_a->RefCount());
107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, mnt->RefCount());
108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, node->RefCount());
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // If we "dup" the handle, we should bump the ref count on the handle
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int fd2 = proxy->AllocateFD(handle_b);
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(4, handle_a->RefCount());
113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, mnt->RefCount());
114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, node->RefCount());
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Handles are expected to come out in order
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(0, fd1);
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(1, fd2);
119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Now we "free" the handles, since the proxy should hold them.
121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  handle_a.reset(NULL);
122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  handle_b.reset(NULL);
123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, mnt->RefCount());
124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, node->RefCount());
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We should find the handle by either fd
127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(0, proxy->AcquireHandle(fd1, &handle_a));
128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(0, proxy->AcquireHandle(fd2, &handle_b));
129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(raw_handle, handle_a.get());
130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(raw_handle, handle_b.get());
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(4, handle_a->RefCount());
133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, mnt->RefCount());
134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, node->RefCount());
135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // A non existent fd should fail, and handleA should decrement as handleB
137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // is released by the call.
138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(EBADF, proxy->AcquireHandle(-1, &handle_b));
139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(NULL, handle_b.get());
140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(3, handle_a->RefCount());
141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(EBADF, proxy->AcquireHandle(100, &handle_b));
143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(NULL, handle_b.get());
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Now only the KernelProxy should reference the KernelHandle in the
146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // FD to KernelHandle Map.
147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  handle_a.reset();
148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  handle_b.reset();
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, raw_handle->RefCount());
151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, mnt->RefCount());
152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, node->RefCount());
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  proxy->FreeFD(fd2);
154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(1, raw_handle->RefCount());
155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, mnt->RefCount());
156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, node->RefCount());
157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  proxy->FreeFD(fd1);
159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(1, mnt->RefCount());
160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(1, node->RefCount());
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(KernelObjectTest, FreeAndReassignFD) {
164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // The mount and node should have 1 ref count at this point
165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(1, mnt->RefCount());
166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(1, node->RefCount());
167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  KernelHandle* raw_handle = new KernelHandleRefMock(mnt, node);
169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ScopedKernelHandle handle(raw_handle);
170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, mnt->RefCount());
172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, node->RefCount());
173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(1, raw_handle->RefCount());
174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
175ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  proxy->AllocateFD(handle);
176eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, mnt->RefCount());
177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, node->RefCount());
178eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, raw_handle->RefCount());
179eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
180eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  proxy->FreeAndReassignFD(5, handle);
181eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, mnt->RefCount());
182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, node->RefCount());
183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(3, raw_handle->RefCount());
184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
185eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  handle.reset();
186eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(2, raw_handle->RefCount());
187eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  proxy->AcquireHandle(5, &handle);
189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(3, raw_handle->RefCount());
190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(raw_handle, handle.get());
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
193