📄 libsmbclient.c
字号:
/* * Set file info on an SMB server. Use setpathinfo call first. If that * fails, use setattrE.. * * Access and modification time parameters are always used and must be * provided. Create time, if zero, will be determined from the actual create * time of the file. If non-zero, the create time will be set as well. * * "mode" (attributes) parameter may be set to -1 if it is not to be set. */static BOOLsmbc_setatr(SMBCCTX * context, SMBCSRV *srv, char *path, time_t c_time, time_t a_time, time_t m_time, uint16 mode){ int fd; int ret; /* * Get the create time of the file (if not provided); we'll need it in * the set call. */ if (! srv->no_pathinfo && c_time == 0) { if (! cli_qpathinfo(&srv->cli, path, &c_time, NULL, NULL, NULL, NULL)) { /* qpathinfo not available */ srv->no_pathinfo = True; } else { /* * We got a creation time. Some OS versions don't * return a valid create time, though. If we got an * invalid time, start with the current time instead. */ if (c_time == 0 || c_time == (time_t) -1) { c_time = time(NULL); } /* * We got a creation time. For sanity sake, since * there is no POSIX function to set the create time * of a file, if the existing create time is greater * than either of access time or modification time, * set create time to the smallest of those. This * ensure that the create time of a file is never * greater than its last access or modification time. */ if (c_time > a_time) c_time = a_time; if (c_time > m_time) c_time = m_time; } } /* * First, try setpathinfo (if qpathinfo succeeded), for it is the * modern function for "new code" to be using, and it works given a * filename rather than requiring that the file be opened to have its * attributes manipulated. */ if (srv->no_pathinfo || ! cli_setpathinfo(&srv->cli, path, c_time, a_time, m_time, mode)) { /* * setpathinfo is not supported; go to plan B. * * cli_setatr() does not work on win98, and it also doesn't * support setting the access time (only the modification * time), so in all cases, we open the specified file and use * cli_setattrE() which should work on all OS versions, and * supports both times. */ /* Don't try {q,set}pathinfo() again, with this server */ srv->no_pathinfo = True; /* Open the file */ if ((fd = cli_open(&srv->cli, path, O_RDWR, DENY_NONE)) < 0) { errno = smbc_errno(context, &srv->cli); return -1; } /* * Get the creat time of the file (if it wasn't provided). * We'll need it in the set call */ if (c_time == 0) { ret = cli_getattrE(&srv->cli, fd, NULL, NULL, &c_time, NULL, NULL); } else { ret = True; } /* If we got create time, set times */ if (ret) { /* Some OS versions don't support create time */ if (c_time == 0 || c_time == -1) { c_time = time(NULL); } /* * For sanity sake, since there is no POSIX function * to set the create time of a file, if the existing * create time is greater than either of access time * or modification time, set create time to the * smallest of those. This ensure that the create * time of a file is never greater than its last * access or modification time. */ if (c_time > a_time) c_time = a_time; if (c_time > m_time) c_time = m_time; /* Set the new attributes */ ret = cli_setattrE(&srv->cli, fd, c_time, a_time, m_time); cli_close(&srv->cli, fd); } /* * Unfortunately, setattrE() doesn't have a provision for * setting the access mode (attributes). We'll have to try * cli_setatr() for that, and with only this parameter, it * seems to work on win98. */ if (ret && mode != (uint16) -1) { ret = cli_setatr(&srv->cli, path, mode, 0); } if (! ret) { errno = smbc_errno(context, &srv->cli); return False; } } return True;} /* * Routine to unlink() a file */static intsmbc_unlink_ctx(SMBCCTX *context, const char *fname){ fstring server, share, user, password, workgroup; pstring path, targetpath; struct cli_state *targetcli; SMBCSRV *srv = NULL; if (!context || !context->internal || !context->internal->_initialized) { errno = EINVAL; /* Best I can think of ... */ return -1; } if (!fname) { errno = EINVAL; return -1; } if (smbc_parse_path(context, fname, server, sizeof(server), share, sizeof(share), path, sizeof(path), user, sizeof(user), password, sizeof(password), NULL, 0)) { errno = EINVAL; return -1; } if (user[0] == (char)0) fstrcpy(user, context->user); fstrcpy(workgroup, context->workgroup); srv = smbc_server(context, True, server, share, workgroup, user, password); if (!srv) { return -1; /* smbc_server sets errno */ } /*d_printf(">>>unlink: resolving %s\n", path);*/ if (!cli_resolve_path( "", &srv->cli, path, &targetcli, targetpath)) { d_printf("Could not resolve %s\n", path); return -1; } /*d_printf(">>>unlink: resolved path as %s\n", targetpath);*/ if (!cli_unlink(targetcli, targetpath)) { errno = smbc_errno(context, targetcli); if (errno == EACCES) { /* Check if the file is a directory */ int saverr = errno; SMB_OFF_T size = 0; uint16 mode = 0; time_t m_time = 0, a_time = 0, c_time = 0; SMB_INO_T ino = 0; if (!smbc_getatr(context, srv, path, &mode, &size, &c_time, &a_time, &m_time, &ino)) { /* Hmmm, bad error ... What? */ errno = smbc_errno(context, targetcli); return -1; } else { if (IS_DOS_DIR(mode)) errno = EISDIR; else errno = saverr; /* Restore this */ } } return -1; } return 0; /* Success ... */}/* * Routine to rename() a file */static intsmbc_rename_ctx(SMBCCTX *ocontext, const char *oname, SMBCCTX *ncontext, const char *nname){ fstring server1; fstring share1; fstring server2; fstring share2; fstring user1; fstring user2; fstring password1; fstring password2; fstring workgroup; pstring path1; pstring path2; pstring targetpath1; pstring targetpath2; struct cli_state *targetcli1; struct cli_state *targetcli2; SMBCSRV *srv = NULL; if (!ocontext || !ncontext || !ocontext->internal || !ncontext->internal || !ocontext->internal->_initialized || !ncontext->internal->_initialized) { errno = EINVAL; /* Best I can think of ... */ return -1; } if (!oname || !nname) { errno = EINVAL; return -1; } DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname)); smbc_parse_path(ocontext, oname, server1, sizeof(server1), share1, sizeof(share1), path1, sizeof(path1), user1, sizeof(user1), password1, sizeof(password1), NULL, 0); if (user1[0] == (char)0) fstrcpy(user1, ocontext->user); smbc_parse_path(ncontext, nname, server2, sizeof(server2), share2, sizeof(share2), path2, sizeof(path2), user2, sizeof(user2), password2, sizeof(password2), NULL, 0); if (user2[0] == (char)0) fstrcpy(user2, ncontext->user); if (strcmp(server1, server2) || strcmp(share1, share2) || strcmp(user1, user2)) { /* Can't rename across file systems, or users?? */ errno = EXDEV; return -1; } fstrcpy(workgroup, ocontext->workgroup); srv = smbc_server(ocontext, True, server1, share1, workgroup, user1, password1); if (!srv) { return -1; } /*d_printf(">>>rename: resolving %s\n", path1);*/ if (!cli_resolve_path( "", &srv->cli, path1, &targetcli1, targetpath1)) { d_printf("Could not resolve %s\n", path1); return -1; } /*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/ /*d_printf(">>>rename: resolving %s\n", path2);*/ if (!cli_resolve_path( "", &srv->cli, path2, &targetcli2, targetpath2)) { d_printf("Could not resolve %s\n", path2); return -1; } /*d_printf(">>>rename: resolved path as %s\n", targetpath2);*/ if (strcmp(targetcli1->desthost, targetcli2->desthost) || strcmp(targetcli1->share, targetcli2->share)) { /* can't rename across file systems */ errno = EXDEV; return -1; } if (!cli_rename(targetcli1, targetpath1, targetpath2)) { int eno = smbc_errno(ocontext, targetcli1); if (eno != EEXIST || !cli_unlink(targetcli1, targetpath2) || !cli_rename(targetcli1, targetpath1, targetpath2)) { errno = eno; return -1; } } return 0; /* Success */}/* * A routine to lseek() a file */static off_tsmbc_lseek_ctx(SMBCCTX *context, SMBCFILE *file, off_t offset, int whence){ SMB_OFF_T size; fstring server, share, user, password; pstring path, targetpath; struct cli_state *targetcli; if (!context || !context->internal || !context->internal->_initialized) { errno = EINVAL; return -1; } if (!file || !DLIST_CONTAINS(context->internal->_files, file)) { errno = EBADF; return -1; } if (!file->file) { errno = EINVAL; return -1; /* Can't lseek a dir ... */ } switch (whence) { case SEEK_SET: file->offset = offset; break; case SEEK_CUR: file->offset += offset; break; case SEEK_END: /*d_printf(">>>lseek: parsing %s\n", file->fname);*/ if (smbc_parse_path(context, file->fname, server, sizeof(server), share, sizeof(share), path, sizeof(path), user, sizeof(user), password, sizeof(password), NULL, 0)) { errno = EINVAL; return -1; } /*d_printf(">>>lseek: resolving %s\n", path);*/ if (!cli_resolve_path("", &file->srv->cli, path, &targetcli, targetpath)) { d_printf("Could not resolve %s\n", path); return -1; } /*d_printf(">>>lseek: resolved path as %s\n", targetpath);*/ if (!cli_qfileinfo(targetcli, file->cli_fd, NULL, &size, NULL, NULL, NULL, NULL, NULL)) { SMB_OFF_T b_size = size; if (!cli_getattrE(targetcli, file->cli_fd, NULL, &b_size, NULL, NULL, NULL)) { errno = EINVAL; return -1; } else size = b_size; } file->offset = size + offset; break; default: errno = EINVAL; break; } return file->offset;}/* * Generate an inode number from file name for those things that need it */static ino_tsmbc_inode(SMBCCTX *context, const char *name){ if (!context || !context->internal || !context->internal->_initialized) { errno = EINVAL; return -1; } if (!*name) return 2; /* FIXME, why 2 ??? */ return (ino_t)str_checksum(name);}/* * Routine to put basic stat info into a stat structure ... Used by stat and * fstat below. */static intsmbc_setup_stat(SMBCCTX *context, struct stat *st, char *fname, SMB_OFF_T size, int mode){ st->st_mode = 0; if (IS_DOS_DIR(mode)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -