hostfs_user.c 8.4 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
J
Jeff Dike 已提交
2
 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
L
Linus Torvalds 已提交
3 4 5 6
 * Licensed under the GPL
 */

#include <stdio.h>
J
Jeff Dike 已提交
7 8
#include <stddef.h>
#include <unistd.h>
L
Linus Torvalds 已提交
9 10
#include <dirent.h>
#include <errno.h>
J
Jeff Dike 已提交
11
#include <fcntl.h>
L
Linus Torvalds 已提交
12 13 14
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
J
Jeff Dike 已提交
15
#include <sys/types.h>
L
Linus Torvalds 已提交
16 17
#include <sys/vfs.h>
#include "hostfs.h"
J
Jeff Dike 已提交
18
#include "os.h"
L
Linus Torvalds 已提交
19
#include "user.h"
J
Jeff Dike 已提交
20
#include <utime.h>
L
Linus Torvalds 已提交
21 22 23 24 25

int stat_file(const char *path, unsigned long long *inode_out, int *mode_out,
	      int *nlink_out, int *uid_out, int *gid_out,
	      unsigned long long *size_out, struct timespec *atime_out,
	      struct timespec *mtime_out, struct timespec *ctime_out,
26
	      int *blksize_out, unsigned long long *blocks_out, int fd)
L
Linus Torvalds 已提交
27 28 29
{
	struct stat64 buf;

J
Jeff Dike 已提交
30
	if (fd >= 0) {
31
		if (fstat64(fd, &buf) < 0)
J
Jeff Dike 已提交
32
			return -errno;
J
Jeff Dike 已提交
33
	} else if (lstat64(path, &buf) < 0) {
J
Jeff Dike 已提交
34
		return -errno;
35
	}
L
Linus Torvalds 已提交
36

J
Jeff Dike 已提交
37 38 39 40 41 42 43 44 45 46 47 48 49
	if (inode_out != NULL)
		*inode_out = buf.st_ino;
	if (mode_out != NULL)
		*mode_out = buf.st_mode;
	if (nlink_out != NULL)
		*nlink_out = buf.st_nlink;
	if (uid_out != NULL)
		*uid_out = buf.st_uid;
	if (gid_out != NULL)
		*gid_out = buf.st_gid;
	if (size_out != NULL)
		*size_out = buf.st_size;
	if (atime_out != NULL) {
L
Linus Torvalds 已提交
50 51 52
		atime_out->tv_sec = buf.st_atime;
		atime_out->tv_nsec = 0;
	}
J
Jeff Dike 已提交
53
	if (mtime_out != NULL) {
L
Linus Torvalds 已提交
54 55 56
		mtime_out->tv_sec = buf.st_mtime;
		mtime_out->tv_nsec = 0;
	}
J
Jeff Dike 已提交
57
	if (ctime_out != NULL) {
L
Linus Torvalds 已提交
58 59 60
		ctime_out->tv_sec = buf.st_ctime;
		ctime_out->tv_nsec = 0;
	}
J
Jeff Dike 已提交
61 62 63 64
	if (blksize_out != NULL)
		*blksize_out = buf.st_blksize;
	if (blocks_out != NULL)
		*blocks_out = buf.st_blocks;
J
Jeff Dike 已提交
65
	return 0;
L
Linus Torvalds 已提交
66 67 68 69 70 71
}

int file_type(const char *path, int *maj, int *min)
{
 	struct stat64 buf;

J
Jeff Dike 已提交
72
	if (lstat64(path, &buf) < 0)
J
Jeff Dike 已提交
73
		return -errno;
J
Jeff Dike 已提交
74 75 76 77 78
	/*
	 * We cannot pass rdev as is because glibc and the kernel disagree
	 * about its definition.
	 */
	if (maj != NULL)
A
Al Viro 已提交
79
		*maj = os_major(buf.st_rdev);
J
Jeff Dike 已提交
80
	if (min != NULL)
A
Al Viro 已提交
81
		*min = os_minor(buf.st_rdev);
L
Linus Torvalds 已提交
82

J
Jeff Dike 已提交
83 84 85 86 87 88 89 90 91 92 93 94
	if (S_ISDIR(buf.st_mode))
		return OS_TYPE_DIR;
	else if (S_ISLNK(buf.st_mode))
		return OS_TYPE_SYMLINK;
	else if (S_ISCHR(buf.st_mode))
		return OS_TYPE_CHARDEV;
	else if (S_ISBLK(buf.st_mode))
		return OS_TYPE_BLOCKDEV;
	else if (S_ISFIFO(buf.st_mode))
		return OS_TYPE_FIFO;
	else if (S_ISSOCK(buf.st_mode))
		return OS_TYPE_SOCK;
J
Jeff Dike 已提交
95
	else return OS_TYPE_FILE;
L
Linus Torvalds 已提交
96 97 98 99 100 101
}

