s3:util: add internal function for transfer_file that uses pread/pwrite
authorRalph Boehme <slow@samba.org>
Mon, 27 Apr 2015 10:16:16 +0000 (12:16 +0200)
committerStefan Metzmacher <metze@samba.org>
Mon, 17 Aug 2015 20:42:17 +0000 (22:42 +0200)
read/write aren't overloaded in the streams VFS modules, using
pread/pwrite instead this makes it possible to use transfer_file() with
named streams.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=11317

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
(cherry picked from commit cda8c24a676232bc5834c523407caef8ea9ff038)

source3/include/transfer_file.h
source3/lib/util_transfer_file.c
source3/smbd/vfs.c

index 546104f8f37b746181c343083e6c791950877134..7e7ac0328fe30c416d115de54f2e568ccd956f6b 100644 (file)
@@ -27,6 +27,12 @@ ssize_t transfer_file_internal(void *in_file,
                               ssize_t (*read_fn)(void *, void *, size_t),
                               ssize_t (*write_fn)(void *, const void *, size_t));
 
+ssize_t transfer_file_internal_offset(void *in_file,
+                                     void *out_file,
+                                     size_t n,
+                                     ssize_t (*pread_fn)(void *, void *, size_t, off_t),
+                                     ssize_t (*pwrite_fn)(void *, const void *, size_t, off_t));
+
 off_t transfer_file(int infd, int outfd, off_t n);
 
 #endif /* __TRANSFER_FILE_H__ */
index 00a2c9d9de98188baf661878e4b0b35439e6acea..6750087ae6a09ad62e822e7663ca2b6931661c49 100644 (file)
@@ -94,6 +94,71 @@ ssize_t transfer_file_internal(void *in_file,
        return (ssize_t)total;
 }
 
+ssize_t transfer_file_internal_offset(void *in_file,
+                                     void *out_file,
+                                     size_t n,
+                                     ssize_t (*pread_fn)(void *, void *, size_t, off_t),
+                                     ssize_t (*pwrite_fn)(void *, const void *, size_t, off_t))
+{
+       char *buf;
+       size_t total = 0;
+       ssize_t read_ret;
+       ssize_t write_ret;
+       size_t num_to_read_thistime;
+       size_t num_written = 0;
+       off_t offset = 0;
+
+       if (n == 0) {
+               return 0;
+       }
+
+       if ((buf = SMB_MALLOC_ARRAY(char, TRANSFER_BUF_SIZE)) == NULL) {
+               return -1;
+       }
+
+       do {
+               num_to_read_thistime = MIN((n - total), TRANSFER_BUF_SIZE);
+
+               read_ret = (*pread_fn)(in_file, buf, num_to_read_thistime, offset);
+               if (read_ret == -1) {
+                       DEBUG(0,("transfer_file_internal: read failure. "
+                                "Error = %s\n", strerror(errno) ));
+                       SAFE_FREE(buf);
+                       return -1;
+               }
+               if (read_ret == 0) {
+                       break;
+               }
+
+               num_written = 0;
+
+               while (num_written < read_ret) {
+                       write_ret = (*pwrite_fn)(out_file, buf + num_written,
+                                               read_ret - num_written,
+                                               offset + num_written);
+
+                       if (write_ret == -1) {
+                               DEBUG(0,("transfer_file_internal: "
+                                        "write failure. Error = %s\n",
+                                        strerror(errno) ));
+                               SAFE_FREE(buf);
+                               return -1;
+                       }
+                       if (write_ret == 0) {
+                               return (ssize_t)total;
+                       }
+
+                       num_written += (size_t)write_ret;
+               }
+
+               total += (size_t)read_ret;
+               offset += (off_t)read_ret;
+       } while (total < n);
+
+       SAFE_FREE(buf);
+       return (ssize_t)total;
+}
+
 static ssize_t sys_read_fn(void *file, void *buf, size_t len)
 {
        int *fd = (int *)file;
@@ -108,8 +173,22 @@ static ssize_t sys_write_fn(void *file, const void *buf, size_t len)
        return sys_write(*fd, buf, len);
 }
 
+static ssize_t sys_pread_fn(void *file, void *buf, size_t len, off_t offset)
+{
+       int *fd = (int *)file;
+
+       return sys_pread(*fd, buf, len, offset);
+}
+
+static ssize_t sys_pwrite_fn(void *file, const void *buf, size_t len, off_t offset)
+{
+       int *fd = (int *)file;
+
+       return sys_pwrite(*fd, buf, len, offset);
+}
+
 off_t transfer_file(int infd, int outfd, off_t n)
 {
-       return (off_t)transfer_file_internal(&infd, &outfd, (size_t)n,
-                                                sys_read_fn, sys_write_fn);
+       return (off_t)transfer_file_internal_offset(&infd, &outfd, (size_t)n,
+                                                   sys_pread_fn, sys_pwrite_fn);
 }
index 885f24cd6e5910e6fe2cf380d8824498c99ac97d..12813225cb71733c2ff1e62a60099a0361dfe043 100644 (file)
@@ -770,10 +770,24 @@ static ssize_t vfs_write_fn(void *file, const void *buf, size_t len)
        return SMB_VFS_WRITE(fsp, buf, len);
 }
 
+static ssize_t vfs_pread_fn(void *file, void *buf, size_t len, off_t offset)
+{
+       struct files_struct *fsp = (struct files_struct *)file;
+
+       return SMB_VFS_PREAD(fsp, buf, len, offset);
+}
+
+static ssize_t vfs_pwrite_fn(void *file, const void *buf, size_t len, off_t offset)
+{
+       struct files_struct *fsp = (struct files_struct *)file;
+
+       return SMB_VFS_PWRITE(fsp, buf, len, offset);
+}
+
 off_t vfs_transfer_file(files_struct *in, files_struct *out, off_t n)
 {
-       return transfer_file_internal((void *)in, (void *)out, n,
-                                     vfs_read_fn, vfs_write_fn);
+       return transfer_file_internal_offset((void *)in, (void *)out, n,
+                                            vfs_pread_fn, vfs_pwrite_fn);
 }
 
 /*******************************************************************