Bladeren bron

Implement file writing

Sylver Bruneau 9 jaren geleden
bovenliggende
commit
7c1891f4b4
4 gewijzigde bestanden met toevoegingen van 114 en 4 verwijderingen
  1. 16 2
      include/bdsm/smb_file.h
  2. 1 0
      src/smb_defs.h
  3. 67 2
      src/smb_file.c
  4. 30 0
      src/smb_packets.h

+ 16 - 2
include/bdsm/smb_file.h

@@ -81,11 +81,25 @@ void      smb_fclose(smb_session *s, smb_fd fd);
 ssize_t   smb_fread(smb_session *s, smb_fd fd, void *buf, size_t buf_size);
 
 /**
- * @brief Sets/Moves/Get the read pointer for a given file
+ * @brief Write to an open file
+ * @details At most 'buf_size' bytes from memory pointed by 'buf' are written
+ * to the current seek offset of the open file represented by the smb file
+ * descriptor 'fd'.
+ *
+ * @param[in] s The session object
+ * @param[in] fd [description]
+ * @param[out] buf [description]
+ * @param[in] buf_size [description]
+ * @return The number of bytes written or -1 in case of error.
+ */
+ssize_t   smb_fwrite(smb_session *s, smb_fd fd, void *buf, size_t buf_size);
+
+/**
+ * @brief Sets/Moves/Get the read/write pointer for a given file
  * @details The behavior of this function is the same as the Unix fseek()
  * function, except the SEEK_END argument isn't supported.
  *
- * This functions adjust the read the read pointer depending on the value of
+ * This functions adjust the read/write pointer depending on the value of
  * offset and whence.
  *
  * - If whence == #SMB_SEEK_SET, the read pointer is set at 'offset'

+ 1 - 0
src/smb_defs.h

@@ -71,6 +71,7 @@
 #define SMB_CMD_TREE_CONNECT    0x75 // Tree Connect AndX
 #define SMB_CMD_ECHO            0x2b
 #define SMB_CMD_READ            0x2e // Read AndX
+#define SMB_CMD_WRITE           0x2f // Write AndX
 #define SMB_CMD_CREATE          0xa2 // NT Create AndX
 #define SMB_CMD_MKDIR           0x00 // Depecated
 #define SMB_CMD_RMDIR           0x01

+ 67 - 2
src/smb_file.c

@@ -77,8 +77,16 @@ smb_fd      smb_fopen(smb_session *s, smb_tid tid, const char *path,
     req.alloc_size     = 0;
     req.file_attr      = 0;
     req.share_access   = SMB_SHARE_READ | SMB_SHARE_WRITE;
-    req.disposition    = SMB_DISPOSITION_FILE_OPEN;  // Open and fails if doesn't exist
-    req.create_opts    = 0;                          // We dont't support create
+    if ((o_flags & SMB_MOD_RW) == SMB_MOD_RW)
+    {
+        req.disposition    = SMB_DISPOSITION_FILE_CREATE; // Create if doesn't exist, fails if exists
+        req.create_opts    = SMB_CREATEOPT_WRITE_THROUGH;
+    }
+    else
+    {
+        req.disposition    = SMB_DISPOSITION_FILE_OPEN;  // Open and fails if doesn't exist
+        req.create_opts    = 0;                          // We dont't support create
+    }
     req.impersonation  = SMB_IMPERSONATION_SEC_IMPERSONATE;
     req.security_flags = SMB_SECURITY_NO_TRACKING;
     req.path_length    = path_len;
@@ -215,6 +223,63 @@ ssize_t   smb_fread(smb_session *s, smb_fd fd, void *buf, size_t buf_size)
     return (resp->data_len);
 }
 
+ssize_t   smb_fwrite(smb_session *s, smb_fd fd, void *buf, size_t buf_size)
+{
+    smb_file       *file;
+    smb_message    *req_msg, resp_msg;
+    smb_write_req   req;
+    smb_write_resp *resp;
+    uint16_t        max_write;
+    int             res;
+
+    if ((s == NULL) || (buf == NULL) || !fd)
+        return -1;
+
+    file = smb_session_file_get(s, fd);
+    if (file == NULL)
+        return -1;
+
+    req_msg = smb_message_new(SMB_CMD_WRITE);
+    if (!req_msg)
+        return (-1);
+    req_msg->packet->header.tid = (uint16_t)file->tid;
+
+    // total size of SMB message shall not exceed maximum size of netbios data payload
+    max_write = UINT16_MAX - sizeof(smb_packet) - sizeof(smb_write_req);
+    max_write = max_write < buf_size ? max_write : (uint16_t)buf_size;
+
+    SMB_MSG_INIT_PKT_ANDX(req);
+    req.wct              = 14; // Must be 14
+    req.fid              = file->fid;
+    req.offset           = file->offset & 0xffffffff;
+    req.timeout          = 0;
+    req.write_mode       = SMB_WRITEMODE_WRITETHROUGH;
+    req.remaining        = 0;
+    req.reserved         = 0;
+    req.data_len         = max_write;
+    req.data_offset      = sizeof(smb_packet) + sizeof(smb_write_req);
+    req.offset_high      = (file->offset >> 32) & 0xffffffff;
+    req.bct              = max_write;
+    SMB_MSG_PUT_PKT(req_msg, req);
+    smb_message_append(req_msg, buf, max_write);
+
+    res = smb_session_send_msg(s, req_msg);
+    smb_message_destroy(req_msg);
+    if (!res)
+        return -1;
+
+    if (!smb_session_recv_msg(s, &resp_msg))
+        return -1;
+    if (resp_msg.packet->header.status != NT_STATUS_SUCCESS)
+        return -1;
+
+    resp = (smb_write_resp *)resp_msg.packet->payload;
+
+    smb_fseek(s, fd, resp->data_len, SEEK_CUR);
+
+    return (resp->data_len);
+}
+
 ssize_t   smb_fseek(smb_session *s, smb_fd fd, ssize_t offset, int whence)
 {
     smb_file  *file;

+ 30 - 0
src/smb_packets.h

@@ -281,6 +281,36 @@ typedef struct
     uint16_t        bct;
 } __attribute__((packed))   smb_read_resp;
 
+//-> Write File
+typedef struct
+{
+    uint8_t         wct;                // 14
+    SMB_ANDX_MEMBERS
+    uint16_t        fid;
+    uint32_t        offset;
+    uint32_t        timeout;
+    uint16_t        write_mode;
+    uint16_t        remaining;
+    uint16_t        reserved;
+    uint16_t        data_len;
+    uint16_t        data_offset;
+    uint32_t        offset_high;        // Continuation of offset field'
+    uint16_t        bct;
+    uint8_t         padding;
+} __attribute__((packed))   smb_write_req;
+
+//<- Write File
+typedef struct
+{
+    uint8_t         wct;                // 6
+    SMB_ANDX_MEMBERS
+    
+    uint16_t        data_len;
+    uint16_t        available;
+    uint32_t        reserved;
+    uint16_t        bct;
+} __attribute__((packed))   smb_write_resp;
+
 //-> Remove File
 typedef struct
 {