int access_file(char *path, int r, int w, int x)
{
	int mode = 0;

J
Jeff Dike 已提交
102 103 104 105 106 107 108
	if (r)
		mode = R_OK;
	if (w)
		mode |= W_OK;
	if (x)
		mode |= X_OK;
	if (access(path, mode) != 0)
J
Jeff Dike 已提交
109 110
		return -errno;
	else return 0;
L
Linus Torvalds 已提交
111 112 113 114 115 116
}

int open_file(char *path, int r, int w, int append)
{
	int mode = 0, fd;

J
Jeff Dike 已提交
117
	if (r && !w)
L
Linus Torvalds 已提交
118
		mode = O_RDONLY;
J
Jeff Dike 已提交
119
	else if (!r && w)
L
Linus Torvalds 已提交
120
		mode = O_WRONLY;
J
Jeff Dike 已提交
121
	else if (r && w)
L
Linus Torvalds 已提交
122 123 124
		mode = O_RDWR;
	else panic("Impossible mode in open_file");

J
Jeff Dike 已提交
125
	if (append)
L
Linus Torvalds 已提交
126 127
		mode |= O_APPEND;
	fd = open64(path, mode);
J
Jeff Dike 已提交
128
	if (fd < 0)
J
Jeff Dike 已提交
129 130
		return -errno;
	else return fd;
L
Linus Torvalds 已提交
131 132 133 134 135 136 137 138
}

void *open_dir(char *path, int *err_out)
{
	DIR *dir;

	dir = opendir(path);
	*err_out = errno;
J
Jeff Dike 已提交
139
	if (dir == NULL)
J
Jeff Dike 已提交
140 141
		return NULL;
	return dir;
L
Linus Torvalds 已提交
142 143 144 145 146 147 148 149 150 151
}

char *read_dir(void *stream, unsigned long long *pos,
	       unsigned long long *ino_out, int *len_out)
{
	DIR *dir = stream;
	struct dirent *ent;

	seekdir(dir, *pos);
	ent = readdir(dir);
J
Jeff Dike 已提交
152
	if (ent == NULL)
J
Jeff Dike 已提交
153
		return NULL;
L
Linus Torvalds 已提交
154 155 156
	*len_out = strlen(ent->d_name);
	*ino_out = ent->d_ino;
	*pos = telldir(dir);
J
Jeff Dike 已提交
157
	return ent->d_name;
L
Linus Torvalds 已提交
158 159 160 161 162 163 164
}

int read_file(int fd, unsigned long long *offset, char *buf, int len)
{
	int n;

	n = pread64(fd, buf, len, *offset);
J
Jeff Dike 已提交
165
	if (n < 0)
J
Jeff Dike 已提交
166
		return -errno;
L
Linus Torvalds 已提交
167
	*offset += n;
J
Jeff Dike 已提交
168
	return n;
L
Linus Torvalds 已提交
169 170 171 172 173 174 175
}

int write_file(int fd, unsigned long long *offset, const char *buf, int len)
{
	int n;

	n = pwrite64(fd, buf, len, *offset);
J
Jeff Dike 已提交
176
	if (n < 0)
J
Jeff Dike 已提交
177
		return -errno;
L
Linus Torvalds 已提交
178
	*offset += n;
J
Jeff Dike 已提交
179
	return n;
L
Linus Torvalds 已提交
180 181 182 183 184 185 186
}

int lseek_file(int fd, long long offset, int whence)
{
	int ret;

	ret = lseek64(fd, offset, whence);
J
Jeff Dike 已提交
187
	if (ret < 0)
J
Jeff Dike 已提交
188 189
		return -errno;
	return 0;
L
Linus Torvalds 已提交
190 191
}

192 193 194 195 196 197 198 199 200 201 202 203 204
int fsync_file(int fd, int datasync)
{
	int ret;
	if (datasync)
		ret = fdatasync(fd);
	else
		ret = fsync(fd);

	if (ret < 0)
		return -errno;
	return 0;
}

L
Linus Torvalds 已提交
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
void close_file(void *stream)
{
	close(*((int *) stream));
}

void close_dir(void *stream)
{
	closedir(stream);
}

