+
+/****************************************************************************
+ Convert open "flags" arg to uint32 on wire.
+****************************************************************************/
+
+static uint32 open_flags_to_wire(int flags)
+{
+ int open_mode = flags & O_ACCMODE;
+ uint32 ret = 0;
+
+ switch (open_mode) {
+ case O_WRONLY:
+ ret |= SMB_O_WRONLY;
+ break;
+ case O_RDWR:
+ ret |= SMB_O_RDWR;
+ break;
+ default:
+ case O_RDONLY:
+ ret |= SMB_O_RDONLY;
+ break;
+ }
+
+ if (flags & O_CREAT) {
+ ret |= SMB_O_CREAT;
+ }
+ if (flags & O_EXCL) {
+ ret |= SMB_O_EXCL;
+ }
+ if (flags & O_TRUNC) {
+ ret |= SMB_O_TRUNC;
+ }
+#if defined(O_SYNC)
+ if (flags & O_SYNC) {
+ ret |= SMB_O_SYNC;
+ }
+#endif /* O_SYNC */
+ if (flags & O_APPEND) {
+ ret |= SMB_O_APPEND;
+ }
+#if defined(O_DIRECT)
+ if (flags & O_DIRECT) {
+ ret |= SMB_O_DIRECT;
+ }
+#endif
+#if defined(O_DIRECTORY)
+ if (flags & O_DIRECTORY) {
+ ret &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
+ ret |= SMB_O_DIRECTORY;
+ }
+#endif
+ return ret;
+}
+
+/****************************************************************************
+ Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
+****************************************************************************/
+
+static int cli_posix_open_internal(struct cli_state *cli, const char *fname, int flags, mode_t mode, bool is_dir)
+{
+ unsigned int data_len = 0;
+ unsigned int param_len = 0;
+ uint16 setup = TRANSACT2_SETPATHINFO;
+ char *param;
+ char data[18];
+ char *rparam=NULL, *rdata=NULL;
+ char *p;
+ int fnum = -1;
+ uint32 wire_flags = open_flags_to_wire(flags);
+ size_t srclen = 2*(strlen(fname)+1);
+
+ param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
+ if (!param) {
+ return false;
+ }
+ memset(param, '\0', 6);
+ SSVAL(param,0, SMB_POSIX_PATH_OPEN);
+ p = ¶m[6];
+
+ p += clistr_push(cli, p, fname, srclen, STR_TERMINATE);
+ param_len = PTR_DIFF(p, param);
+
+ if (is_dir) {
+ wire_flags &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
+ wire_flags |= SMB_O_DIRECTORY;
+ }
+
+ p = data;
+ SIVAL(p,0,0); /* No oplock. */
+ SIVAL(p,4,wire_flags);
+ SIVAL(p,8,unix_perms_to_wire(mode));
+ SIVAL(p,12,0); /* Top bits of perms currently undefined. */
+ SSVAL(p,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
+
+ data_len = 18;
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ (char *)&data, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ SAFE_FREE(param);
+ return -1;
+ }
+
+ SAFE_FREE(param);
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, ¶m_len,
+ &rdata, &data_len)) {
+ return -1;
+ }
+
+ fnum = SVAL(rdata,2);
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return fnum;
+}
+
+/****************************************************************************
+ open - POSIX semantics.
+****************************************************************************/
+
+int cli_posix_open(struct cli_state *cli, const char *fname, int flags, mode_t mode)
+{
+ return cli_posix_open_internal(cli, fname, flags, mode, False);
+}
+
+/****************************************************************************
+ mkdir - POSIX semantics.
+****************************************************************************/
+
+int cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
+{
+ return (cli_posix_open_internal(cli, fname, O_CREAT, mode, True) == -1) ? -1 : 0;
+}
+
+/****************************************************************************
+ unlink or rmdir - POSIX semantics.
+****************************************************************************/
+
+static bool cli_posix_unlink_internal(struct cli_state *cli, const char *fname, bool is_dir)
+{
+ unsigned int data_len = 0;
+ unsigned int param_len = 0;
+ uint16 setup = TRANSACT2_SETPATHINFO;
+ char *param;
+ char data[2];
+ char *rparam=NULL, *rdata=NULL;
+ char *p;
+ size_t srclen = 2*(strlen(fname)+1);
+
+ param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
+ if (!param) {
+ return false;
+ }
+ memset(param, '\0', 6);
+ SSVAL(param,0, SMB_POSIX_PATH_UNLINK);
+ p = ¶m[6];
+
+ p += clistr_push(cli, p, fname, srclen, STR_TERMINATE);
+ param_len = PTR_DIFF(p, param);
+
+ SSVAL(data, 0, is_dir ? SMB_POSIX_UNLINK_DIRECTORY_TARGET :
+ SMB_POSIX_UNLINK_FILE_TARGET);
+ data_len = 2;
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ (char *)&data, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ SAFE_FREE(param);
+ return False;
+ }
+
+ SAFE_FREE(param);
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, ¶m_len,
+ &rdata, &data_len)) {
+ return False;
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return True;
+}
+
+/****************************************************************************
+ unlink - POSIX semantics.
+****************************************************************************/
+
+bool cli_posix_unlink(struct cli_state *cli, const char *fname)
+{
+ return cli_posix_unlink_internal(cli, fname, False);
+}
+
+/****************************************************************************
+ rmdir - POSIX semantics.
+****************************************************************************/
+
+int cli_posix_rmdir(struct cli_state *cli, const char *fname)
+{
+ return cli_posix_unlink_internal(cli, fname, True);
+}