SMBCFILE * SMBC_open_print_job_ctx(SMBCCTX *context, const char *fname) { char *server = NULL; char *share = NULL; char *user = NULL; char *password = NULL; char *path = NULL; TALLOC_CTX *frame = talloc_stackframe(); if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); return NULL; } if (!fname) { errno = EINVAL; TALLOC_FREE(frame); return NULL; } DEBUG(4, ("SMBC_open_print_job_ctx(%s)\n", fname)); if (SMBC_parse_path(frame, context, fname, NULL, &server, &share, &path, &user, &password, NULL)) { errno = EINVAL; TALLOC_FREE(frame); return NULL; } /* What if the path is empty, or the file exists? */ TALLOC_FREE(frame); return smbc_getFunctionOpen(context)(context, fname, O_WRONLY, 666); }
SMBCFILE * SMBC_open_ctx(SMBCCTX *context, const char *fname, int flags, mode_t mode) { char *server = NULL; char *share = NULL; char *user = NULL; char *password = NULL; char *workgroup = NULL; char *path = NULL; char *targetpath = NULL; struct cli_state *targetcli = NULL; SMBCSRV *srv = NULL; SMBCFILE *file = NULL; uint16_t fd; uint16_t port = 0; NTSTATUS status = NT_STATUS_OBJECT_PATH_INVALID; TALLOC_CTX *frame = talloc_stackframe(); if (!context || !context->internal->initialized) { errno = EINVAL; /* Best I can think of ... */ TALLOC_FREE(frame); return NULL; } if (!fname) { errno = EINVAL; TALLOC_FREE(frame); return NULL; } if (SMBC_parse_path(frame, context, fname, &workgroup, &server, &port, &share, &path, &user, &password, NULL)) { errno = EINVAL; TALLOC_FREE(frame); return NULL; } if (!user || user[0] == (char)0) { user = talloc_strdup(frame, smbc_getUser(context)); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); return NULL; } } srv = SMBC_server(frame, context, True, server, port, share, &workgroup, &user, &password); if (!srv) { if (errno == EPERM) errno = EACCES; TALLOC_FREE(frame); return NULL; /* SMBC_server sets errno */ } /* Hmmm, the test for a directory is suspect here ... FIXME */ if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') { status = NT_STATUS_OBJECT_PATH_INVALID; } else { file = SMB_MALLOC_P(SMBCFILE); if (!file) { errno = ENOMEM; TALLOC_FREE(frame); return NULL; } ZERO_STRUCTP(file); /*d_printf(">>>open: resolving %s\n", path);*/ status = cli_resolve_path( frame, "", context->internal->auth_info, srv->cli, path, &targetcli, &targetpath); if (!NT_STATUS_IS_OK(status)) { d_printf("Could not resolve %s\n", path); errno = ENOENT; SAFE_FREE(file); TALLOC_FREE(frame); return NULL; } /*d_printf(">>>open: resolved %s as %s\n", path, targetpath);*/ status = cli_open(targetcli, targetpath, flags, context->internal->share_mode, &fd); if (!NT_STATUS_IS_OK(status)) { /* Handle the error ... */ SAFE_FREE(file); errno = SMBC_errno(context, targetcli); TALLOC_FREE(frame); return NULL; } /* Fill in file struct */ file->cli_fd = fd; file->fname = SMB_STRDUP(fname); file->srv = srv; file->offset = 0; file->file = True; /* * targetcli is either equal to srv->cli or * is a subsidiary DFS connection. Either way * file->cli_fd belongs to it so we must cache * it for read/write/close, not re-resolve each time. * Re-resolving is both slow and incorrect. */ file->targetcli = targetcli; DLIST_ADD(context->internal->files, file); /* * If the file was opened in O_APPEND mode, all write * operations should be appended to the file. To do that, * though, using this protocol, would require a getattrE() * call for each and every write, to determine where the end * of the file is. (There does not appear to be an append flag * in the protocol.) Rather than add all of that overhead of * retrieving the current end-of-file offset prior to each * write operation, we'll assume that most append operations * will continuously write, so we'll just set the offset to * the end of the file now and hope that's adequate. * * Note to self: If this proves inadequate, and O_APPEND * should, in some cases, be forced for each write, add a * field in the context options structure, for * "strict_append_mode" which would select between the current * behavior (if FALSE) or issuing a getattrE() prior to each * write and forcing the write to the end of the file (if * TRUE). Adding that capability will likely require adding * an "append" flag into the _SMBCFILE structure to track * whether a file was opened in O_APPEND mode. -- djl */ if (flags & O_APPEND) { if (SMBC_lseek_ctx(context, file, 0, SEEK_END) < 0) { (void) SMBC_close_ctx(context, file); errno = ENXIO; TALLOC_FREE(frame); return NULL; } } TALLOC_FREE(frame); return file; } /* Check if opendir needed ... */ if (!NT_STATUS_IS_OK(status)) { int eno = 0; eno = SMBC_errno(context, srv->cli); file = smbc_getFunctionOpendir(context)(context, fname); if (!file) errno = eno; TALLOC_FREE(frame); return file; } errno = EINVAL; /* FIXME, correct errno ? */ TALLOC_FREE(frame); return NULL; }
int SMBC_fstat_ctx(SMBCCTX *context, SMBCFILE *file, struct stat *st) { struct timespec change_time_ts; struct timespec access_time_ts; struct timespec write_time_ts; SMB_OFF_T size; uint16 mode; char *server = NULL; char *share = NULL; char *user = NULL; char *password = NULL; char *path = NULL; char *targetpath = NULL; struct cli_state *targetcli = NULL; SMB_INO_T ino = 0; TALLOC_CTX *frame = talloc_stackframe(); NTSTATUS status; if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); return -1; } if (!file || !SMBC_dlist_contains(context->internal->files, file)) { errno = EBADF; TALLOC_FREE(frame); return -1; } if (!file->file) { TALLOC_FREE(frame); return smbc_getFunctionFstatdir(context)(context, file, st); } /*d_printf(">>>fstat: parsing %s\n", file->fname);*/ if (SMBC_parse_path(frame, context, file->fname, NULL, &server, &share, &path, &user, &password, NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } /*d_printf(">>>fstat: resolving %s\n", path);*/ status = cli_resolve_path(frame, "", context->internal->auth_info, file->srv->cli, path, &targetcli, &targetpath); if (!NT_STATUS_IS_OK(status)) { d_printf("Could not resolve %s\n", path); errno = ENOENT; TALLOC_FREE(frame); return -1; } /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/ if (!NT_STATUS_IS_OK(cli_qfileinfo_basic( targetcli, file->cli_fd, &mode, &size, NULL, &access_time_ts, &write_time_ts, &change_time_ts, &ino))) { time_t change_time, access_time, write_time; if (!NT_STATUS_IS_OK(cli_getattrE(targetcli, file->cli_fd, &mode, &size, &change_time, &access_time, &write_time))) { errno = EINVAL; TALLOC_FREE(frame); return -1; } change_time_ts = convert_time_t_to_timespec(change_time); access_time_ts = convert_time_t_to_timespec(access_time); write_time_ts = convert_time_t_to_timespec(write_time); } st->st_ino = ino; setup_stat(context, st, file->fname, size, mode); st->st_atime = convert_timespec_to_time_t(access_time_ts); st->st_ctime = convert_timespec_to_time_t(change_time_ts); st->st_mtime = convert_timespec_to_time_t(write_time_ts); st->st_dev = file->srv->dev; TALLOC_FREE(frame); return 0; }
int SMBC_stat_ctx(SMBCCTX *context, const char *fname, struct stat *st) { SMBCSRV *srv = NULL; char *server = NULL; char *share = NULL; char *user = NULL; char *password = NULL; char *workgroup = NULL; char *path = NULL; struct timespec write_time_ts; struct timespec access_time_ts; struct timespec change_time_ts; SMB_OFF_T size = 0; uint16 mode = 0; SMB_INO_T ino = 0; TALLOC_CTX *frame = talloc_stackframe(); if (!context || !context->internal->initialized) { errno = EINVAL; /* Best I can think of ... */ TALLOC_FREE(frame); return -1; } if (!fname) { errno = EINVAL; TALLOC_FREE(frame); return -1; } DEBUG(4, ("smbc_stat(%s)\n", fname)); if (SMBC_parse_path(frame, context, fname, &workgroup, &server, &share, &path, &user, &password, NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } if (!user || user[0] == (char)0) { user = talloc_strdup(frame, smbc_getUser(context)); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); return -1; } } srv = SMBC_server(frame, context, True, server, share, &workgroup, &user, &password); if (!srv) { TALLOC_FREE(frame); return -1; /* errno set by SMBC_server */ } if (!SMBC_getatr(context, srv, path, &mode, &size, NULL, &access_time_ts, &write_time_ts, &change_time_ts, &ino)) { errno = SMBC_errno(context, srv->cli); TALLOC_FREE(frame); return -1; } st->st_ino = ino; setup_stat(context, st, fname, size, mode); st->st_atime = convert_timespec_to_time_t(access_time_ts); st->st_ctime = convert_timespec_to_time_t(change_time_ts); st->st_mtime = convert_timespec_to_time_t(write_time_ts); st->st_dev = srv->dev; TALLOC_FREE(frame); return 0; }
int SMBC_ftruncate_ctx(SMBCCTX *context, SMBCFILE *file, off_t length) { off_t size = length; char *server = NULL; char *share = NULL; char *user = NULL; char *password = NULL; char *path = NULL; char *targetpath = NULL; struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); NTSTATUS status; if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); return -1; } if (!file || !SMBC_dlist_contains(context->internal->files, file)) { errno = EBADF; TALLOC_FREE(frame); return -1; } if (!file->file) { errno = EINVAL; TALLOC_FREE(frame); return -1; } /*d_printf(">>>fstat: parsing %s\n", file->fname);*/ if (SMBC_parse_path(frame, context, file->fname, NULL, &server, &share, &path, &user, &password, NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } /*d_printf(">>>fstat: resolving %s\n", path);*/ status = cli_resolve_path(frame, "", context->internal->auth_info, file->srv->cli, path, &targetcli, &targetpath); if (!NT_STATUS_IS_OK(status)) { d_printf("Could not resolve %s\n", path); errno = ENOENT; TALLOC_FREE(frame); return -1; } /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/ if (!NT_STATUS_IS_OK(cli_ftruncate(targetcli, file->cli_fd, (uint64_t)size))) { errno = EINVAL; TALLOC_FREE(frame); return -1; } TALLOC_FREE(frame); return 0; }
off_t SMBC_lseek_ctx(SMBCCTX *context, SMBCFILE *file, off_t offset, int whence) { off_t size; char *server = NULL, *share = NULL, *user = NULL, *password = NULL; char *path = NULL; char *targetpath = NULL; struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); NTSTATUS status; if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); return -1; } if (!file || !SMBC_dlist_contains(context->internal->files, file)) { errno = EBADF; TALLOC_FREE(frame); return -1; } if (!file->file) { errno = EINVAL; TALLOC_FREE(frame); 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(frame, context, file->fname, NULL, &server, &share, &path, &user, &password, NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } /*d_printf(">>>lseek: resolving %s\n", path);*/ status = cli_resolve_path( frame, "", context->internal->auth_info, file->srv->cli, path, &targetcli, &targetpath); if (!NT_STATUS_IS_OK(status)) { d_printf("Could not resolve %s\n", path); errno = ENOENT; TALLOC_FREE(frame); return -1; } /*d_printf(">>>lseek: resolved path as %s\n", targetpath);*/ if (!NT_STATUS_IS_OK(cli_qfileinfo_basic( targetcli, file->cli_fd, NULL, &size, NULL, NULL, NULL, NULL, NULL))) { off_t b_size = size; if (!NT_STATUS_IS_OK(cli_getattrE(targetcli, file->cli_fd, NULL, &b_size, NULL, NULL, NULL))) { errno = EINVAL; TALLOC_FREE(frame); return -1; } else size = b_size; } file->offset = size + offset; break; default: errno = EINVAL; break; } TALLOC_FREE(frame); return file->offset; }
int SMBC_close_ctx(SMBCCTX *context, SMBCFILE *file) { SMBCSRV *srv; char *server = NULL, *share = NULL, *user = NULL, *password = NULL; char *path = NULL; char *targetpath = NULL; struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); NTSTATUS status; if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); return -1; } if (!file || !SMBC_dlist_contains(context->internal->files, file)) { errno = EBADF; TALLOC_FREE(frame); return -1; } /* IS a dir ... */ if (!file->file) { TALLOC_FREE(frame); return smbc_getFunctionClosedir(context)(context, file); } /*d_printf(">>>close: parsing %s\n", file->fname);*/ if (SMBC_parse_path(frame, context, file->fname, NULL, &server, &share, &path, &user, &password, NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } /*d_printf(">>>close: resolving %s\n", path);*/ status = cli_resolve_path(frame, "", context->internal->auth_info, file->srv->cli, path, &targetcli, &targetpath); if (!NT_STATUS_IS_OK(status)) { d_printf("Could not resolve %s\n", path); errno = ENOENT; TALLOC_FREE(frame); return -1; } /*d_printf(">>>close: resolved path as %s\n", targetpath);*/ if (!NT_STATUS_IS_OK(cli_close(targetcli, file->cli_fd))) { DEBUG(3, ("cli_close failed on %s. purging server.\n", file->fname)); /* Deallocate slot and remove the server * from the server cache if unused */ errno = SMBC_errno(context, targetcli); srv = file->srv; DLIST_REMOVE(context->internal->files, file); SAFE_FREE(file->fname); SAFE_FREE(file); smbc_getFunctionRemoveUnusedServer(context)(context, srv); TALLOC_FREE(frame); return -1; } DLIST_REMOVE(context->internal->files, file); SAFE_FREE(file->fname); SAFE_FREE(file); TALLOC_FREE(frame); return 0; }
ssize_t SMBC_write_ctx(SMBCCTX *context, SMBCFILE *file, const void *buf, size_t count) { off_t offset; char *server = NULL, *share = NULL, *user = NULL, *password = NULL; char *path = NULL; char *targetpath = NULL; struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); NTSTATUS status; /* First check all pointers before dereferencing them */ if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); return -1; } if (!file || !SMBC_dlist_contains(context->internal->files, file)) { errno = EBADF; TALLOC_FREE(frame); return -1; } /* Check that the buffer exists ... */ if (buf == NULL) { errno = EINVAL; TALLOC_FREE(frame); return -1; } offset = file->offset; /* See "offset" comment in SMBC_read_ctx() */ /*d_printf(">>>write: parsing %s\n", file->fname);*/ if (SMBC_parse_path(frame, context, file->fname, NULL, &server, &share, &path, &user, &password, NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } /*d_printf(">>>write: resolving %s\n", path);*/ status = cli_resolve_path(frame, "", context->internal->auth_info, file->srv->cli, path, &targetcli, &targetpath); if (!NT_STATUS_IS_OK(status)) { d_printf("Could not resolve %s\n", path); errno = ENOENT; TALLOC_FREE(frame); return -1; } /*d_printf(">>>write: resolved path as %s\n", targetpath);*/ status = cli_writeall(targetcli, file->cli_fd, 0, (const uint8_t *)buf, offset, count, NULL); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); TALLOC_FREE(frame); return -1; } file->offset += count; TALLOC_FREE(frame); return count; /* Success, 0 bytes of data ... */ }
ssize_t SMBC_read_ctx(SMBCCTX *context, SMBCFILE *file, void *buf, size_t count) { size_t ret; char *server = NULL, *share = NULL, *user = NULL, *password = NULL; char *path = NULL; char *targetpath = NULL; struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); NTSTATUS status; /* * offset: * * Compiler bug (possibly) -- gcc (GCC) 3.3.5 (Debian 1:3.3.5-2) -- * appears to pass file->offset (which is type off_t) differently than * a local variable of type off_t. Using local variable "offset" in * the call to cli_read() instead of file->offset fixes a problem * retrieving data at an offset greater than 4GB. */ off_t offset; if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); return -1; } DEBUG(4, ("smbc_read(%p, %d)\n", file, (int)count)); if (!file || !SMBC_dlist_contains(context->internal->files, file)) { errno = EBADF; TALLOC_FREE(frame); return -1; } offset = file->offset; /* Check that the buffer exists ... */ if (buf == NULL) { errno = EINVAL; TALLOC_FREE(frame); return -1; } /*d_printf(">>>read: parsing %s\n", file->fname);*/ if (SMBC_parse_path(frame, context, file->fname, NULL, &server, &share, &path, &user, &password, NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } /*d_printf(">>>read: resolving %s\n", path);*/ status = cli_resolve_path(frame, "", context->internal->auth_info, file->srv->cli, path, &targetcli, &targetpath); if (!NT_STATUS_IS_OK(status)) { d_printf("Could not resolve %s\n", path); errno = ENOENT; TALLOC_FREE(frame); return -1; } /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/ status = cli_read(targetcli, file->cli_fd, (char *)buf, offset, count, &ret); if (!NT_STATUS_IS_OK(status)) { errno = SMBC_errno(context, targetcli); TALLOC_FREE(frame); return -1; } file->offset += ret; DEBUG(4, (" --> %ld\n", (unsigned long)ret)); TALLOC_FREE(frame); return ret; /* Success, ret bytes of data ... */ }
int SMBC_unlink_print_job_ctx(SMBCCTX *context, const char *fname, int id) { SMBCSRV *srv = NULL; char *server = NULL; char *share = NULL; char *user = NULL; char *password = NULL; char *workgroup = NULL; char *path = NULL; int err; TALLOC_CTX *frame = talloc_stackframe(); if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); return -1; } if (!fname) { errno = EINVAL; TALLOC_FREE(frame); return -1; } DEBUG(4, ("smbc_unlink_print_job(%s)\n", fname)); if (SMBC_parse_path(frame, context, fname, &workgroup, &server, &share, &path, &user, &password, NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } if (!user || user[0] == (char)0) { user = talloc_strdup(frame, smbc_getUser(context)); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); return -1; } } srv = SMBC_server(frame, context, True, server, share, &workgroup, &user, &password); if (!srv) { TALLOC_FREE(frame); return -1; /* errno set by SMBC_server */ } if ((err = cli_printjob_del(srv->cli, id)) != 0) { if (err < 0) errno = SMBC_errno(context, srv->cli); else if (err == ERRnosuchprintjob) errno = EINVAL; TALLOC_FREE(frame); return -1; } TALLOC_FREE(frame); return 0; }
int SMBC_list_print_jobs_ctx(SMBCCTX *context, const char *fname, smbc_list_print_job_fn fn) { SMBCSRV *srv = NULL; char *server = NULL; char *share = NULL; char *user = NULL; char *password = NULL; char *workgroup = NULL; char *path = NULL; TALLOC_CTX *frame = talloc_stackframe(); if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); return -1; } if (!fname) { errno = EINVAL; TALLOC_FREE(frame); return -1; } DEBUG(4, ("smbc_list_print_jobs(%s)\n", fname)); if (SMBC_parse_path(frame, context, fname, &workgroup, &server, &share, &path, &user, &password, NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } if (!user || user[0] == (char)0) { user = talloc_strdup(frame, smbc_getUser(context)); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); return -1; } } srv = SMBC_server(frame, context, True, server, share, &workgroup, &user, &password); if (!srv) { TALLOC_FREE(frame); return -1; /* errno set by SMBC_server */ } if (cli_print_queue(srv->cli, (void (*)(struct print_job_info *))fn) < 0) { errno = SMBC_errno(context, srv->cli); TALLOC_FREE(frame); return -1; } TALLOC_FREE(frame); return 0; }
off_t SMBC_splice_ctx(SMBCCTX *context, SMBCFILE *srcfile, SMBCFILE *dstfile, off_t count, int (*splice_cb)(off_t n, void *priv), void *priv) { off_t written; char *server = NULL, *share = NULL, *user = NULL, *password = NULL; char *path = NULL; char *targetpath = NULL; struct cli_state *srccli = NULL; struct cli_state *dstcli = NULL; uint16_t port = 0; TALLOC_CTX *frame = talloc_stackframe(); NTSTATUS status; if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); return -1; } if (!srcfile || !SMBC_dlist_contains(context->internal->files, srcfile)) { errno = EBADF; TALLOC_FREE(frame); return -1; } if (!dstfile || !SMBC_dlist_contains(context->internal->files, dstfile)) { errno = EBADF; TALLOC_FREE(frame); return -1; } if (SMBC_parse_path(frame, context, srcfile->fname, NULL, &server, &port, &share, &path, &user, &password, NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } status = cli_resolve_path(frame, "", context->internal->auth_info, srcfile->srv->cli, path, &srccli, &targetpath); if (!NT_STATUS_IS_OK(status)) { d_printf("Could not resolve %s\n", path); errno = ENOENT; TALLOC_FREE(frame); return -1; } if (SMBC_parse_path(frame, context, dstfile->fname, NULL, &server, &port, &share, &path, &user, &password, NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } status = cli_resolve_path(frame, "", context->internal->auth_info, dstfile->srv->cli, path, &dstcli, &targetpath); if (!NT_STATUS_IS_OK(status)) { d_printf("Could not resolve %s\n", path); errno = ENOENT; TALLOC_FREE(frame); return -1; } status = cli_splice(srccli, dstcli, srcfile->cli_fd, dstfile->cli_fd, count, srcfile->offset, dstfile->offset, &written, splice_cb, priv); if (!NT_STATUS_IS_OK(status)) { errno = SMBC_errno(context, srccli); TALLOC_FREE(frame); return -1; } srcfile->offset += written; dstfile->offset += written; TALLOC_FREE(frame); return written; }