⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smbfs.c

📁 Sanos Operating System Kernel ----------------------------- Sanos is an OS kernel for use in PC base
💻 C
📖 第 1 页 / 共 2 页
字号:
    filp->flags |= F_MODIFIED;
    left -= rc;
    p += rc;

    if (filp->pos > file->statbuf.quad.size_low) file->statbuf.quad.size_low = filp->pos;
  }

  return size;
}

int smb_ioctl(struct file *filp, int cmd, void *data, size_t size)
{
  return -ENOSYS;
}

loff_t smb_tell(struct file *filp)
{
  if (filp->flags & F_DIR) return -EBADF;

  return filp->pos;
}

loff_t smb_lseek(struct file *filp, loff_t offset, int origin)
{
  struct smb_file *file = (struct smb_file *) filp->data;

  if (filp->flags & F_DIR) return -EBADF;

  switch (origin)
  {
    case SEEK_END:
      offset += file->statbuf.quad.size_low;
      break;

    case SEEK_CUR:
      offset += filp->pos;
  }

  if (offset < 0) return -EINVAL;

  filp->pos = offset;
  return offset;
}

int smb_chsize(struct file *filp, loff_t size)
{
  struct smb_share *share = (struct smb_share *) filp->fs->data;
  struct smb_file *file = (struct smb_file *) filp->data;
  struct smb_set_fileinfo_request req;
  struct smb_file_end_of_file_info info;
  struct smb_set_fileinfo_response rsp;
  int rc;
  int rsplen;

  memset(&req, 0, sizeof(req));
  req.fid = file->fid;
  req.infolevel = 0x104;

  info.end_of_file = size;

  rsplen = sizeof(rsp);
  rc = smb_trans(share, TRANS2_SET_FILE_INFORMATION, &req, sizeof(req), &info, sizeof(info), &rsp, &rsplen, NULL, NULL);
  if (rc < 0) return rc;

  if (filp->pos > size) filp->pos = size;
  return 0;
}

int smb_futime(struct file *filp, struct utimbuf *times)
{
  struct smb_share *share = (struct smb_share *) filp->fs->data;
  struct smb_file *file = (struct smb_file *) filp->data;
  struct smb_set_fileinfo_request req;
  struct smb_file_basic_info info;
  struct smb_set_fileinfo_response rsp;
  int rc;
  int rsplen;

  memset(&req, 0, sizeof(req));
  req.fid = file->fid;
  req.infolevel = 0x101;

  info.creation_time = time2ft(times->ctime == -1 ? file->statbuf.ctime : times->ctime);
  info.last_access_time = time2ft(times->atime == -1 ? file->statbuf.atime : times->atime);
  info.last_write_time = time2ft(times->mtime == -1 ? file->statbuf.mtime : times->mtime);
  info.change_time = time2ft(times->mtime == -1 ? file->statbuf.mtime : times->mtime);
  info.attributes = file->attrs;

  rsplen = sizeof(rsp);
  rc = smb_trans(share, TRANS2_SET_FILE_INFORMATION, &req, sizeof(req), &info, sizeof(info), &rsp, &rsplen, NULL, NULL);
  if (rc < 0) return rc;

  if (times->ctime != -1) file->statbuf.ctime = times->ctime;
  if (times->mtime != -1) file->statbuf.mtime = times->mtime;
  if (times->atime != -1) file->statbuf.atime = times->atime;

  return 0;
}

int smb_utime(struct fs *fs, char *name, struct utimbuf *times)
{
  struct file filp;
  int rc;

  memset(&filp, 0, sizeof(struct file));
  filp.fs = fs;

  rc = smb_open(&filp, name);
  if (rc < 0) return rc;

  rc = smb_futime(&filp, times);
  
  smb_close(&filp);
  return rc;
}

int smb_fstat(struct file *filp, struct stat *buffer)
{
  struct smb_file *file = (struct smb_file *) filp->data;

  if (filp->flags & F_DIR) return -EBADF;

  if (buffer) memcpy(buffer, &file->statbuf, sizeof(struct stat));

  return file->statbuf.quad.size_low;
}

