View Javadoc
1   /*
2    * Copyright (C) 2015, Matthias Sohn <matthias.sohn@sap.com>
3    * and other copyright owners as documented in the project's IP log.
4    *
5    * This program and the accompanying materials are made available
6    * under the terms of the Eclipse Distribution License v1.0 which
7    * accompanies this distribution, is reproduced below, and is
8    * available at http://www.eclipse.org/org/documents/edl-v10.php
9    *
10   * All rights reserved.
11   *
12   * Redistribution and use in source and binary forms, with or
13   * without modification, are permitted provided that the following
14   * conditions are met:
15   *
16   * - Redistributions of source code must retain the above copyright
17   *   notice, this list of conditions and the following disclaimer.
18   *
19   * - Redistributions in binary form must reproduce the above
20   *   copyright notice, this list of conditions and the following
21   *   disclaimer in the documentation and/or other materials provided
22   *   with the distribution.
23   *
24   * - Neither the name of the Eclipse Foundation, Inc. nor the
25   *   names of its contributors may be used to endorse or promote
26   *   products derived from this software without specific prior
27   *   written permission.
28   *
29   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42   */
43  package org.eclipse.jgit.lfs.server.fs;
44  
45  import static org.eclipse.jgit.util.HttpSupport.HDR_AUTHORIZATION;
46  
47  import java.io.IOException;
48  import java.nio.channels.FileChannel;
49  import java.nio.channels.ReadableByteChannel;
50  import java.nio.file.Files;
51  import java.nio.file.Path;
52  import java.nio.file.StandardOpenOption;
53  import java.util.Collections;
54  
55  import org.eclipse.jgit.annotations.Nullable;
56  import org.eclipse.jgit.lfs.internal.AtomicObjectOutputStream;
57  import org.eclipse.jgit.lfs.lib.AnyLongObjectId;
58  import org.eclipse.jgit.lfs.lib.Constants;
59  import org.eclipse.jgit.lfs.server.LargeFileRepository;
60  import org.eclipse.jgit.lfs.server.Response;
61  import org.eclipse.jgit.lfs.server.Response.Action;
62  
63  /**
64   * Repository storing large objects in the file system
65   *
66   * @since 4.3
67   */
68  public class FileLfsRepository implements LargeFileRepository {
69  
70  	private String url;
71  	private final Path dir;
72  
73  	/**
74  	 * <p>Constructor for FileLfsRepository.</p>
75  	 *
76  	 * @param url
77  	 *            external URL of this repository
78  	 * @param dir
79  	 *            storage directory
80  	 * @throws java.io.IOException
81  	 */
82  	public FileLfsRepository(String url, Path dir) throws IOException {
83  		this.url = url;
84  		this.dir = dir;
85  		Files.createDirectories(dir);
86  	}
87  
88  	/** {@inheritDoc} */
89  	@Override
90  	public Response.Action getDownloadAction(AnyLongObjectId id) {
91  		return getAction(id);
92  	}
93  
94  	/** {@inheritDoc} */
95  	@Override
96  	public Action getUploadAction(AnyLongObjectId id, long size) {
97  		return getAction(id);
98  	}
99  
100 	/** {@inheritDoc} */
101 	@Override
102 	public @Nullable Action getVerifyAction(AnyLongObjectId id) {
103 		return null;
104 	}
105 
106 	/** {@inheritDoc} */
107 	@Override
108 	public long getSize(AnyLongObjectId id) throws IOException {
109 		Path p = getPath(id);
110 		if (Files.exists(p)) {
111 			return Files.size(p);
112 		} else {
113 			return -1;
114 		}
115 	}
116 
117 	/**
118 	 * Get the storage directory
119 	 *
120 	 * @return the path of the storage directory
121 	 */
122 	public Path getDir() {
123 		return dir;
124 	}
125 
126 	/**
127 	 * Get the path where the given object is stored
128 	 *
129 	 * @param id
130 	 *            id of a large object
131 	 * @return path the object's storage path
132 	 */
133 	protected Path getPath(AnyLongObjectId id) {
134 		StringBuilder s = new StringBuilder(
135 				Constants.LONG_OBJECT_ID_STRING_LENGTH + 6);
136 		s.append(toHexCharArray(id.getFirstByte())).append('/');
137 		s.append(toHexCharArray(id.getSecondByte())).append('/');
138 		s.append(id.name());
139 		return dir.resolve(s.toString());
140 	}
141 
142 	private Response.Action getAction(AnyLongObjectId id) {
143 		Response.Action a = new Response.Action();
144 		a.href = url + id.getName();
145 		a.header = Collections.singletonMap(HDR_AUTHORIZATION, "not:required"); //$NON-NLS-1$
146 		return a;
147 	}
148 
149 	ReadableByteChannel getReadChannel(AnyLongObjectId id)
150 			throws IOException {
151 		return FileChannel.open(getPath(id), StandardOpenOption.READ);
152 	}
153 
154 	AtomicObjectOutputStream getOutputStream(AnyLongObjectId id)
155 			throws IOException {
156 		Path path = getPath(id);
157 		Path parent = path.getParent();
158 		if (parent != null) {
159 			Files.createDirectories(parent);
160 		}
161 		return new AtomicObjectOutputStream(path, id);
162 	}
163 
164 	private static char[] toHexCharArray(int b) {
165 		final char[] dst = new char[2];
166 		formatHexChar(dst, 0, b);
167 		return dst;
168 	}
169 
170 	private static final char[] hexchar = { '0', '1', '2', '3', '4', '5', '6',
171 			'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
172 
173 	private static void formatHexChar(char[] dst, int p, int b) {
174 		int o = p + 1;
175 		while (o >= p && b != 0) {
176 			dst[o--] = hexchar[b & 0xf];
177 			b >>>= 4;
178 		}
179 		while (o >= p)
180 			dst[o--] = '0';
181 	}
182 
183 	/**
184 	 * @return the url of the content server
185 	 * @since 4.11
186 	 */
187 	public String getUrl() {
188 		return url;
189 	}
190 
191 	/**
192 	 * @param url
193 	 *            the url of the content server
194 	 * @since 4.11
195 	 */
196 	public void setUrl(String url) {
197 		this.url = url;
198 	}
199 }