]> arthur.barton.de Git - netatalk.git/blobdiff - libatalk/adouble/ad_open.c
remove gcc warnings and cleanup inline mess
[netatalk.git] / libatalk / adouble / ad_open.c
index 44aeb5efe2ce0337cd6450a9016d1bc2ea6e33e5..086b5d850fd02c0996aacd4a6c90e2e046a00b52 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ad_open.c,v 1.30.6.14 2004-05-11 08:28:33 didg Exp $
+ * $Id: ad_open.c,v 1.30.6.18.2.8 2008-11-25 15:16:33 didg Exp $
  *
  * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
 /* we keep local copies of a bunch of stuff so that we can initialize things 
  * correctly. */
 
-/* Bits in the finderinfo data. 
- * see etc/afpd/{directory.c,file.c} for the finderinfo structure
- * layout. */
-#define FINDERINFO_CUSTOMICON 0x4
-#define FINDERINFO_CLOSEDVIEW 0x100
-
-/* offsets in finderinfo */
-#define FINDERINFO_FRTYPEOFF   0
-#define FINDERINFO_FRCREATOFF  4
-#define FINDERINFO_FRFLAGOFF   8
-#define FINDERINFO_FRVIEWOFF  14
-
 /* invisible bit for dot files */
 #define ATTRBIT_INVISIBLE     (1 << 0)
-#define FINDERINFO_INVISIBLE  (1 << 14)
 
 /* this is to prevent changing timezones from causing problems with
    localtime volumes. the screw-up is 30 years. we use a delta of 5
@@ -210,6 +197,7 @@ static const struct entry entry_order_osx[ADEID_NUM_OSX +1] = {
 
 #if AD_VERSION == AD_VERSION2
 
+/* update a version 2 adouble resource fork with our private entries */
 static int ad_update(struct adouble *ad, const char *path)
 {
   struct stat st;
@@ -219,19 +207,20 @@ static int ad_update(struct adouble *ad, const char *path)
   static off_t entry_len[ADEID_MAX];
   static char  databuf[ADEID_MAX][256], *buf;
   int fd;
+  int ret = -1;
 
   /* check to see if we should convert this header. */
-  if (!path || (ad->ad_flags != AD_VERSION2))
+  if (!path || ad->ad_flags != AD_VERSION2)
     return 0;
   
-  if (!(ad->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) {
-      /* we were unable to open the file read write the last time
-      */
+  if (!(ad->ad_hf.adf_flags & O_RDWR)) {
+      /* we were unable to open the file read write the last time */
       return 0;
   }
 
-  if (ad->ad_eid[ADEID_RFORK].ade_off)  
-    shiftdata = ADEDOFF_RFORK_V2 -ad->ad_eid[ADEID_RFORK].ade_off;
+  if (ad->ad_eid[ADEID_RFORK].ade_off) {
+      shiftdata = ADEDOFF_RFORK_V2 -ad->ad_eid[ADEID_RFORK].ade_off;
+  }
 
   memcpy(&nentries, ad->ad_data + ADEDOFF_NENTRIES, sizeof( nentries ));
   nentries = ntohs( nentries );
@@ -246,26 +235,42 @@ static int ad_update(struct adouble *ad, const char *path)
   if (ad_tmplock(ad, ADEID_RFORK, ADLOCK_WR, 0, 0, 0) < 0)
     goto bail_err;
 
-  if ((fd = open(path, O_RDWR)) < 0)
-    goto bail_lock;
+  fd = ad->ad_hf.adf_fd;
 
-  if (fstat(fd, &st) ||
-    sys_ftruncate(fd, st.st_size + shiftdata) < 0) {
-    goto bail_open;
+  if (fstat(fd, &st)) {
+    goto bail_lock;
   }
+
   if (st.st_size > 0x7fffffff) {
-    LOG(log_debug, logtype_default, "ad_update: file '%s' too big for update.", path);
-    goto bail_truncate;
+      LOG(log_debug, logtype_default, "ad_update: file '%s' too big for update.", path);
+      errno = EIO;
+      goto bail_lock;
   }
-  /* last place for failure. */
+
+  off = ad->ad_eid[ADEID_RFORK].ade_off;
+  if (off > st.st_size) {
+      LOG(log_error, logtype_default, "ad_update: invalid resource fork offset. (off: %u)", off); 
+      errno = EIO;
+      goto bail_lock;
+  }
+
+  if (ad->ad_eid[ADEID_RFORK].ade_len > st.st_size - off) {
+      LOG(log_error, logtype_default, "ad_update: invalid resource fork length. (rfork len: %u)", ad->ad_eid[ADEID_RFORK].ade_len); 
+      errno = EIO;
+      goto bail_lock;
+  }
+  
   if ((void *) (buf = (char *)
                 mmap(NULL, st.st_size + shiftdata,
                      PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) ==
           MAP_FAILED) {
-    goto bail_truncate;
+    goto bail_lock;
   }
 
-  off = ad->ad_eid[ADEID_RFORK].ade_off;
+  /* last place for failure. */
+  if (sys_ftruncate(fd, st.st_size + shiftdata) < 0) {
+    goto bail_lock;
+  }
 
   /* move the RFORK. this assumes that the RFORK is at the end */
   if (off) {
@@ -273,7 +278,6 @@ static int ad_update(struct adouble *ad, const char *path)
   }
 
   munmap(buf, st.st_size + shiftdata);
-  close(fd);
 
   /* now, fix up our copy of the header */
   memset(ad->ad_filler, 0, sizeof(ad->ad_filler));
@@ -303,53 +307,46 @@ static int ad_update(struct adouble *ad, const char *path)
   }
 
   /* rebuild the header and cleanup */
-  ad_flush(ad, ADFLAGS_HF );
-  ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0, 0);
-
   LOG(log_debug, logtype_default, "updated AD2 header %s", path);
+  ad_flush(ad, ADFLAGS_HF );
+  ret = 0;
 
-  return 0;
-
-bail_truncate:
-  sys_ftruncate(fd, st.st_size);
-bail_open:
-  close(fd);
 bail_lock:
   ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0, 0);
 bail_err:
-  return -1;
+  return ret;
 }
 
-
-/* FIXME work only if < 2GB */
-static int ad_v1tov2(struct adouble *ad, const char *path)
+/* ------------------------------------------
+   FIXME work only if < 2GB 
+*/
+static int ad_convert(struct adouble *ad, const char *path)
 {
   struct stat st;
   u_int16_t attr;
   char *buf;
   int fd, off;
+  int ret = -1;
   /* use resource fork offset from file */
   int shiftdata;
+  int toV2;
+  int toV1;
   
-  /* check to see if we should convert this header. */
-  if (!path || (ad->ad_version != AD_VERSION1))
-    return 0;
-
-  /* we want version1 anyway */
-  if (ad->ad_flags != AD_VERSION2)
+  if (!path) {
       return 0;
-
-  if (!(ad->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) {
-      /* we were unable to open the file read write the last time
-      */
+  }
+  
+  if (!(ad->ad_hf.adf_flags & ( O_RDWR))) {
+      /* we were unable to open the file read write the last time */
       return 0;
   }
 
-  if (!ad->ad_flags) {
-      /* we don't really know what we want */
-      ad->ad_flags = ad->ad_version;
+  /* check to see if we should convert this header. */
+  toV2 = ad->ad_version == AD_VERSION1 && ad->ad_flags == AD_VERSION2;
+  toV1 = ad->ad_version == AD_VERSION2 && ad->ad_flags == AD_VERSION1;
+
+  if (!toV2 && !toV1)
       return 0;
-  }
 
   /* convert from v1 to v2. what does this mean?
    *  1) change FILEI into FILEDATESI
@@ -362,9 +359,9 @@ static int ad_v1tov2(struct adouble *ad, const char *path)
   /* bail if we can't get a lock */
   if (ad_tmplock(ad, ADEID_RFORK, ADLOCK_WR, 0, 0, 0) < 0) 
     goto bail_err;
-  
-  if ((fd = open(path, O_RDWR)) < 0) 
-    goto bail_lock;
+
+  /* we reuse fd from the resource fork */
+  fd = ad->ad_hf.adf_fd;
 
   if (ad->ad_eid[ADEID_RFORK].ade_off) {
       shiftdata = ADEDOFF_RFORK_V2 -ad->ad_eid[ADEID_RFORK].ade_off;
@@ -373,32 +370,49 @@ static int ad_v1tov2(struct adouble *ad, const char *path)
       shiftdata = ADEDOFF_RFORK_V2 -ADEDOFF_RFORK_V1; /* 136 */
   }
 
-  if (fstat(fd, &st) ||
-      sys_ftruncate(fd, st.st_size + shiftdata) < 0) {
-    goto bail_open;
+  if (fstat(fd, &st)) { 
+      goto bail_lock;
   }
-  if (st.st_size > 0x7fffffff) {
+
+  if (st.st_size > 0x7fffffff -shiftdata) {
       LOG(log_debug, logtype_default, "ad_v1tov2: file too big."); 
-      goto bail_truncate;
+      errno = EIO;
+      goto bail_lock;
+  }
+  
+  off = ad->ad_eid[ADEID_RFORK].ade_off;
+
+  if (off > st.st_size) {
+      LOG(log_error, logtype_default, "ad_v1tov2: invalid resource fork offset. (off: %u)", off); 
+      errno = EIO;
+      goto bail_lock;
+  }
+
+  if (ad->ad_eid[ADEID_RFORK].ade_len > st.st_size - off) {
+      LOG(log_error, logtype_default, "ad_v1tov2: invalid resource fork length. (rfork len: %u)", ad->ad_eid[ADEID_RFORK].ade_len); 
+      errno = EIO;
+      goto bail_lock;
   }
   
-  /* last place for failure. */
   if ((void *) (buf = (char *) 
                mmap(NULL, st.st_size + shiftdata,
                     PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == 
          MAP_FAILED) {
-    goto bail_truncate;
+    goto bail_lock;
   }
-  
-  off = ad->ad_eid[ADEID_RFORK].ade_off;
 
+  /* last place for failure. */
+
+  if (sys_ftruncate(fd, st.st_size + shiftdata) < 0) {
+      goto bail_lock;
+  }
+  
   /* move the RFORK. this assumes that the RFORK is at the end */
   if (off) {
       memmove(buf + ADEDOFF_RFORK_V2, buf + off, ad->ad_eid[ADEID_RFORK].ade_len);
   }
 
   munmap(buf, st.st_size + shiftdata);
-  close(fd);
 
   /* now, fix up our copy of the header */
   memset(ad->ad_filler, 0, sizeof(ad->ad_filler));
@@ -435,8 +449,8 @@ static int ad_v1tov2(struct adouble *ad, const char *path)
   ad->ad_eid[ADEID_FINDERI].ade_off = ADEDOFF_FINDERI_V2;
   ad->ad_eid[ADEID_RFORK].ade_off = ADEDOFF_RFORK_V2;
   
-  /* switch to v2 */
-  ad->ad_version = AD_VERSION2;
+  /* switch to dest version */
+  ad->ad_version = (toV2)?AD_VERSION2:AD_VERSION1;
   
   /* move our data buffer to make space for the new entries. */
   memmove(ad->ad_data + ADEDOFF_NAME_V2, ad->ad_data + ADEDOFF_NAME_V1,
@@ -453,21 +467,16 @@ static int ad_v1tov2(struct adouble *ad, const char *path)
   
   /* rebuild the header and cleanup */
   ad_flush(ad, ADFLAGS_HF );
-  ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0, 0);
-
-  return 0;
+  ret = 0;
   
-bail_truncate:
-  sys_ftruncate(fd, st.st_size);
-bail_open:
-  close(fd);
 bail_lock:
   ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0, 0);
 bail_err:
-  return -1;
+  return ret;
 }
 #endif /* AD_VERSION == AD_VERSION2 */
 
+/* --------------------------- */
 #ifdef ATACC
 mode_t ad_hf_mode (mode_t mode)
 {
@@ -475,6 +484,7 @@ mode_t ad_hf_mode (mode_t mode)
 #if 0
     mode |= S_IRUSR;
 #endif    
+    mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
     /* fnctl lock need write access */
     if ((mode & S_IRUSR))
         mode |= S_IWUSR;
@@ -516,7 +526,8 @@ static void parse_entries(struct adouble *ad, char *buf,
        len = ntohl( len );
        buf += sizeof( len );
 
-       if ( 0 < eid && eid < ADEID_MAX ) {
+       if (eid && eid < ADEID_MAX && ( (off < sizeof(ad->ad_data) && 
+                off +len <= sizeof(ad->ad_data)) || eid == ADEID_RFORK)) {
            ad->ad_eid[ eid ].ade_off = off;
            ad->ad_eid[ eid ].ade_len = len;
        } else if (!warning) {
@@ -701,9 +712,7 @@ ad_path( path, adflags )
  * ._name
  */
 char *
-ad_path_osx( path, adflags )
-    const char *path;
-    int                adflags;
+ad_path_osx( const char        *path, int adflags _U_)
 {
     static char        pathbuf[ MAXPATHLEN + 1];
     char       c, *slash, buf[MAXPATHLEN + 1];
@@ -822,7 +831,7 @@ int ret = 0;
 #ifdef EMULATE_SUIDDIR
 uid_t id;
 
-    if (default_uid != -1) {  
+    if (default_uid != (uid_t)-1) {  
         /* we are root (admin) */
         id = (default_uid)?default_uid:stbuf->st_uid;
        ret = chown( path, id, stbuf->st_gid );
@@ -908,7 +917,7 @@ static int new_rfork(const char *path, struct adouble *ad, int adflags);
 #define AD_SET(a) a = 0
 #endif
 
-void ad_init(struct adouble *ad, int flags)
+void ad_init(struct adouble *ad, int flags, int options)
 {
     memset( ad, 0, sizeof( struct adouble ) );
     ad->ad_flags = flags;
@@ -918,6 +927,7 @@ void ad_init(struct adouble *ad, int flags)
     else {
         ad->ad_path     = ad_path;
     }
+    ad->ad_options = options;
 }
 
 /* -------------------
@@ -932,7 +942,7 @@ int ad_open( path, adflags, oflags, mode, ad )
     struct stat         st;
     char               *slash, *ad_p;
     int                        hoflags, admode;
-    int                 st_invalid;
+    int                 st_invalid = -1;
     int                 open_df = 0;
     
     if (ad->ad_inited != AD_INITED) {
@@ -948,12 +958,17 @@ int ad_open( path, adflags, oflags, mode, ad )
         if (ad_dfileno(ad) == -1) {
          hoflags = (oflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
          admode = mode;
-         st_invalid = ad_mode_st(path, &admode, &st);
+         if ((oflags & O_CREAT)) {
+             st_invalid = ad_mode_st(path, &admode, &st);
+             if ((ad->ad_options & ADVOL_UNIXPRIV)) {
+                 admode = mode;
+             }
+         }
           ad->ad_df.adf_fd =open( path, hoflags, admode );
          if (ad->ad_df.adf_fd < 0 ) {
              if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) {
                 hoflags = oflags;
-                ad->ad_df.adf_fd =open( path, hoflags, admode );
+                ad->ad_df.adf_fd = open( path, hoflags, admode );
              }
          }
          if ( ad->ad_df.adf_fd < 0)
@@ -961,7 +976,7 @@ int ad_open( path, adflags, oflags, mode, ad )
 
          AD_SET(ad->ad_df.adf_off);
          ad->ad_df.adf_flags = hoflags;
-         if ((oflags & O_CREAT) && !st_invalid) {
+         if (!st_invalid) {
              /* just created, set owner if admin (root) */
              ad_chown(path, &st);
          }
@@ -1028,6 +1043,9 @@ int ad_open( path, adflags, oflags, mode, ad )
            admode = mode;
            errno = 0;
            st_invalid = ad_mode_st(ad_p, &admode, &st);
+           if ((ad->ad_options & ADVOL_UNIXPRIV)) {
+               admode = mode;
+           }
            admode = ad_hf_mode(admode); 
            if ( errno == ENOENT && !(adflags & ADFLAGS_NOADOUBLE) && ad->ad_flags != AD_VERSION2_OSX) {
                /*
@@ -1045,6 +1063,9 @@ int ad_open( path, adflags, oflags, mode, ad )
                *slash = '/';
                admode = mode;
                st_invalid = ad_mode_st(ad_p, &admode, &st);
+               if ((ad->ad_options & ADVOL_UNIXPRIV)) {
+                   admode = mode;
+               }
                admode = ad_hf_mode(admode); 
            }
            /* retry with O_CREAT */
@@ -1087,7 +1108,7 @@ int ad_open( path, adflags, oflags, mode, ad )
            /* Read the adouble header in and parse it.*/
        if ((ad_header_read( ad , &st) < 0)
 #if AD_VERSION == AD_VERSION2
-               || (ad_v1tov2(ad, ad_p) < 0) || (ad_update(ad, ad_p) < 0)
+               || (ad_convert(ad, ad_p) < 0) || (ad_update(ad, ad_p) < 0)
 #endif /* AD_VERSION == AD_VERSION2 */
         ) {
             int err = errno;
@@ -1166,17 +1187,18 @@ static int new_rfork(const char *path, struct adouble *ad, int adflags)
                     &ashort, sizeof(ashort));
     } else {
         /* set default creator/type fields */
-       memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRTYPEOFF,"TEXT", 4);
-       memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRCREATOFF,"UNIX", 4);
+       memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRTYPEOFF,"\0\0\0\0", 4);
+       memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRCREATOFF,"\0\0\0\0", 4);
     }
 
     /* make things invisible */
-    if ((*path == '.') && strcmp(path, ".") && strcmp(path, "..")) {
+    if ((ad->ad_options & ADVOL_INVDOTS) && !(adflags & ADFLAGS_CREATE) && 
+           (*path == '.') && strcmp(path, ".") && strcmp(path, "..")) 
+    {
         ashort = htons(ATTRBIT_INVISIBLE);
        ad_setattr(ad, ashort);
        ashort = htons(FINDERINFO_INVISIBLE);
-       memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF,
-                    &ashort, sizeof(ashort));
+       memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
     }
 
     if (stat(path, &st) < 0) {