int smb_stat(struct fs *fs, char *name, struct stat *buffer)
{
  struct smb_share *share = (struct smb_share *) fs->data;
  struct smb_pathinfo_request req;
  struct smb_file_basic_info rspb;
  struct smb_file_standard_info rsps;
  struct smb_dentry *dentry;
  int rsplen;
  short dummy;
  int dummylen;
  int rc;

  rc = smb_convert_filename(name);
  if (rc < 0) return rc;

  // Handle root mount point
  if (!*name)
  {
    if (buffer)
    {
      memset(buffer, 0, sizeof(struct stat));
      buffer->atime = time(0);
      buffer->ctime = share->mounttime;
      buffer->mtime = share->mounttime;
      buffer->mode = FS_DIRECTORY;
      buffer->nlink = 1;
      return 0;
    }
  }

  // Look in cache
  dentry = smb_find_in_cache(share, name);
  if (dentry != NULL)
  {
    if (buffer) memcpy(buffer, &dentry->statbuf, sizeof(struct stat));
    return dentry->statbuf.quad.size_low;
  }

  // Query server for file information
  if (buffer)
  {
    req.infolevel = SMB_QUERY_FILE_BASIC_INFO;
    req.reserved = 0;
    strcpy(req.filename, name);

    rsplen = sizeof(rspb);
    dummylen = sizeof(dummy);
    rc = smb_trans(share, TRANS2_QUERY_PATH_INFORMATION, &req, sizeof(req) - MAXPATH + strlen(name) + 1, NULL, 0, &dummy, &dummylen, &rspb, &rsplen);
    if (rc < 0) return rc;
  }

  req.infolevel = SMB_QUERY_FILE_STANDARD_INFO;
  req.reserved = 0;
  strcpy(req.filename, name);

  rsplen = sizeof(rsps);
  dummylen = sizeof(dummy);
  rc = smb_trans(share, TRANS2_QUERY_PATH_INFORMATION, &req, sizeof(req) - MAXPATH + strlen(name) + 1, NULL, 0, &dummy, &dummylen, &rsps, &rsplen);
  if (rc < 0) return rc;

  if (buffer)
  {
    buffer->mode = 0;
    buffer->ino = 0;
    buffer->nlink = rsps.number_of_links;
    buffer->devno = NODEV;
    buffer->atime = ft2time(rspb.last_access_time);
    buffer->mtime = ft2time(rspb.last_write_time);
    buffer->ctime = ft2time(rspb.creation_time);
    buffer->size = rsps.end_of_file;
    if (rspb.attributes & SMB_FILE_ATTR_DIRECTORY) buffer->mode |= FS_DIRECTORY;
  }

  return (int) rsps.end_of_file;
}

int smb_mkdir(struct fs *fs, char *name)
{
  struct smb_share *share = (struct smb_share *) fs->data;
  struct smb *smb;
  char namebuf[MAXPATH + 1 + 1];
  char *p;
  int rc;

  rc = smb_convert_filename(name);
  if (rc < 0) return rc;

  // Make directory
  smb = smb_init(share, 0);

  p = namebuf;
  *p++ = 4;
  p = addstrz(p, name);

  rc = smb_request(share, smb, SMB_COM_CREATE_DIRECTORY, 0, namebuf, p - namebuf, 1);
  if (rc < 0) return rc;

  return 0;
}

int smb_rmdir(struct fs *fs, char *name)
{
  struct smb_share *share = (struct smb_share *) fs->data;
  struct smb *smb;
  char namebuf[MAXPATH + 1 + 1];
  char *p;
  int rc;

  rc = smb_convert_filename(name);
  if (rc < 0) return rc;

  // Delete directory
  smb = smb_init(share, 0);

  p = namebuf;
  *p++ = 4;
  p = addstrz(p, name);

  rc = smb_request(share, smb, SMB_COM_DELETE_DIRECTORY, 0, namebuf, p - namebuf, 1);
  if (rc < 0) return rc;

  return 0;
}

int smb_rename(struct fs *fs, char *oldname, char *newname)
{
  struct smb_share *share = (struct smb_share *) fs->data;
  struct smb *smb;
  char namebuf[(MAXPATH + 1 + 1) * 2];
  char *p;
  int rc;

  rc = smb_convert_filename(oldname);
  if (rc < 0) return rc;

  rc = smb_convert_filename(newname);
  if (rc < 0) return rc;

  // Rename file
  smb = smb_init(share, 0);

  p = namebuf;
  *p++ = 4;
  p = addstrz(p, oldname);
  *p++ = 4;
  p = addstrz(p, newname);

  rc = smb_request(share, smb, SMB_COM_RENAME, 1, namebuf, p - namebuf, 1);
  if (rc < 0) return rc;

  return 0;
}

int smb_link(struct fs *fs, char *oldname, char *newname)
{
  return -ENOSYS;
}

int smb_unlink(struct fs *fs, char *name)
{
  struct smb_share *share = (struct smb_share *) fs->data;
  struct smb *smb;
  char namebuf[MAXPATH + 1 + 1];
  char *p;
  int rc;

  rc = smb_convert_filename(name);
  if (rc < 0) return rc;

  // Delete file
  smb = smb_init(share, 0);

  p = namebuf;
  *p++ = 4;
  p = addstrz(p, name);

  rc = smb_request(share, smb, SMB_COM_DELETE, 1, namebuf, p - namebuf, 1);
  if (rc < 0) return rc;

  return 0;
}

int smb_opendir(struct file *filp, char *name)
{
  struct smb_share *share = (struct smb_share *) filp->fs->data;
  struct smb_findfirst_request req;
  struct smb_findfirst_response rsp;
  struct smb_directory *dir;
  int rsplen;
  int buflen;
  int rc;

  rc = smb_convert_filename(name);
  if (rc < 0) return rc;

  dir = (struct smb_directory *) kmalloc(sizeof(struct smb_directory));
  if (!dir) return -ENOMEM;

  memset(&req, 0, sizeof(req));
  req.search_attributes = SMB_FILE_ATTR_SYSTEM | SMB_FILE_ATTR_HIDDEN | SMB_FILE_ATTR_DIRECTORY;
  req.flags = SMB_CLOSE_IF_END;
  req.infolevel = 0x101;
  req.search_count = 512;
  strcpy(req.filename, name);
  if (*name) strcat(req.filename, "\\*");

  rsplen = sizeof(rsp);
  buflen = SMB_DIRBUF_SIZE;
  rc = smb_trans(share, TRANS2_FIND_FIRST2, &req, 12 + strlen(req.filename) + 1, NULL, 0, &rsp, &rsplen, dir->buffer, &buflen);
  if (rc < 0) 
  {
    kfree(dir);
    return rc;
  }

  dir->sid = rsp.sid;
  dir->eos = rsp.end_of_search;
  dir->entries_left = rsp.search_count;
  dir->fi = (struct smb_file_directory_info *) dir->buffer;
  strcpy(dir->path, name);

  filp->data = dir;
  return 0;
}

int smb_readdir(struct file *filp, struct dirent *dirp, int count)
{
  struct smb_share *share = (struct smb_share *) filp->fs->data;
  struct smb_directory *dir = (struct smb_directory *) filp->data;
  struct stat statbuf;

  if (count != 1) return -1;

again:
  if (dir->entries_left == 0)
  {
    struct smb_findnext_request req;
    struct smb_findnext_response rsp;
    int rsplen;
    int buflen;
    int rc;

    if (dir->eos) return 0;

    memset(&req, 0, sizeof(req));
    req.sid = dir->sid;
    req.flags = SMB_CONTINUE_BIT | SMB_CLOSE_IF_END;
    req.infolevel = 0x101;
    req.search_count = 512;

    rsplen = sizeof(rsp);
    buflen = SMB_DIRBUF_SIZE;
    rc = smb_trans(share, TRANS2_FIND_NEXT2, &req, sizeof(req), NULL, 0, &rsp, &rsplen, dir->buffer, &buflen);
    if (rc < 0) return rc;

    dir->eos = rsp.end_of_search;
    dir->entries_left = rsp.search_count;
    dir->fi = (struct smb_file_directory_info *) dir->buffer;

    if (dir->entries_left == 0) return 0;
  }

  if (dir->fi->filename[0] == '.' && (dir->fi->filename[1] == 0 || (dir->fi->filename[1] == '.' && dir->fi->filename[2] == 0))) 
  {
    dir->entries_left--;
    dir->fi = (struct smb_file_directory_info *) ((char *) dir->fi + dir->fi->next_entry_offset);
    goto again;
  }

  memset(&statbuf, 0, sizeof(struct stat));
  statbuf.nlink = 1;
  statbuf.ctime = ft2time(dir->fi->creation_time);
  statbuf.mtime = ft2time(dir->fi->last_write_time);
  statbuf.atime = ft2time(dir->fi->last_access_time);
  statbuf.size = dir->fi->end_of_file;
  if (dir->fi->ext_file_attributes & SMB_FILE_ATTR_DIRECTORY) statbuf.mode |= FS_DIRECTORY;

  smb_add_to_cache(share, dir->path, dir->fi->filename, &statbuf);

  dirp->ino = 0;
  dirp->namelen = strlen(dir->fi->filename);
  dirp->reclen = sizeof(struct dirent) - MAXPATH + dirp->namelen + 1;
  strcpy(dirp->name, dir->fi->filename);

  dir->entries_left--;
  dir->fi = (struct smb_file_directory_info *) ((char *) dir->fi + dir->fi->next_entry_offset);

  return 1;
}

struct fsops smbfsops =
{
  0,

  smb_lockfs,
  smb_unlockfs,

  smb_format,
  smb_mount,
  smb_umount,

  smb_statfs,

  smb_open,
  smb_close,
  smb_flush,

  smb_read,
  smb_write,
  smb_ioctl,

  smb_tell,
  smb_lseek,
  smb_chsize,

  smb_futime,
  smb_utime,

  smb_fstat,
  smb_stat,

  smb_mkdir,
  smb_rmdir,

  smb_rename,
  smb_link,
  smb_unlink,

  smb_opendir,
  smb_readdir
};

void init_smbfs()
{
  register_filesystem("smbfs", &smbfsops);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -