📄 vfs_simple.c
字号:
/* Unix SMB/CIFS implementation. simple NTVFS filesystem backend Copyright (C) Andrew Tridgell 2003 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.*//* this implements a very simple NTVFS filesystem backend. this backend largely ignores the POSIX -> CIFS mappings, just doing absolutely minimal work to give a working backend.*/#include "includes.h"#include "system/dir.h"#include "system/filesys.h"#include "svfs.h"#include "system/time.h"#include "lib/util/dlinklist.h"#include "ntvfs/ntvfs.h"#include "ntvfs/simple/proto.h"#ifndef O_DIRECTORY#define O_DIRECTORY 0#endif#define CHECK_READ_ONLY(req) do { if (share_bool_option(ntvfs->ctx->config, SHARE_READONLY, true)) return NT_STATUS_ACCESS_DENIED; } while (0)/* connect to a share - used when a tree_connect operation comes in. For a disk based backend we needs to ensure that the base directory exists (tho it doesn't need to be accessible by the user, that comes later)*/static NTSTATUS svfs_connect(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, const char *sharename){ struct stat st; struct svfs_private *private; struct share_config *scfg = ntvfs->ctx->config; private = talloc(ntvfs, struct svfs_private); NT_STATUS_HAVE_NO_MEMORY(private); private->ntvfs = ntvfs; private->next_search_handle = 0; private->connectpath = talloc_strdup(private, share_string_option(scfg, SHARE_PATH, "")); private->open_files = NULL; private->search = NULL; /* the directory must exist */ if (stat(private->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) { DEBUG(0,("'%s' is not a directory, when connecting to [%s]\n", private->connectpath, sharename)); return NT_STATUS_BAD_NETWORK_NAME; } ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS"); NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type); ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "A:"); NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type); ntvfs->private_data = private; return NT_STATUS_OK;}/* disconnect from a share*/static NTSTATUS svfs_disconnect(struct ntvfs_module_context *ntvfs){ return NT_STATUS_OK;}/* find open file handle given fd*/static struct svfs_file *find_fd(struct svfs_private *private, struct ntvfs_handle *handle){ struct svfs_file *f; void *p; p = ntvfs_handle_get_backend_data(handle, private->ntvfs); if (!p) return NULL; f = talloc_get_type(p, struct svfs_file); if (!f) return NULL; return f;}/* delete a file - the dirtype specifies the file types to include in the search. The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)*/static NTSTATUS svfs_unlink(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_unlink *unl){ char *unix_path; CHECK_READ_ONLY(req); unix_path = svfs_unix_path(ntvfs, req, unl->unlink.in.pattern); /* ignoring wildcards ... */ if (unlink(unix_path) == -1) { return map_nt_error_from_unix(errno); } return NT_STATUS_OK;}/* ioctl interface - we don't do any*/static NTSTATUS svfs_ioctl(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_ioctl *io){ return NT_STATUS_INVALID_PARAMETER;}/* check if a directory exists*/static NTSTATUS svfs_chkpath(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_chkpath *cp){ char *unix_path; struct stat st; unix_path = svfs_unix_path(ntvfs, req, cp->chkpath.in.path); if (stat(unix_path, &st) == -1) { return map_nt_error_from_unix(errno); } if (!S_ISDIR(st.st_mode)) { return NT_STATUS_NOT_A_DIRECTORY; } return NT_STATUS_OK;}/* build a file_id from a stat struct*/static uint64_t svfs_file_id(struct stat *st){ uint64_t ret = st->st_ino; ret <<= 32; ret |= st->st_dev; return ret;}/* approximately map a struct stat to a generic fileinfo struct*/static NTSTATUS svfs_map_fileinfo(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_fileinfo *info, struct stat *st, const char *unix_path){ struct svfs_dir *dir = NULL; char *pattern = NULL; int i; const char *s, *short_name; s = strrchr(unix_path, '/'); if (s) { short_name = s+1; } else { short_name = ""; } asprintf(&pattern, "%s:*", unix_path); if (pattern) { dir = svfs_list_unix(req, req, pattern); } unix_to_nt_time(&info->generic.out.create_time, st->st_ctime); unix_to_nt_time(&info->generic.out.access_time, st->st_atime); unix_to_nt_time(&info->generic.out.write_time, st->st_mtime); unix_to_nt_time(&info->generic.out.change_time, st->st_mtime); info->generic.out.alloc_size = st->st_size; info->generic.out.size = st->st_size; info->generic.out.attrib = svfs_unix_to_dos_attrib(st->st_mode); info->generic.out.alloc_size = st->st_blksize * st->st_blocks; info->generic.out.nlink = st->st_nlink; info->generic.out.directory = S_ISDIR(st->st_mode) ? 1 : 0; info->generic.out.file_id = svfs_file_id(st); /* REWRITE: TODO stuff in here */ info->generic.out.delete_pending = 0; info->generic.out.ea_size = 0; info->generic.out.num_eas = 0; info->generic.out.fname.s = talloc_strdup(req, short_name); info->generic.out.alt_fname.s = talloc_strdup(req, short_name); info->generic.out.compressed_size = 0; info->generic.out.format = 0; info->generic.out.unit_shift = 0; info->generic.out.chunk_shift = 0; info->generic.out.cluster_shift = 0; info->generic.out.access_flags = 0; info->generic.out.position = 0; info->generic.out.mode = 0; info->generic.out.alignment_requirement = 0; info->generic.out.reparse_tag = 0; info->generic.out.num_streams = 0; /* setup a single data stream */ info->generic.out.num_streams = 1 + (dir?dir->count:0); info->generic.out.streams = talloc_array(req, struct stream_struct, info->generic.out.num_streams); if (!info->generic.out.streams) { return NT_STATUS_NO_MEMORY; } info->generic.out.streams[0].size = st->st_size; info->generic.out.streams[0].alloc_size = st->st_size; info->generic.out.streams[0].stream_name.s = talloc_strdup(req,"::$DATA"); for (i=0;dir && i<dir->count;i++) { s = strchr(dir->files[i].name, ':'); info->generic.out.streams[1+i].size = dir->files[i].st.st_size; info->generic.out.streams[1+i].alloc_size = dir->files[i].st.st_size; info->generic.out.streams[1+i].stream_name.s = s?s:dir->files[i].name; } return NT_STATUS_OK;}/* return info on a pathname*/static NTSTATUS svfs_qpathinfo(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_fileinfo *info){ char *unix_path; struct stat st; DEBUG(19,("svfs_qpathinfo: file %s level 0x%x\n", info->generic.in.file.path, info->generic.level)); if (info->generic.level != RAW_FILEINFO_GENERIC) { return ntvfs_map_qpathinfo(ntvfs, req, info); } unix_path = svfs_unix_path(ntvfs, req, info->generic.in.file.path); DEBUG(19,("svfs_qpathinfo: file %s\n", unix_path)); if (stat(unix_path, &st) == -1) { DEBUG(19,("svfs_qpathinfo: file %s errno=%d\n", unix_path, errno)); return map_nt_error_from_unix(errno); } DEBUG(19,("svfs_qpathinfo: file %s, stat done\n", unix_path)); return svfs_map_fileinfo(ntvfs, req, info, &st, unix_path);}/* query info on a open file*/static NTSTATUS svfs_qfileinfo(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_fileinfo *info){ struct svfs_private *private = ntvfs->private_data; struct svfs_file *f; struct stat st; if (info->generic.level != RAW_FILEINFO_GENERIC) { return ntvfs_map_qfileinfo(ntvfs, req, info); } f = find_fd(private, info->generic.in.file.ntvfs); if (!f) { return NT_STATUS_INVALID_HANDLE; } if (fstat(f->fd, &st) == -1) { return map_nt_error_from_unix(errno); } return svfs_map_fileinfo(ntvfs, req,info, &st, f->name);}/* open a file*/static NTSTATUS svfs_open(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_open *io){ struct svfs_private *private = ntvfs->private_data; char *unix_path; struct stat st; int fd, flags; struct svfs_file *f; int create_flags, rdwr_flags; bool readonly; NTSTATUS status; struct ntvfs_handle *handle; if (io->generic.level != RAW_OPEN_GENERIC) { return ntvfs_map_open(ntvfs, req, io); } readonly = share_bool_option(ntvfs->ctx->config, SHARE_READONLY, SHARE_READONLY_DEFAULT); if (readonly) { create_flags = 0; rdwr_flags = O_RDONLY; } else { create_flags = O_CREAT; rdwr_flags = O_RDWR; } unix_path = svfs_unix_path(ntvfs, req, io->ntcreatex.in.fname); switch (io->generic.in.open_disposition) { case NTCREATEX_DISP_SUPERSEDE: case NTCREATEX_DISP_OVERWRITE_IF: flags = create_flags | O_TRUNC; break; case NTCREATEX_DISP_OPEN: case NTCREATEX_DISP_OVERWRITE: flags = 0; break; case NTCREATEX_DISP_CREATE: flags = create_flags | O_EXCL; break; case NTCREATEX_DISP_OPEN_IF: flags = create_flags; break; default: flags = 0; break; } flags |= rdwr_flags; if (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) { flags = O_RDONLY | O_DIRECTORY; if (readonly) { goto do_open; } switch (io->generic.in.open_disposition) { case NTCREATEX_DISP_CREATE: if (mkdir(unix_path, 0755) == -1) { DEBUG(9,("svfs_open: mkdir %s errno=%d\n", unix_path, errno)); return map_nt_error_from_unix(errno); } break; case NTCREATEX_DISP_OPEN_IF: if (mkdir(unix_path, 0755) == -1 && errno != EEXIST) { DEBUG(9,("svfs_open: mkdir %s errno=%d\n", unix_path, errno)); return map_nt_error_from_unix(errno); } break; } }do_open: fd = open(unix_path, flags, 0644); if (fd == -1) { return map_nt_error_from_unix(errno); } if (fstat(fd, &st) == -1) { DEBUG(9,("svfs_open: fstat errno=%d\n", errno)); close(fd); return map_nt_error_from_unix(errno); } status = ntvfs_handle_new(ntvfs, req, &handle); NT_STATUS_NOT_OK_RETURN(status); f = talloc(handle, struct svfs_file); NT_STATUS_HAVE_NO_MEMORY(f); f->fd = fd; f->name = talloc_strdup(f, unix_path); NT_STATUS_HAVE_NO_MEMORY(f->name); DLIST_ADD(private->open_files, f); status = ntvfs_handle_set_backend_data(handle, ntvfs, f); NT_STATUS_NOT_OK_RETURN(status); ZERO_STRUCT(io->generic.out); unix_to_nt_time(&io->generic.out.create_time, st.st_ctime); unix_to_nt_time(&io->generic.out.access_time, st.st_atime); unix_to_nt_time(&io->generic.out.write_time, st.st_mtime); unix_to_nt_time(&io->generic.out.change_time, st.st_mtime); io->generic.out.file.ntvfs = handle; io->generic.out.alloc_size = st.st_size; io->generic.out.size = st.st_size; io->generic.out.attrib = svfs_unix_to_dos_attrib(st.st_mode); io->generic.out.is_directory = S_ISDIR(st.st_mode) ? 1 : 0; return NT_STATUS_OK;}/* create a directory*/static NTSTATUS svfs_mkdir(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_mkdir *md){ char *unix_path; CHECK_READ_ONLY(req); if (md->generic.level != RAW_MKDIR_MKDIR) { return NT_STATUS_INVALID_LEVEL; } unix_path = svfs_unix_path(ntvfs, req, md->mkdir.in.path); if (mkdir(unix_path, 0777) == -1) { return map_nt_error_from_unix(errno); } return NT_STATUS_OK;}/* remove a directory*/static NTSTATUS svfs_rmdir(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, struct smb_rmdir *rd){ char *unix_path; CHECK_READ_ONLY(req); unix_path = svfs_unix_path(ntvfs, req, rd->in.path); if (rmdir(unix_path) == -1) { return map_nt_error_from_unix(errno); } return NT_STATUS_OK;}/* rename a set of files*/static NTSTATUS svfs_rename(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_rename *ren){ char *unix_path1, *unix_path2; CHECK_READ_ONLY(req); if (ren->generic.level != RAW_RENAME_RENAME) { return NT_STATUS_INVALID_LEVEL; } unix_path1 = svfs_unix_path(ntvfs, req, ren->rename.in.pattern1); unix_path2 = svfs_unix_path(ntvfs, req, ren->rename.in.pattern2); if (rename(unix_path1, unix_path2) == -1) { return map_nt_error_from_unix(errno); } return NT_STATUS_OK;}/* copy a set of files*/static NTSTATUS svfs_copy(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, struct smb_copy *cp){ return NT_STATUS_NOT_SUPPORTED;}/* read from a file*/static NTSTATUS svfs_read(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_read *rd){ struct svfs_private *private = ntvfs->private_data; struct svfs_file *f; ssize_t ret; if (rd->generic.level != RAW_READ_READX) { return NT_STATUS_NOT_SUPPORTED; } f = find_fd(private, rd->readx.in.file.ntvfs); if (!f) { return NT_STATUS_INVALID_HANDLE; } ret = pread(f->fd, rd->readx.out.data, rd->readx.in.maxcnt, rd->readx.in.offset); if (ret == -1) { return map_nt_error_from_unix(errno); } rd->readx.out.nread = ret; rd->readx.out.remaining = 0; /* should fill this in? */ rd->readx.out.compaction_mode = 0; return NT_STATUS_OK;}/* write to a file*/static NTSTATUS svfs_write(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_write *wr){ struct svfs_private *private = ntvfs->private_data; struct svfs_file *f; ssize_t ret; if (wr->generic.level != RAW_WRITE_WRITEX) { return ntvfs_map_write(ntvfs, req, wr); } CHECK_READ_ONLY(req); f = find_fd(private, wr->writex.in.file.ntvfs); if (!f) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -