| /******************************************************************************* |
| * Copyright (c) 2007 Wind River Systems, Inc. and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Wind River Systems - initial API and implementation |
| *******************************************************************************/ |
| |
| /* |
| * Target service implementation: file system access (TCF name FileSystem) |
| */ |
| |
| #include "config.h" |
| #if SERVICE_FileSystem |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <assert.h> |
| #include <fcntl.h> |
| #include <sys/stat.h> |
| #ifdef WIN32 |
| # include <sys/utime.h> |
| # include <direct.h> |
| #else |
| # include <utime.h> |
| # include <dirent.h> |
| #endif |
| #include "mdep.h" |
| #include "myalloc.h" |
| #include "streams.h" |
| #include "channel.h" |
| #include "link.h" |
| #include "trace.h" |
| #include "json.h" |
| #include "exceptions.h" |
| #include "base64.h" |
| #include "protocol.h" |
| #include "filesystem.h" |
| |
| #define BUF_SIZE 0x1000 |
| |
| static const char * FILE_SYSTEM = "FileSystem"; |
| |
| static const int |
| TCF_O_READ = 0x00000001, |
| TCF_O_WRITE = 0x00000002, |
| TCF_O_APPEND = 0x00000004, |
| TCF_O_CREAT = 0x00000008, |
| TCF_O_TRUNC = 0x00000010, |
| TCF_O_EXCL = 0x00000020; |
| |
| static const int |
| ATTR_SIZE = 0x00000001, |
| ATTR_UIDGID = 0x00000002, |
| ATTR_PERMISSIONS = 0x00000004, |
| ATTR_ACMODTIME = 0x00000008; |
| |
| static const int |
| STATUS_OK = 0, |
| STATUS_EOF = 1, |
| STATUS_NO_SUCH_FILE = 2, |
| STATUS_PERMISSION_DENIED = 3, |
| STATUS_FAILURE = 4, |
| STATUS_BAD_MESSAGE = 5, |
| STATUS_NO_CONNECTION = 6, |
| STATUS_CONNECTION_LOST = 7, |
| STATUS_OP_UNSUPPORTED = 8; |
| |
| typedef struct OpenFileInfo OpenFileInfo; |
| |
| struct OpenFileInfo { |
| unsigned long handle; |
| char path[FILE_PATH_SIZE]; |
| int file; |
| DIR * dir; |
| InputStream * inp; |
| LINK link_ring; |
| LINK link_hash; |
| }; |
| |
| #define hash2file(A) ((OpenFileInfo *)((char *)(A) - (int)&((OpenFileInfo *)0)->link_hash)) |
| #define ring2file(A) ((OpenFileInfo *)((char *)(A) - (int)&((OpenFileInfo *)0)->link_ring)) |
| |
| typedef struct FileAttrs FileAttrs; |
| |
| struct FileAttrs { |
| int flags; |
| int64 size; |
| int uid; |
| int gid; |
| int permissions; |
| int64 atime; |
| int64 mtime; |
| }; |
| |
| static unsigned long handle_cnt = 0; |
| |
| #define HANDLE_HASH_SIZE 0x1000 |
| static LINK handle_hash[HANDLE_HASH_SIZE]; |
| static LINK file_info_ring = { NULL, NULL }; |
| |
| #if defined(_WRS_KERNEL) |
| # define FS_ROOT "host:c:/" |
| #endif |
| |
| static OpenFileInfo * create_open_file_info(InputStream * inp, char * path, int file, DIR * dir) { |
| int i = 0; |
| LINK * list_head = NULL; |
| |
| OpenFileInfo * h = (OpenFileInfo *)loc_alloc_zero(sizeof(OpenFileInfo)); |
| for (;;) { |
| LINK * list_next; |
| OpenFileInfo * p = NULL; |
| h->handle = handle_cnt++; |
| list_head = &handle_hash[h->handle % HANDLE_HASH_SIZE]; |
| for (list_next = list_head->next; list_next != list_head; list_next = list_next->next) { |
| if (hash2file(list_next)->handle == h->handle) { |
| p = hash2file(list_next); |
| break; |
| } |
| } |
| if (p == NULL) break; |
| } |
| strcpy(h->path, path); |
| h->file = file; |
| h->dir = dir; |
| h->inp = inp; |
| list_add_first(&h->link_ring, &file_info_ring); |
| list_add_first(&h->link_hash, list_head); |
| return h; |
| } |
| |
| static OpenFileInfo * find_open_file_info(char * id) { |
| unsigned long handle = 0; |
| LINK * list_head = NULL; |
| LINK * list_next = NULL; |
| |
| if (id == NULL || id[0] != 'F' || id[1] != 'S' || id[2] == 0) return NULL; |
| handle = strtoul(id + 2, &id, 10); |
| if (id[0] != 0) return NULL; |
| list_head = &handle_hash[handle % HANDLE_HASH_SIZE]; |
| for (list_next = list_head->next; list_next != list_head; list_next = list_next->next) { |
| if (hash2file(list_next)->handle == handle) return hash2file(list_next); |
| } |
| return NULL; |
| } |
| |
| static void delete_open_file_info(OpenFileInfo * h) { |
| list_remove(&h->link_ring); |
| list_remove(&h->link_hash); |
| loc_free(h); |
| } |
| |
| static void channel_close_listener(InputStream * inp, OutputStream * out) { |
| LINK list; |
| LINK * list_next = NULL; |
| |
| list_init(&list); |
| for (list_next = file_info_ring.next; list_next != &file_info_ring; list_next = list_next->next) { |
| OpenFileInfo * h = ring2file(list_next); |
| if (h->inp == inp) { |
| trace(LOG_ALWAYS, "file handle left open by client: FS%d", h->handle); |
| list_remove(&h->link_hash); |
| if (h->dir != NULL) { |
| closedir(h->dir); |
| h->dir = NULL; |
| } |
| if (h->file >= 0) { |
| close(h->file); |
| h->file = -1; |
| } |
| list_add_last(&h->link_hash, &list); |
| } |
| } |
| |
| while (!list_is_empty(&list)) delete_open_file_info(hash2file(list.next)); |
| } |
| |
| static void write_fs_errno(OutputStream * out, int err) { |
| char * msg = NULL; |
| int status = 0; |
| switch (err) { |
| case 0: |
| status = STATUS_OK; |
| break; |
| case ERR_EOF: |
| status = STATUS_EOF; |
| break; |
| case ENOENT: |
| status = STATUS_NO_SUCH_FILE; |
| break; |
| case EACCES: |
| status = STATUS_PERMISSION_DENIED; |
| break; |
| default: |
| status = STATUS_FAILURE; |
| break; |
| } |
| json_write_long(out, status); |
| out->write(out, 0); |
| if (err != 0) msg = errno_to_str(err); |
| json_write_string(out, msg); |
| out->write(out, 0); |
| } |
| |
| static void write_file_handle(OutputStream * out, OpenFileInfo * h) { |
| if (h == NULL) { |
| write_string(out, "null"); |
| } |
| else { |
| char s[32]; |
| char * p = s + sizeof(s); |
| unsigned long n = h->handle; |
| *(--p) = 0; |
| do { |
| *(--p) = (char)(n % 10 + '0'); |
| n = n / 10; |
| } |
| while (n != 0); |
| *(--p) = 'S'; |
| *(--p) = 'F'; |
| json_write_string(out, p); |
| } |
| out->write(out, 0); |
| } |
| |
| static void fill_attrs(FileAttrs * attrs, struct_stat * buf) { |
| memset(attrs, 0, sizeof(FileAttrs)); |
| attrs->flags |= ATTR_SIZE | ATTR_UIDGID | ATTR_PERMISSIONS | ATTR_ACMODTIME; |
| attrs->size = buf->st_size; |
| attrs->uid = buf->st_uid; |
| attrs->gid = buf->st_gid; |
| attrs->permissions = buf->st_mode; |
| attrs->atime = (int64)buf->st_atime * 1000; |
| attrs->mtime = (int64)buf->st_mtime * 1000; |
| } |
| |
| static void read_file_attrs(InputStream * inp, char * nm, void * arg) { |
| FileAttrs * attrs = (FileAttrs *)arg; |
| if (strcmp(nm, "Size") == 0) { |
| attrs->size = json_read_int64(inp); |
| attrs->flags |= ATTR_SIZE; |
| } |
| else if (strcmp(nm, "UID") == 0) { |
| attrs->uid = (int)json_read_long(inp); |
| attrs->flags |= ATTR_UIDGID; |
| } |
| else if (strcmp(nm, "GID") == 0) { |
| attrs->gid = (int)json_read_long(inp); |
| attrs->flags |= ATTR_UIDGID; |
| } |
| else if (strcmp(nm, "Permissions") == 0) { |
| attrs->permissions = (int)json_read_long(inp); |
| attrs->flags |= ATTR_PERMISSIONS; |
| } |
| else if (strcmp(nm, "ATime") == 0) { |
| attrs->atime = json_read_int64(inp); |
| attrs->flags |= ATTR_ACMODTIME; |
| } |
| else if (strcmp(nm, "MTime") == 0) { |
| attrs->mtime = json_read_int64(inp); |
| attrs->flags |= ATTR_ACMODTIME; |
| } |
| else { |
| exception(ERR_JSON_SYNTAX); |
| } |
| } |
| |
| static void write_file_attrs(OutputStream * out, FileAttrs * attrs) { |
| int cnt = 0; |
| |
| if (attrs == NULL) { |
| write_stringz(out, "null"); |
| return; |
| } |
| |
| out->write(out, '{'); |
| if (attrs->flags & ATTR_SIZE) { |
| json_write_string(out, "Size"); |
| out->write(out, ':'); |
| json_write_int64(out, attrs->size); |
| cnt++; |
| } |
| if (attrs->flags & ATTR_UIDGID) { |
| if (cnt) out->write(out, ','); |
| json_write_string(out, "UID"); |
| out->write(out, ':'); |
| json_write_long(out, attrs->uid); |
| out->write(out, ','); |
| json_write_string(out, "GID"); |
| out->write(out, ':'); |
| json_write_long(out, attrs->gid); |
| cnt++; |
| } |
| if (attrs->flags & ATTR_SIZE) { |
| if (cnt) out->write(out, ','); |
| json_write_string(out, "Permissions"); |
| out->write(out, ':'); |
| json_write_long(out, attrs->permissions); |
| cnt++; |
| } |
| if (attrs->flags & ATTR_ACMODTIME) { |
| if (cnt) out->write(out, ','); |
| json_write_string(out, "ATime"); |
| out->write(out, ':'); |
| json_write_int64(out, attrs->atime); |
| out->write(out, ','); |
| json_write_string(out, "MTime"); |
| out->write(out, ':'); |
| json_write_int64(out, attrs->mtime); |
| cnt++; |
| } |
| out->write(out, '}'); |
| } |
| |
| static int to_local_open_flags(int flags) { |
| int res = O_BINARY | O_LARGEFILE; |
| if (flags & TCF_O_READ) res |= O_RDONLY; |
| if (flags & TCF_O_WRITE) res |= O_WRONLY; |
| if (flags & TCF_O_APPEND) res |= O_APPEND; |
| if (flags & TCF_O_CREAT) res |= O_CREAT; |
| if (flags & TCF_O_TRUNC) res |= O_TRUNC; |
| if (flags & TCF_O_EXCL) res |= O_EXCL; |
| return res; |
| } |
| |
| static void read_path(InputStream * inp, char * path, int size) { |
| int i = 0; |
| char buf[FILE_PATH_SIZE]; |
| json_read_string(inp, path, size); |
| while (path[i] != 0) { |
| if (path[i] == '\\') path[i] = '/'; |
| i++; |
| } |
| #ifdef WIN32 |
| if (path[0] != 0 && path[1] == ':' && path[2] == '/') return; |
| #elif defined(_WRS_KERNEL) |
| if (strncmp(path, FS_ROOT, strlen(FS_ROOT)) == 0) return; |
| #endif |
| if (path[0] == 0) { |
| strcpy(path, get_user_home()); |
| } |
| else if (path[0] != '/') { |
| snprintf(buf, sizeof(buf), "%s/%s", get_user_home(), path); |
| strcpy(path, buf); |
| } |
| } |
| |
| static void command_open(char * token, InputStream * inp, OutputStream * out) { |
| char path[FILE_PATH_SIZE]; |
| unsigned long flags = 0; |
| FileAttrs attrs; |
| int file = -1; |
| int err = 0; |
| OpenFileInfo * handle = NULL; |
| |
| read_path(inp, path, sizeof(path)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| flags = json_read_ulong(inp); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| memset(&attrs, 0, sizeof(FileAttrs)); |
| json_read_struct(inp, read_file_attrs, &attrs); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| if ((attrs.flags & ATTR_PERMISSIONS) == 0) { |
| attrs.permissions = 0775; |
| } |
| file = open(path, to_local_open_flags(flags), attrs.permissions); |
| |
| if (file < 0){ |
| err = errno; |
| } |
| else { |
| handle = create_open_file_info(inp, path, file, NULL); |
| } |
| |
| write_stringz(out, "R"); |
| write_stringz(out, token); |
| write_fs_errno(out, err); |
| write_file_handle(out, handle); |
| out->write(out, MARKER_EOM); |
| } |
| |
| static void command_close(char * token, InputStream * inp, OutputStream * out) { |
| char id[256]; |
| OpenFileInfo * h = NULL; |
| int err = 0; |
| |
| json_read_string(inp, id, sizeof(id)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| h = find_open_file_info(id); |
| if (h == NULL) { |
| err = EBADF; |
| } |
| else if (h->dir != NULL) { |
| if (closedir(h->dir) < 0) { |
| err = errno; |
| } |
| else { |
| delete_open_file_info(h); |
| } |
| } |
| else { |
| if (close(h->file) < 0) { |
| err = errno; |
| } |
| else { |
| delete_open_file_info(h); |
| } |
| } |
| |
| write_stringz(out, "R"); |
| write_stringz(out, token); |
| write_fs_errno(out, err); |
| out->write(out, MARKER_EOM); |
| } |
| |
| static void command_read(char * token, InputStream * inp, OutputStream * out) { |
| char id[256]; |
| OpenFileInfo * h = NULL; |
| int err = 0; |
| int eof = 0; |
| int64 offset; |
| unsigned long len; |
| unsigned long cnt = 0; |
| |
| json_read_string(inp, id, sizeof(id)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| offset = json_read_int64(inp); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| len = json_read_ulong(inp); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| write_stringz(out, "R"); |
| write_stringz(out, token); |
| |
| h = find_open_file_info(id); |
| if (h == NULL) { |
| err = EBADF; |
| write_stringz(out, "null"); |
| } |
| else { |
| char buf[BUF_SIZE + 4]; |
| int rem = 0; |
| unsigned long chk = 0; |
| out->write(out, '"'); |
| while (cnt < len) { |
| if (lseek(h->file, offset + cnt, SEEK_SET) == -1) { |
| assert(errno != 0); |
| err = errno; |
| break; |
| } |
| else { |
| int i, j; |
| int rd = read(h->file, buf + rem, BUF_SIZE < len - cnt ? BUF_SIZE : len - cnt); |
| if (rd < 0) { |
| assert(errno != 0); |
| err = errno; |
| break; |
| } |
| if (rd == 0) { |
| assert(cnt < len); |
| eof = 1; |
| break; |
| } |
| j = rem + rd; |
| rem = j % 3; |
| chk += write_base64(out, buf, j - rem); |
| for (i = 0; i < rem; i++) buf[i] = buf[j - rem + i]; |
| cnt += rd; |
| } |
| } |
| chk += write_base64(out, buf, rem); |
| out->write(out, '"'); |
| out->write(out, 0); |
| assert(chk == (cnt + 2) / 3 * 4); |
| } |
| |
| assert(err || eof || cnt == len); |
| write_fs_errno(out, err); |
| json_write_boolean(out, eof); |
| out->write(out, 0); |
| out->write(out, MARKER_EOM); |
| } |
| |
| static void command_write(char * token, InputStream * inp, OutputStream * out) { |
| char id[256]; |
| OpenFileInfo * h = NULL; |
| int err = 0; |
| int64 offset; |
| unsigned long len = 0; |
| |
| json_read_string(inp, id, sizeof(id)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| offset = json_read_int64(inp); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (inp->read(inp) != '"') exception(ERR_JSON_SYNTAX); |
| |
| h = find_open_file_info(id); |
| if (h == NULL) err = EBADF; |
| for (;;) { |
| char buf[BUF_SIZE]; |
| int rd = read_base64(inp, buf, sizeof(buf)); |
| if (rd == 0) break; |
| if (err == 0 && lseek(h->file, offset + len, SEEK_SET) == -1) { |
| err = errno; |
| } |
| if (err == 0) { |
| int wr = write(h->file, buf, rd); |
| if (wr < 0) err = errno; |
| else if (wr < rd) err = ENOSPC; |
| } |
| len += rd; |
| } |
| |
| if (inp->read(inp) != '"') exception(ERR_JSON_SYNTAX); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| write_stringz(out, "R"); |
| write_stringz(out, token); |
| write_fs_errno(out, err); |
| out->write(out, MARKER_EOM); |
| } |
| |
| static void write_stat_result(char * token, OutputStream * out, int err, struct_stat * buf) { |
| FileAttrs attrs; |
| |
| if (err == 0) fill_attrs(&attrs, buf); |
| else memset(&attrs, 0, sizeof(attrs)); |
| |
| write_stringz(out, "R"); |
| write_stringz(out, token); |
| write_fs_errno(out, err); |
| write_file_attrs(out, &attrs); |
| out->write(out, 0); |
| out->write(out, MARKER_EOM); |
| } |
| |
| static void command_stat(char * token, InputStream * inp, OutputStream * out) { |
| char path[FILE_PATH_SIZE]; |
| struct_stat buf; |
| int err = 0; |
| |
| read_path(inp, path, sizeof(path)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| memset(&buf, 0, sizeof(buf)); |
| if (stat(path, &buf) < 0) err = errno; |
| |
| write_stat_result(token, out, err, &buf); |
| } |
| |
| static void command_lstat(char * token, InputStream * inp, OutputStream * out) { |
| char path[FILE_PATH_SIZE]; |
| struct_stat buf; |
| int err = 0; |
| |
| read_path(inp, path, sizeof(path)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| memset(&buf, 0, sizeof(buf)); |
| if (lstat(path, &buf) < 0) err = errno; |
| |
| write_stat_result(token, out, err, &buf); |
| } |
| |
| static void command_fstat(char * token, InputStream * inp, OutputStream * out) { |
| char id[256]; |
| struct_stat buf; |
| OpenFileInfo * h = NULL; |
| int err = 0; |
| |
| json_read_string(inp, id, sizeof(id)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| h = find_open_file_info(id); |
| memset(&buf, 0, sizeof(buf)); |
| if (h == NULL) err = EBADF; |
| else if (fstat(h->file, &buf) < 0) err = errno; |
| write_stat_result(token, out, err, &buf); |
| } |
| |
| static void command_setstat(char * token, InputStream * inp, OutputStream * out) { |
| char path[FILE_PATH_SIZE]; |
| FileAttrs attrs; |
| int err = 0; |
| |
| read_path(inp, path, sizeof(path)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| memset(&attrs, 0, sizeof(FileAttrs)); |
| json_read_struct(inp, read_file_attrs, &attrs); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| if (attrs.flags & ATTR_SIZE) { |
| if (truncate(path, attrs.size) < 0) err = errno; |
| } |
| #if !defined(WIN32) && !defined(_WRS_KERNEL) |
| if (attrs.flags & ATTR_UIDGID) { |
| if (chown(path, attrs.uid, attrs.gid) < 0) err = errno; |
| } |
| #endif |
| if (attrs.flags & ATTR_PERMISSIONS) { |
| if (chmod(path, attrs.permissions) < 0) err = errno; |
| } |
| if (attrs.flags & ATTR_ACMODTIME) { |
| struct utimbuf buf; |
| buf.actime = (long)(attrs.atime / 1000); |
| buf.modtime = (long)(attrs.mtime / 1000); |
| if (utime(path, &buf) < 0) err = errno; |
| } |
| |
| write_stringz(out, "R"); |
| write_stringz(out, token); |
| write_fs_errno(out, err); |
| out->write(out, MARKER_EOM); |
| } |
| |
| static void command_fsetstat(char * token, InputStream * inp, OutputStream * out) { |
| char id[256]; |
| FileAttrs attrs; |
| OpenFileInfo * h = NULL; |
| int err = 0; |
| |
| json_read_string(inp, id, sizeof(id)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| memset(&attrs, 0, sizeof(FileAttrs)); |
| json_read_struct(inp, read_file_attrs, &attrs); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| h = find_open_file_info(id); |
| if (h == NULL) { |
| err = EBADF; |
| } |
| else { |
| if (attrs.flags & ATTR_SIZE) { |
| if (ftruncate(h->file, attrs.size) < 0) err = errno; |
| } |
| #if defined(WIN32) || defined(_WRS_KERNEL) |
| if (attrs.flags & ATTR_PERMISSIONS) { |
| if (chmod(h->path, attrs.permissions) < 0) err = errno; |
| } |
| #else |
| if (attrs.flags & ATTR_UIDGID) { |
| if (fchown(h->file, attrs.uid, attrs.gid) < 0) err = errno; |
| } |
| if (attrs.flags & ATTR_PERMISSIONS) { |
| if (fchmod(h->file, attrs.permissions) < 0) err = errno; |
| } |
| #endif |
| if (attrs.flags & ATTR_ACMODTIME) { |
| struct utimbuf buf; |
| buf.actime = (long)(attrs.atime / 1000); |
| buf.modtime = (long)(attrs.mtime / 1000); |
| if (utime(h->path, &buf) < 0) err = errno; |
| } |
| } |
| |
| write_stringz(out, "R"); |
| write_stringz(out, token); |
| write_fs_errno(out, err); |
| out->write(out, MARKER_EOM); |
| } |
| |
| static void command_opendir(char * token, InputStream * inp, OutputStream * out) { |
| char path[FILE_PATH_SIZE]; |
| DIR * dir = NULL; |
| int err = 0; |
| OpenFileInfo * handle = NULL; |
| |
| read_path(inp, path, sizeof(path)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| dir = opendir(path); |
| if (dir == NULL){ |
| err = errno; |
| } |
| else { |
| handle = create_open_file_info(inp, path, -1, dir); |
| } |
| |
| write_stringz(out, "R"); |
| write_stringz(out, token); |
| write_fs_errno(out, err); |
| write_file_handle(out, handle); |
| out->write(out, MARKER_EOM); |
| } |
| |
| static void command_readdir(char * token, InputStream * inp, OutputStream * out) { |
| char id[256]; |
| OpenFileInfo * h = NULL; |
| int err = 0; |
| int eof = 0; |
| |
| json_read_string(inp, id, sizeof(id)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| write_stringz(out, "R"); |
| write_stringz(out, token); |
| |
| h = find_open_file_info(id); |
| if (h == NULL || h->dir == NULL) { |
| write_stringz(out, "null"); |
| err = EBADF; |
| } |
| else { |
| int cnt = 0; |
| out->write(out, '['); |
| while (cnt < 64) { |
| struct dirent * e; |
| char path[FILE_PATH_SIZE]; |
| struct_stat st; |
| FileAttrs attrs; |
| errno = 0; |
| e = readdir(h->dir); |
| if (e == NULL) { |
| err = errno; |
| if (err == 0) eof = 1; |
| break; |
| } |
| if (strcmp(e->d_name, ".") == 0) continue; |
| if (strcmp(e->d_name, "..") == 0) continue; |
| if (cnt > 0) out->write(out, ','); |
| out->write(out, '{'); |
| json_write_string(out, "FileName"); |
| out->write(out, ':'); |
| json_write_string(out, e->d_name); |
| memset(&st, 0, sizeof(st)); |
| snprintf(path, sizeof(path), "%s/%s", h->path, e->d_name); |
| if (stat(path, &st) == 0) { |
| fill_attrs(&attrs, &st); |
| out->write(out, ','); |
| json_write_string(out, "Attrs"); |
| out->write(out, ':'); |
| write_file_attrs(out, &attrs); |
| } |
| out->write(out, '}'); |
| cnt++; |
| } |
| out->write(out, ']'); |
| out->write(out, 0); |
| } |
| |
| write_fs_errno(out, err); |
| json_write_boolean(out, eof); |
| out->write(out, 0); |
| out->write(out, MARKER_EOM); |
| } |
| |
| static void command_remove(char * token, InputStream * inp, OutputStream * out) { |
| char path[FILE_PATH_SIZE]; |
| DIR * dir = NULL; |
| int err = 0; |
| |
| read_path(inp, path, sizeof(path)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| if (remove(path) < 0) err = errno; |
| |
| write_stringz(out, "R"); |
| write_stringz(out, token); |
| write_fs_errno(out, err); |
| out->write(out, MARKER_EOM); |
| } |
| |
| static void command_rmdir(char * token, InputStream * inp, OutputStream * out) { |
| char path[FILE_PATH_SIZE]; |
| DIR * dir = NULL; |
| int err = 0; |
| |
| read_path(inp, path, sizeof(path)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| if (rmdir(path) < 0) err = errno; |
| |
| write_stringz(out, "R"); |
| write_stringz(out, token); |
| write_fs_errno(out, err); |
| out->write(out, MARKER_EOM); |
| } |
| |
| static void command_mkdir(char * token, InputStream * inp, OutputStream * out) { |
| char path[FILE_PATH_SIZE]; |
| FileAttrs attrs; |
| int err = 0; |
| int mode = 0777; |
| |
| read_path(inp, path, sizeof(path)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| memset(&attrs, 0, sizeof(FileAttrs)); |
| json_read_struct(inp, read_file_attrs, &attrs); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| if (attrs.flags & ATTR_PERMISSIONS) { |
| mode = attrs.permissions; |
| } |
| #if defined(WIN32) || defined(_WRS_KERNEL) |
| if (mkdir(path) < 0) err = errno; |
| #else |
| if (mkdir(path, mode) < 0) err = errno; |
| #endif |
| |
| write_stringz(out, "R"); |
| write_stringz(out, token); |
| write_fs_errno(out, err); |
| out->write(out, MARKER_EOM); |
| } |
| |
| static void command_realpath(char * token, InputStream * inp, OutputStream * out) { |
| char path[FILE_PATH_SIZE]; |
| char * real = NULL; |
| int err = 0; |
| |
| read_path(inp, path, sizeof(path)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| real = canonicalize_file_name(path); |
| if (real == NULL) err = errno; |
| |
| write_stringz(out, "R"); |
| write_stringz(out, token); |
| write_fs_errno(out, err); |
| json_write_string(out, real); |
| out->write(out, 0); |
| out->write(out, MARKER_EOM); |
| free(real); |
| } |
| |
| static void command_rename(char * token, InputStream * inp, OutputStream * out) { |
| char path[FILE_PATH_SIZE]; |
| char newp[FILE_PATH_SIZE]; |
| int err = 0; |
| |
| read_path(inp, path, sizeof(path)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| read_path(inp, newp, sizeof(newp)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| if (rename(path, newp) < 0) err = errno; |
| |
| write_stringz(out, "R"); |
| write_stringz(out, token); |
| write_fs_errno(out, err); |
| out->write(out, MARKER_EOM); |
| } |
| |
| static void command_readlink(char * token, InputStream * inp, OutputStream * out) { |
| char path[FILE_PATH_SIZE]; |
| char link[FILE_PATH_SIZE]; |
| int err = 0; |
| |
| read_path(inp, path, sizeof(path)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| link[0] = 0; |
| #if defined(WIN32) || defined(_WRS_KERNEL) |
| err = ENOSYS; |
| #else |
| if (readlink(path, link, sizeof(link)) < 0) err = errno; |
| #endif |
| |
| write_stringz(out, "R"); |
| write_stringz(out, token); |
| write_fs_errno(out, err); |
| json_write_string(out, link); |
| out->write(out, 0); |
| out->write(out, MARKER_EOM); |
| } |
| |
| static void command_symlink(char * token, InputStream * inp, OutputStream * out) { |
| char link[FILE_PATH_SIZE]; |
| char target[FILE_PATH_SIZE]; |
| int err = 0; |
| |
| read_path(inp, link, sizeof(link)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| read_path(inp, target, sizeof(target)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| #if defined(WIN32) || defined(_WRS_KERNEL) |
| err = ENOSYS; |
| #else |
| if (symlink(target, link) < 0) err = errno; |
| #endif |
| |
| write_stringz(out, "R"); |
| write_stringz(out, token); |
| write_fs_errno(out, err); |
| out->write(out, MARKER_EOM); |
| } |
| |
| static void command_copy(char * token, InputStream * inp, OutputStream * out) { |
| char src[FILE_PATH_SIZE]; |
| char dst[FILE_PATH_SIZE]; |
| int copy_uidgid; |
| int copy_perms; |
| struct_stat st; |
| int fi = -1; |
| int fo = -1; |
| int err = 0; |
| int64 pos = 0; |
| |
| read_path(inp, src, sizeof(src)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| read_path(inp, dst, sizeof(dst)); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| copy_uidgid = json_read_boolean(inp); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| copy_perms = json_read_boolean(inp); |
| if (inp->read(inp) != 0) exception(ERR_JSON_SYNTAX); |
| if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| |
| if (stat(src, &st) < 0) err = errno; |
| if (err == 0 && (fi = open(src, O_RDONLY | O_BINARY, 0)) < 0) err = errno; |
| if (err == 0 && (fo = open(dst, O_WRONLY | O_BINARY | O_CREAT, 0775)) < 0) err = errno; |
| |
| while (err == 0 && pos < st.st_size) { |
| char buf[BUF_SIZE]; |
| int wr = 0; |
| int rd = read(fi, buf, sizeof(buf)); |
| if (rd == 0) break; |
| if (rd < 0) { |
| err == errno; |
| break; |
| } |
| wr = write(fo, buf, rd); |
| if (wr < 0) { |
| err = errno; |
| break; |
| } |
| if (wr < rd) { |
| err = ENOSPC; |
| break; |
| } |
| pos += rd; |
| } |
| |
| if (fo >= 0 && close(fo) < 0 && err == 0) err = errno; |
| if (fi >= 0 && close(fi) < 0 && err == 0) err = errno; |
| |
| if (err == 0) { |
| struct utimbuf buf; |
| buf.actime = st.st_atime; |
| buf.modtime = st.st_mtime; |
| if (utime(dst, &buf) < 0) err = errno; |
| } |
| if (err == 0 && copy_perms && chmod(dst, st.st_mode) < 0) err = errno; |
| #if !defined(WIN32) && !defined(_WRS_KERNEL) |
| if (err == 0 && copy_uidgid && chown(dst, st.st_uid, st.st_gid) < 0) err = errno; |
| #endif |
| |
| write_stringz(out, "R"); |
| write_stringz(out, token); |
| write_fs_errno(out, err); |
| out->write(out, MARKER_EOM); |
| } |
| |
| static void command_user(char * token, InputStream * inp, OutputStream * out) { |
| if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| write_stringz(out, "R"); |
| write_stringz(out, token); |
| json_write_long(out, getuid()); |
| out->write(out, 0); |
| json_write_long(out, geteuid()); |
| out->write(out, 0); |
| json_write_long(out, getgid()); |
| out->write(out, 0); |
| json_write_long(out, getegid()); |
| out->write(out, 0); |
| json_write_string(out, get_user_home()); |
| out->write(out, 0); |
| |
| out->write(out, MARKER_EOM); |
| } |
| |
| static void command_roots(char * token, InputStream * inp, OutputStream * out) { |
| struct_stat st; |
| int err = 0; |
| int cnt = 0; |
| int disk = 0; |
| |
| if (inp->read(inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); |
| write_stringz(out, "R"); |
| write_stringz(out, token); |
| out->write(out, '['); |
| |
| #ifdef WIN32 |
| for (disk = 'A'; disk <= 'Z'; disk++) { |
| char path[32]; |
| snprintf(path, sizeof(path), "%c:/", disk); |
| memset(&st, 0, sizeof(st)); |
| if (stat(path, &st) == 0) { |
| FileAttrs attrs; |
| if (cnt > 0) out->write(out, ','); |
| out->write(out, '{'); |
| json_write_string(out, "FileName"); |
| out->write(out, ':'); |
| json_write_string(out, path); |
| fill_attrs(&attrs, &st); |
| out->write(out, ','); |
| json_write_string(out, "Attrs"); |
| out->write(out, ':'); |
| write_file_attrs(out, &attrs); |
| out->write(out, '}'); |
| cnt++; |
| } |
| } |
| #elif defined(_WRS_KERNEL) |
| out->write(out, '{'); |
| json_write_string(out, "FileName"); |
| out->write(out, ':'); |
| json_write_string(out, FS_ROOT); |
| memset(&st, 0, sizeof(st)); |
| if (stat("/", &st) == 0) { |
| FileAttrs attrs; |
| fill_attrs(&attrs, &st); |
| out->write(out, ','); |
| json_write_string(out, "Attrs"); |
| out->write(out, ':'); |
| write_file_attrs(out, &attrs); |
| } |
| out->write(out, '}'); |
| #else |
| out->write(out, '{'); |
| json_write_string(out, "FileName"); |
| out->write(out, ':'); |
| json_write_string(out, "/"); |
| memset(&st, 0, sizeof(st)); |
| if (stat("/", &st) == 0) { |
| FileAttrs attrs; |
| fill_attrs(&attrs, &st); |
| out->write(out, ','); |
| json_write_string(out, "Attrs"); |
| out->write(out, ':'); |
| write_file_attrs(out, &attrs); |
| } |
| out->write(out, '}'); |
| #endif |
| |
| out->write(out, ']'); |
| out->write(out, 0); |
| write_fs_errno(out, err); |
| |
| out->write(out, MARKER_EOM); |
| } |
| |
| void ini_file_system_service(void) { |
| int i; |
| |
| add_channel_close_listener(channel_close_listener); |
| list_init(&file_info_ring); |
| for (i = 0; i < HANDLE_HASH_SIZE; i++) { |
| list_init(&handle_hash[i]); |
| } |
| |
| add_command_handler(FILE_SYSTEM, "open", command_open); |
| add_command_handler(FILE_SYSTEM, "close", command_close); |
| add_command_handler(FILE_SYSTEM, "read", command_read); |
| add_command_handler(FILE_SYSTEM, "write", command_write); |
| add_command_handler(FILE_SYSTEM, "stat", command_stat); |
| add_command_handler(FILE_SYSTEM, "lstat", command_lstat); |
| add_command_handler(FILE_SYSTEM, "fstat", command_fstat); |
| add_command_handler(FILE_SYSTEM, "setstat", command_setstat); |
| add_command_handler(FILE_SYSTEM, "fsetstat", command_fsetstat); |
| add_command_handler(FILE_SYSTEM, "opendir", command_opendir); |
| add_command_handler(FILE_SYSTEM, "readdir", command_readdir); |
| add_command_handler(FILE_SYSTEM, "remove", command_remove); |
| add_command_handler(FILE_SYSTEM, "rmdir", command_rmdir); |
| add_command_handler(FILE_SYSTEM, "mkdir", command_mkdir); |
| add_command_handler(FILE_SYSTEM, "realpath", command_realpath); |
| add_command_handler(FILE_SYSTEM, "rename", command_rename); |
| add_command_handler(FILE_SYSTEM, "readlink", command_readlink); |
| add_command_handler(FILE_SYSTEM, "symlink", command_symlink); |
| add_command_handler(FILE_SYSTEM, "copy", command_copy); |
| add_command_handler(FILE_SYSTEM, "user", command_user); |
| add_command_handler(FILE_SYSTEM, "roots", command_roots); |
| } |
| |
| #endif |
| |