ndr: fix push/pull DATA_BLOB with NDR_NOALIGN
[obnox/samba/samba-obnox.git] / librpc / ndr / ndr_basic.c
index ab234bf5caa2605cdc683a2fd1fc0310a8c3be69..1887838779d409941ec336c6ffb9a66682c3ad64 100644 (file)
@@ -1247,16 +1247,21 @@ _PUBLIC_ void ndr_print_DATA_BLOB(struct ndr_print *ndr, const char *name, DATA_
 
 
 /*
-  push a DATA_BLOB onto the wire. 
-*/
+ * Push a DATA_BLOB onto the wire.
+ * 1) When called with LIBNDR_FLAG_ALIGN* alignment flags set, push padding
+ *    bytes _only_. The length is determined by the alignment required and the
+ *    current ndr offset.
+ * 2) When called with the LIBNDR_FLAG_REMAINING flag, push the byte array to
+ *    the ndr buffer.
+ * 3) Otherwise, push a uint32 length _and_ a corresponding byte array to the
+ *    ndr buffer.
+ */
 _PUBLIC_ enum ndr_err_code ndr_push_DATA_BLOB(struct ndr_push *ndr, int ndr_flags, DATA_BLOB blob)
 {
        if (ndr->flags & LIBNDR_FLAG_REMAINING) {
                /* nothing to do */
-       } else if (ndr->flags & LIBNDR_ALIGN_FLAGS) {
-               if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
-                       blob.length = 0;
-               } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
+       } else if (ndr->flags & (LIBNDR_ALIGN_FLAGS & ~LIBNDR_FLAG_NOALIGN)) {
+               if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
                        blob.length = NDR_ALIGN(ndr, 2);
                } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
                        blob.length = NDR_ALIGN(ndr, 4);
@@ -1273,18 +1278,23 @@ _PUBLIC_ enum ndr_err_code ndr_push_DATA_BLOB(struct ndr_push *ndr, int ndr_flag
 }
 
 /*
-  pull a DATA_BLOB from the wire. 
-*/
+ * Pull a DATA_BLOB from the wire.
+ * 1) when called with LIBNDR_FLAG_ALIGN* alignment flags set, pull padding
+ *    bytes _only_. The length is determined by the alignment required and the
+ *    current ndr offset.
+ * 2) When called with the LIBNDR_FLAG_REMAINING flag, pull all remaining bytes
+ *    from the ndr buffer.
+ * 3) Otherwise, pull a uint32 length _and_ a corresponding byte array from the
+ *    ndr buffer.
+ */
 _PUBLIC_ enum ndr_err_code ndr_pull_DATA_BLOB(struct ndr_pull *ndr, int ndr_flags, DATA_BLOB *blob)
 {
        uint32_t length = 0;
 
        if (ndr->flags & LIBNDR_FLAG_REMAINING) {
                length = ndr->data_size - ndr->offset;
-       } else if (ndr->flags & LIBNDR_ALIGN_FLAGS) {
-               if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
-                       length = 0;
-               } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
+       } else if (ndr->flags & (LIBNDR_ALIGN_FLAGS & ~LIBNDR_FLAG_NOALIGN)) {
+               if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
                        length = NDR_ALIGN(ndr, 2);
                } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
                        length = NDR_ALIGN(ndr, 4);
@@ -1338,3 +1348,90 @@ _PUBLIC_ NTSTATUS ndr_map_error2ntstatus(enum ndr_err_code ndr_err)
        /* we should map all error codes to different status codes */
        return NT_STATUS_INVALID_PARAMETER;
 }
+
+_PUBLIC_ int ndr_map_error2errno(enum ndr_err_code ndr_err)
+{
+       switch (ndr_err) {
+       case NDR_ERR_SUCCESS:
+               return 0;
+       case NDR_ERR_BUFSIZE:
+               return ENOSPC;
+       case NDR_ERR_TOKEN:
+               return EINVAL;
+       case NDR_ERR_ALLOC:
+               return ENOMEM;
+       case NDR_ERR_ARRAY_SIZE:
+               return EMSGSIZE;
+       case NDR_ERR_INVALID_POINTER:
+               return EINVAL;
+       case NDR_ERR_UNREAD_BYTES:
+               return EOVERFLOW;
+       default:
+               break;
+       }
+
+       /* we should map all error codes to different status codes */
+       return EINVAL;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_timespec(struct ndr_push *ndr,
+                                            int ndr_flags,
+                                            const struct timespec *t)
+{
+       NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+       NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, t->tv_sec));
+       NDR_CHECK(ndr_push_uint32(ndr, ndr_flags, t->tv_nsec));
+       return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_timespec(struct ndr_pull *ndr,
+                                            int ndr_flags,
+                                            struct timespec *t)
+{
+       uint64_t secs;
+       uint32_t nsecs;
+       NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+       NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &secs));
+       NDR_CHECK(ndr_pull_uint32(ndr, ndr_flags, &nsecs));
+       t->tv_sec = secs;
+       t->tv_nsec = nsecs;
+       return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_timespec(struct ndr_print *ndr, const char *name,
+                                const struct timespec *t)
+{
+       ndr->print(ndr, "%-25s: %s.%ld", name, timestring(ndr, t->tv_sec),
+                  (long)t->tv_nsec);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_timeval(struct ndr_push *ndr,
+                                           int ndr_flags,
+                                           const struct timeval *t)
+{
+       NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+       NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, t->tv_sec));
+       NDR_CHECK(ndr_push_uint32(ndr, ndr_flags, t->tv_usec));
+       return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_timeval(struct ndr_pull *ndr,
+                                           int ndr_flags,
+                                           struct timeval *t)
+{
+       uint64_t secs;
+       uint32_t usecs;
+       NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+       NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &secs));
+       NDR_CHECK(ndr_pull_uint32(ndr, ndr_flags, &usecs));
+       t->tv_sec = secs;
+       t->tv_usec = usecs;
+       return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_timeval(struct ndr_print *ndr, const char *name,
+                               const struct timeval *t)
+{
+       ndr->print(ndr, "%-25s: %s.%ld", name, timestring(ndr, t->tv_sec),
+                  (long)t->tv_usec);
+}