Merge branch 'mm/mkstemps-mode-for-packfiles' into maint
authorJunio C Hamano <gitster@pobox.com>
Mon, 8 Mar 2010 08:36:00 +0000 (00:36 -0800)
committerJunio C Hamano <gitster@pobox.com>
Mon, 8 Mar 2010 08:36:00 +0000 (00:36 -0800)
* mm/mkstemps-mode-for-packfiles:
Use git_mkstemp_mode instead of plain mkstemp to create object files
git_mkstemps_mode: don't set errno to EINVAL on exit.
Use git_mkstemp_mode and xmkstemp_mode in odb_mkstemp, not chmod later.
git_mkstemp_mode, xmkstemp_mode: variants of gitmkstemps with mode argument.
Move gitmkstemps to path.c
Add a testcase for ACL with restrictive umask.

1  2 
cache.h
path.c
sha1_file.c
diff --combined cache.h
index d454b7e686d6461162a85ef9c5f752eea401f51a,031963772356d925f3e1e338b72d5c8d38dd615e..4d89aa3da4d32653289c742f37abe8ef604ab11b
+++ b/cache.h
@@@ -641,6 -641,10 +641,10 @@@ int git_mkstemp(char *path, size_t n, c
  
  int git_mkstemps(char *path, size_t n, const char *template, int suffix_len);
  
+ /* set default permissions by passing mode arguments to open(2) */
+ int git_mkstemps_mode(char *pattern, int suffix_len, int mode);
+ int git_mkstemp_mode(char *pattern, int mode);
  /*
   * NOTE NOTE NOTE!!
   *
@@@ -775,7 -779,7 +779,7 @@@ extern const char *git_committer_info(i
  extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int);
  extern const char *fmt_name(const char *name, const char *email);
  extern const char *git_editor(void);
 -extern const char *git_pager(void);
 +extern const char *git_pager(int stdout_is_tty);
  
  struct checkout {
        const char *base_dir;
diff --combined path.c
index e166d5380e47a7f6560f504de6550a508de1e170,12ef731acebb96481dcc2360648ce4e1b85de33d..aaa9345ebca4140317d8509ba95ec61cff82192d
--- 1/path.c
--- 2/path.c
+++ b/path.c
@@@ -157,6 -157,85 +157,85 @@@ int git_mkstemps(char *path, size_t len
        return mkstemps(path, suffix_len);
  }
  
+ /* Adapted from libiberty's mkstemp.c. */
+ #undef TMP_MAX
+ #define TMP_MAX 16384
+ int git_mkstemps_mode(char *pattern, int suffix_len, int mode)
+ {
+       static const char letters[] =
+               "abcdefghijklmnopqrstuvwxyz"
+               "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+               "0123456789";
+       static const int num_letters = 62;
+       uint64_t value;
+       struct timeval tv;
+       char *template;
+       size_t len;
+       int fd, count;
+       len = strlen(pattern);
+       if (len < 6 + suffix_len) {
+               errno = EINVAL;
+               return -1;
+       }
+       if (strncmp(&pattern[len - 6 - suffix_len], "XXXXXX", 6)) {
+               errno = EINVAL;
+               return -1;
+       }
+       /*
+        * Replace pattern's XXXXXX characters with randomness.
+        * Try TMP_MAX different filenames.
+        */
+       gettimeofday(&tv, NULL);
+       value = ((size_t)(tv.tv_usec << 16)) ^ tv.tv_sec ^ getpid();
+       template = &pattern[len - 6 - suffix_len];
+       for (count = 0; count < TMP_MAX; ++count) {
+               uint64_t v = value;
+               /* Fill in the random bits. */
+               template[0] = letters[v % num_letters]; v /= num_letters;
+               template[1] = letters[v % num_letters]; v /= num_letters;
+               template[2] = letters[v % num_letters]; v /= num_letters;
+               template[3] = letters[v % num_letters]; v /= num_letters;
+               template[4] = letters[v % num_letters]; v /= num_letters;
+               template[5] = letters[v % num_letters]; v /= num_letters;
+               fd = open(pattern, O_CREAT | O_EXCL | O_RDWR, mode);
+               if (fd > 0)
+                       return fd;
+               /*
+                * Fatal error (EPERM, ENOSPC etc).
+                * It doesn't make sense to loop.
+                */
+               if (errno != EEXIST)
+                       break;
+               /*
+                * This is a random value.  It is only necessary that
+                * the next TMP_MAX values generated by adding 7777 to
+                * VALUE are different with (module 2^32).
+                */
+               value += 7777;
+       }
+       /* We return the null string if we can't find a unique file name.  */
+       pattern[0] = '\0';
+       return -1;
+ }
+ int git_mkstemp_mode(char *pattern, int mode)
+ {
+       /* mkstemp is just mkstemps with no suffix */
+       return git_mkstemps_mode(pattern, 0, mode);
+ }
+ int gitmkstemps(char *pattern, int suffix_len)
+ {
+       return git_mkstemps_mode(pattern, suffix_len, 0600);
+ }
  int validate_headref(const char *path)
  {
        struct stat st;
@@@ -610,7 -689,7 +689,7 @@@ int daemon_avoid_alias(const char *p
        /*
         * This resurrects the belts and suspenders paranoia check by HPA
         * done in <435560F7.4080006@zytor.com> thread, now enter_repo()
 -       * does not do getcwd() based path canonicalizations.
 +       * does not do getcwd() based path canonicalization.
         *
         * sl becomes true immediately after seeing '/' and continues to
         * be true as long as dots continue after that without intervening
diff --combined sha1_file.c
index 006321e009b321db6cf4f7bf35d8385017a7076a,3316f282c6903eb9156835d2d2ebd0d5501ee142..c23cc5e6e19a2d8c9a92161b0a5d62a5ef8e920b
@@@ -2206,7 -2206,7 +2206,7 @@@ int move_temp_to_file(const char *tmpfi
        }
  
  out:
-       if (set_shared_perm(filename, (S_IFREG|0444)))
+       if (adjust_shared_perm(filename))
                return error("unable to set permission to '%s'", filename);
        return 0;
  }
@@@ -2262,7 -2262,7 +2262,7 @@@ static int create_tmpfile(char *buffer
        }
        memcpy(buffer, filename, dirlen);
        strcpy(buffer + dirlen, "tmp_obj_XXXXXX");
-       fd = mkstemp(buffer);
+       fd = git_mkstemp_mode(buffer, 0444);
        if (fd < 0 && dirlen && errno == ENOENT) {
                /* Make sure the directory exists */
                memcpy(buffer, filename, dirlen);
  
                /* Try again */
                strcpy(buffer + dirlen - 1, "/tmp_obj_XXXXXX");
-               fd = mkstemp(buffer);
+               fd = git_mkstemp_mode(buffer, 0444);
        }
        return fd;
  }
@@@ -2281,10 -2281,9 +2281,10 @@@ static int write_loose_object(const uns
                              void *buf, unsigned long len, time_t mtime)
  {
        int fd, ret;
 -      size_t size;
 -      unsigned char *compressed;
 +      unsigned char compressed[4096];
        z_stream stream;
 +      git_SHA_CTX c;
 +      unsigned char parano_sha1[20];
        char *filename;
        static char tmpfile[PATH_MAX];
  
        /* Set it up */
        memset(&stream, 0, sizeof(stream));
        deflateInit(&stream, zlib_compression_level);
 -      size = 8 + deflateBound(&stream, len+hdrlen);
 -      compressed = xmalloc(size);
 -
 -      /* Compress it */
        stream.next_out = compressed;
 -      stream.avail_out = size;
 +      stream.avail_out = sizeof(compressed);
 +      git_SHA1_Init(&c);
  
        /* First header.. */
        stream.next_in = (unsigned char *)hdr;
        stream.avail_in = hdrlen;
        while (deflate(&stream, 0) == Z_OK)
                /* nothing */;
 +      git_SHA1_Update(&c, hdr, hdrlen);
  
        /* Then the data itself.. */
        stream.next_in = buf;
        stream.avail_in = len;
 -      ret = deflate(&stream, Z_FINISH);
 +      do {
 +              unsigned char *in0 = stream.next_in;
 +              ret = deflate(&stream, Z_FINISH);
 +              git_SHA1_Update(&c, in0, stream.next_in - in0);
 +              if (write_buffer(fd, compressed, stream.next_out - compressed) < 0)
 +                      die("unable to write sha1 file");
 +              stream.next_out = compressed;
 +              stream.avail_out = sizeof(compressed);
 +      } while (ret == Z_OK);
 +
        if (ret != Z_STREAM_END)
                die("unable to deflate new object %s (%d)", sha1_to_hex(sha1), ret);
 -
        ret = deflateEnd(&stream);
        if (ret != Z_OK)
                die("deflateEnd on object %s failed (%d)", sha1_to_hex(sha1), ret);
 +      git_SHA1_Final(parano_sha1, &c);
 +      if (hashcmp(sha1, parano_sha1) != 0)
 +              die("confused by unstable object source data for %s", sha1_to_hex(sha1));
  
 -      size = stream.total_out;
 -
 -      if (write_buffer(fd, compressed, size) < 0)
 -              die("unable to write sha1 file");
        close_sha1_file(fd);
 -      free(compressed);
  
        if (mtime) {
                struct utimbuf utb;
@@@ -2439,8 -2434,6 +2439,8 @@@ static int index_mem(unsigned char *sha
        return ret;
  }
  
 +#define SMALL_FILE_SIZE (32*1024)
 +
  int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
             enum object_type type, const char *path)
  {
                else
                        ret = -1;
                strbuf_release(&sbuf);
 +      } else if (size <= SMALL_FILE_SIZE) {
 +              char *buf = xmalloc(size);
 +              if (size == read_in_full(fd, buf, size))
 +                      ret = index_mem(sha1, buf, size, write_object, type,
 +                                      path);
 +              else
 +                      ret = error("short read %s", strerror(errno));
 +              free(buf);
        } else if (size) {
                void *buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
                ret = index_mem(sha1, buf, size, write_object, type, path);