int file_create(char *name, int ur, int uw, int ux, int gr,
		int gw, int gx, int or, int ow, int ox)
{
	int mode, fd;

	mode = 0;
	mode |= ur ? S_IRUSR : 0;
	mode |= uw ? S_IWUSR : 0;
	mode |= ux ? S_IXUSR : 0;
	mode |= gr ? S_IRGRP : 0;
	mode |= gw ? S_IWGRP : 0;
	mode |= gx ? S_IXGRP : 0;
	mode |= or ? S_IROTH : 0;
	mode |= ow ? S_IWOTH : 0;
	mode |= ox ? S_IXOTH : 0;
	fd = open64(name, O_CREAT | O_RDWR, mode);
J
Jeff Dike 已提交
231
	if (fd < 0)
J
Jeff Dike 已提交
232 233
		return -errno;
	return fd;
L
Linus Torvalds 已提交
234 235
}

236
int set_attr(const char *file, struct hostfs_iattr *attrs, int fd)
L
Linus Torvalds 已提交
237
{
238 239
	struct timeval times[2];
	struct timespec atime_ts, mtime_ts;
L
Linus Torvalds 已提交
240 241
	int err, ma;

242 243 244 245 246
	if (attrs->ia_valid & HOSTFS_ATTR_MODE) {
		if (fd >= 0) {
			if (fchmod(fd, attrs->ia_mode) != 0)
				return (-errno);
		} else if (chmod(file, attrs->ia_mode) != 0) {
J
Jeff Dike 已提交
247
			return -errno;
248
		}
L
Linus Torvalds 已提交
249
	}
250 251 252
	if (attrs->ia_valid & HOSTFS_ATTR_UID) {
		if (fd >= 0) {
			if (fchown(fd, attrs->ia_uid, -1))
J
Jeff Dike 已提交
253
				return -errno;
J
Jeff Dike 已提交
254
		} else if (chown(file, attrs->ia_uid, -1)) {
J
Jeff Dike 已提交
255
			return -errno;
256
		}
L
Linus Torvalds 已提交
257
	}
258 259 260
	if (attrs->ia_valid & HOSTFS_ATTR_GID) {
		if (fd >= 0) {
			if (fchown(fd, -1, attrs->ia_gid))
J
Jeff Dike 已提交
261
				return -errno;
262
		} else if (chown(file, -1, attrs->ia_gid)) {
J
Jeff Dike 已提交
263
			return -errno;
264
		}
L
Linus Torvalds 已提交
265
	}
266 267 268
	if (attrs->ia_valid & HOSTFS_ATTR_SIZE) {
		if (fd >= 0) {
			if (ftruncate(fd, attrs->ia_size))
J
Jeff Dike 已提交
269
				return -errno;
270
		} else if (truncate(file, attrs->ia_size)) {
J
Jeff Dike 已提交
271
			return -errno;
272
		}
L
Linus Torvalds 已提交
273
	}
274

J
Jeff Dike 已提交
275 276
	/*
	 * Update accessed and/or modified time, in two parts: first set
277
	 * times according to the changes to perform, and then call futimes()
J
Jeff Dike 已提交
278 279
	 * or utimes() to apply them.
	 */
280 281 282 283 284 285 286 287
	ma = (HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET);
	if (attrs->ia_valid & ma) {
		err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL,
				&atime_ts, &mtime_ts, NULL, NULL, NULL, fd);
		if (err != 0)
			return err;

		times[0].tv_sec = atime_ts.tv_sec;
288
		times[0].tv_usec = atime_ts.tv_nsec / 1000;
289
		times[1].tv_sec = mtime_ts.tv_sec;
290
		times[1].tv_usec = mtime_ts.tv_nsec / 1000;
291 292 293

		if (attrs->ia_valid & HOSTFS_ATTR_ATIME_SET) {
			times[0].tv_sec = attrs->ia_atime.tv_sec;
294
			times[0].tv_usec = attrs->ia_atime.tv_nsec / 1000;
L
Linus Torvalds 已提交
295
		}
296 297
		if (attrs->ia_valid & HOSTFS_ATTR_MTIME_SET) {
			times[1].tv_sec = attrs->ia_mtime.tv_sec;
298
			times[1].tv_usec = attrs->ia_mtime.tv_nsec / 1000;
299 300 301 302
		}

		if (fd >= 0) {
			if (futimes(fd, times) != 0)
J
Jeff Dike 已提交
303
				return -errno;
304
		} else if (utimes(file, times) != 0) {
J
Jeff Dike 已提交
305
			return -errno;
L
Linus Torvalds 已提交
306 307
		}
	}
308

J
Jeff Dike 已提交
309
	/* Note: ctime is not handled */
J
Jeff Dike 已提交
310
	if (attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)) {
L
Linus Torvalds 已提交
311 312
		err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL,
				&attrs->ia_atime, &attrs->ia_mtime, NULL,
313
				NULL, NULL, fd);
