tdb: Fix blank line endings
[samba.git] / lib / tdb / common / io.c
index ac21e3f67a1b00c30f0cb354e72a46ca52a015ac..2e0a206c2c8b9cec407771313674b4370257f850 100644 (file)
@@ -1,4 +1,4 @@
- /* 
+ /*
    Unix SMB/CIFS implementation.
 
    trivial database library
@@ -30,7 +30,7 @@
 
 /* check for an out of bounds access - if it is out of bounds then
    see if the database has been expanded by someone else and expand
-   if necessary 
+   if necessary
 */
 static int tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len,
                   int probe)
@@ -63,16 +63,6 @@ static int tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len,
                return -1;
        }
 
-       if (st.st_size < (size_t)off + len) {
-               if (!probe) {
-                       /* Ensure ecode is set for log fn. */
-                       tdb->ecode = TDB_ERR_IO;
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %u beyond eof at %u\n",
-                                (int)(off + len), (int)st.st_size));
-               }
-               return -1;
-       }
-
        /* Beware >4G files! */
        if ((tdb_off_t)st.st_size != st.st_size) {
                /* Ensure ecode is set for log fn. */
@@ -82,18 +72,35 @@ static int tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len,
                return -1;
        }
 
-       /* Unmap, update size, remap */
+       /* Unmap, update size, remap.  We do this unconditionally, to handle
+        * the unusual case where the db is truncated.
+        *
+        * This can happen to a child using tdb_reopen_all(true) on a
+        * TDB_CLEAR_IF_FIRST tdb whose parent crashes: the next
+        * opener will truncate the database. */
        if (tdb_munmap(tdb) == -1) {
                tdb->ecode = TDB_ERR_IO;
                return -1;
        }
        tdb->map_size = st.st_size;
-       tdb_mmap(tdb);
+       if (tdb_mmap(tdb) != 0) {
+               return - 1;
+       }
+
+       if (st.st_size < (size_t)off + len) {
+               if (!probe) {
+                       /* Ensure ecode is set for log fn. */
+                       tdb->ecode = TDB_ERR_IO;
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_oob len %u beyond eof at %u\n",
+                                (int)(off + len), (int)st.st_size));
+               }
+               return -1;
+       }
        return 0;
 }
 
 /* write a lump of data at a specified offset */