J
Jeff Dike 已提交
314
		if (err != 0)
J
Jeff Dike 已提交
315
			return err;
L
Linus Torvalds 已提交
316
	}
J
Jeff Dike 已提交
317
	return 0;
L
Linus Torvalds 已提交
318 319 320 321 322 323 324
}

int make_symlink(const char *from, const char *to)
{
	int err;

	err = symlink(to, from);
J
Jeff Dike 已提交
325
	if (err)
J
Jeff Dike 已提交
326 327
		return -errno;
	return 0;
L
Linus Torvalds 已提交
328 329 330 331 332 333 334
}

int unlink_file(const char *file)
{
	int err;

	err = unlink(file);
J
Jeff Dike 已提交
335
	if (err)
J
Jeff Dike 已提交
336 337
		return -errno;
	return 0;
L
Linus Torvalds 已提交
338 339 340 341 342 343 344
}

int do_mkdir(const char *file, int mode)
{
	int err;

	err = mkdir(file, mode);
J
Jeff Dike 已提交
345
	if (err)
J
Jeff Dike 已提交
346 347
		return -errno;
	return 0;
L
Linus Torvalds 已提交
348 349 350 351 352 353 354
}

int do_rmdir(const char *file)
{
	int err;

	err = rmdir(file);
J
Jeff Dike 已提交
355
	if (err)
J
Jeff Dike 已提交
356 357
		return -errno;
	return 0;
L
Linus Torvalds 已提交
358 359
}

J
Johannes Stezenbach 已提交
360
int do_mknod(const char *file, int mode, unsigned int major, unsigned int minor)
L
Linus Torvalds 已提交
361 362 363
{
	int err;

A
Al Viro 已提交
364
	err = mknod(file, mode, os_makedev(major, minor));
J
Jeff Dike 已提交
365
	if (err)
J
Jeff Dike 已提交
366 367
		return -errno;
	return 0;
L
Linus Torvalds 已提交
368 369 370 371 372 373 374
}

int link_file(const char *to, const char *from)
{
	int err;

	err = link(to, from);
J
Jeff Dike 已提交
375
	if (err)
J
Jeff Dike 已提交
376 377
		return -errno;
	return 0;
L
Linus Torvalds 已提交
378 379
}

380
int hostfs_do_readlink(char *file, char *buf, int size)
L
Linus Torvalds 已提交
381 382 383 384
{
	int n;

	n = readlink(file, buf, size);
J
Jeff Dike 已提交
385
	if (n < 0)
J
Jeff Dike 已提交
386
		return -errno;
J
Jeff Dike 已提交
387
	if (n < size)
L
Linus Torvalds 已提交
388
		buf[n] = '\0';
J
Jeff Dike 已提交
389
	return n;
L
Linus Torvalds 已提交
390 391 392 393 394 395 396
}

int rename_file(char *from, char *to)
{
	int err;

	err = rename(from, to);
J
Jeff Dike 已提交
397
	if (err < 0)
J
Jeff Dike 已提交
398 399
		return -errno;
	return 0;
L
Linus Torvalds 已提交
400 401 402 403 404 405 406 407 408 409 410 411
}

int do_statfs(char *root, long *bsize_out, long long *blocks_out,
	      long long *bfree_out, long long *bavail_out,
	      long long *files_out, long long *ffree_out,
	      void *fsid_out, int fsid_size, long *namelen_out,
	      long *spare_out)
{
	struct statfs64 buf;
	int err;

	err = statfs64(root, &buf);
J
Jeff Dike 已提交
412
	if (err < 0)
J
Jeff Dike 已提交
413 414
		return -errno;

L
Linus Torvalds 已提交
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
	*bsize_out = buf.f_bsize;
	*blocks_out = buf.f_blocks;
	*bfree_out = buf.f_bfree;
	*bavail_out = buf.f_bavail;
	*files_out = buf.f_files;
	*ffree_out = buf.f_ffree;
	memcpy(fsid_out, &buf.f_fsid,
	       sizeof(buf.f_fsid) > fsid_size ? fsid_size :
	       sizeof(buf.f_fsid));
	*namelen_out = buf.f_namelen;
	spare_out[0] = buf.f_spare[0];
	spare_out[1] = buf.f_spare[1];
	spare_out[2] = buf.f_spare[2];
	spare_out[3] = buf.f_spare[3];
	spare_out[4] = buf.f_spare[4];
J
Jeff Dike 已提交
430
	return 0;
L
Linus Torvalds 已提交
431
}