-static int tdb_write(struct tdb_context *tdb, tdb_off_t off, 
+static int tdb_write(struct tdb_context *tdb, tdb_off_t off,
                     const void *buf, tdb_len_t len)
 {
        if (len == 0) {
@@ -111,6 +118,10 @@ static int tdb_write(struct tdb_context *tdb, tdb_off_t off,
        if (tdb->map_ptr) {
                memcpy(off + (char *)tdb->map_ptr, buf, len);
        } else {
+#ifdef HAVE_INCOHERENT_MMAP
+               tdb->ecode = TDB_ERR_IO;
+               return -1;
+#else
                ssize_t written = pwrite(tdb->fd, buf, len, off);
                if ((written != (ssize_t)len) && (written != -1)) {
                        /* try once more */
@@ -135,6 +146,7 @@ static int tdb_write(struct tdb_context *tdb, tdb_off_t off,
                                 len, off));
                        return -1;
                }
+#endif
        }
        return 0;
 }
@@ -150,7 +162,7 @@ void *tdb_convert(void *buf, uint32_t size)
 
 
 /* read a lump of data at a specified offset, maybe convert */
-static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf, 
+static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
                    tdb_len_t len, int cv)
 {
        if (tdb->methods->tdb_oob(tdb, off, len, 0) != 0) {
@@ -160,6 +172,10 @@ static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
        if (tdb->map_ptr) {
                memcpy(buf, off + (char *)tdb->map_ptr, len);
        } else {
+#ifdef HAVE_INCOHERENT_MMAP
+               tdb->ecode = TDB_ERR_IO;
+               return -1;
+#else
                ssize_t ret = pread(tdb->fd, buf, len, off);
                if (ret != (ssize_t)len) {
                        /* Ensure ecode is set for log fn. */
@@ -170,6 +186,7 @@ static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
                                 (int)tdb->map_size));
                        return -1;
                }
+#endif
        }
        if (cv) {
                tdb_convert(buf, len);
@@ -182,7 +199,7 @@ static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
 /*
   do an unlocked scan of the hash table heads to find the next non-zero head. The value
   will then be confirmed with the lock held
-*/             
+*/
 static void tdb_next_hash_chain(struct tdb_context *tdb, uint32_t *chain)
 {
        uint32_t h = *chain;
@@ -222,15 +239,25 @@ int tdb_munmap(struct tdb_context *tdb)
        return 0;
 }
 
-void tdb_mmap(struct tdb_context *tdb)
+/* If mmap isn't coherent, *everyone* must always mmap. */
+static bool should_mmap(const struct tdb_context *tdb)
+{
+#ifdef HAVE_INCOHERENT_MMAP
+       return true;
+#else
+       return !(tdb->flags & TDB_NOMMAP);
+#endif
+}
+
+int tdb_mmap(struct tdb_context *tdb)
 {
        if (tdb->flags & TDB_INTERNAL)
-               return;
+               return 0;
 
 #ifdef HAVE_MMAP
-       if (!(tdb->flags & TDB_NOMMAP)) {
-               tdb->map_ptr = mmap(NULL, tdb->map_size, 
-                                   PROT_READ|(tdb->read_only? 0:PROT_WRITE), 
+       if (should_mmap(tdb)) {
+               tdb->map_ptr = mmap(NULL, tdb->map_size,
+                                   PROT_READ|(tdb->read_only? 0:PROT_WRITE),
                                    MAP_SHARED|MAP_FILE, tdb->fd, 0);
 
                /*
@@ -239,8 +266,12 @@ void tdb_mmap(struct tdb_context *tdb)
 
                if (tdb->map_ptr == MAP_FAILED) {
                        tdb->map_ptr = NULL;
-                       TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_mmap failed for size %d (%s)\n", 
+                       TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_mmap failed for size %d (%s)\n",
                                 tdb->map_size, strerror(errno)));
+#ifdef HAVE_INCOHERENT_MMAP
+                       tdb->ecode = TDB_ERR_IO;
+                       return -1;
+#endif
                }
        } else {
                tdb->map_ptr = NULL;
@@ -248,6 +279,7 @@ void tdb_mmap(struct tdb_context *tdb)
 #else
        tdb->map_ptr = NULL;
 #endif
+       return 0;
 }
 
 /* expand a file.  we prefer to use ftruncate, as that is what posix
@@ -273,7 +305,7 @@ static int tdb_expand_file(struct tdb_context *tdb, tdb_off_t size, tdb_off_t ad
                        errno = ENOSPC;
                }
                if (written != 1) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file to %d failed (%s)\n", 
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file to %d failed (%s)\n",
                                 size+addition, strerror(errno)));
                        return -1;
                }
@@ -357,48 +389,36 @@ int tdb_expand(struct tdb_context *tdb, tdb_off_t size)
 
        size = tdb_expand_adjust(tdb->map_size, size, tdb->page_size);
 
-       if (!(tdb->flags & TDB_INTERNAL))
-               tdb_munmap(tdb);
-
-       /*
-        * We must ensure the file is unmapped before doing this
-        * to ensure consistency with systems like OpenBSD where
-        * writes and mmaps are not consistent.
-        */
-
        /* expand the file itself */
        if (!(tdb->flags & TDB_INTERNAL)) {
                if (tdb->methods->tdb_expand_file(tdb, tdb->map_size, size) != 0)
                        goto fail;
        }
 
-       tdb->map_size += size;
+       /* form a new freelist record */
+       offset = tdb->map_size;
+       memset(&rec,'\0',sizeof(rec));
+       rec.rec_len = size - sizeof(rec);
 
        if (tdb->flags & TDB_INTERNAL) {
                char *new_map_ptr = (char *)realloc(tdb->map_ptr,
-                                                   tdb->map_size);
+                                                   tdb->map_size + size);
                if (!new_map_ptr) {
-                       tdb->map_size -= size;
                        goto fail;
                }
                tdb->map_ptr = new_map_ptr;
+               tdb->map_size += size;
        } else {
-               /*
-                * We must ensure the file is remapped before adding the space
-                * to ensure consistency with systems like OpenBSD where
-                * writes and mmaps are not consistent.
-                */
-
-               /* We're ok if the mmap fails as we'll fallback to read/write */
-               tdb_mmap(tdb);
+               /* Explicitly remap: if we're in a transaction, this won't
+                * happen automatically! */
+               tdb_munmap(tdb);
+               tdb->map_size += size;
+               if (tdb_mmap(tdb) != 0) {
+                       goto fail;
+               }
        }
 
-       /* form a new freelist record */
-       memset(&rec,'\0',sizeof(rec));
-       rec.rec_len = size - sizeof(rec);
-
        /* link it into the free list */
-       offset = tdb->map_size - size;
        if (tdb_free(tdb, offset, &rec) == -1)
                goto fail;