]> arthur.barton.de Git - netatalk.git/blobdiff - libatalk/adouble/ad_read.c
Writing metadata xattr on directories with sticky bit set, FR#94
[netatalk.git] / libatalk / adouble / ad_read.c
index 35bcc197026c35bf87412196e99f4f2da47a2e8b..852a6e963b94f964e3b47d1ea8b67df6cac0717e 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: ad_read.c,v 1.3 2001-06-29 14:14:46 rufustfirefly Exp $
- *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
  *
  * permission. This software is supplied as is without expressed or
  * implied warranties of any kind.
  *
- *     Research Systems Unix Group
- *     The University of Michigan
- *     c/o Mike Clark
- *     535 W. William Street
- *     Ann Arbor, Michigan
- *     +1-313-763-0525
- *     netatalk@itd.umich.edu
+ *  Research Systems Unix Group
+ *  The University of Michigan
+ *  c/o Mike Clark
+ *  535 W. William Street
+ *  Ann Arbor, Michigan
+ *  +1-313-763-0525
+ *  netatalk@itd.umich.edu
  */
 
 #ifdef HAVE_CONFIG_H
 #endif /* HAVE_CONFIG_H */
 
 #include <string.h>
-#include <sys/types.h>
 #include <sys/param.h>
+#include <errno.h>
+#include <stdlib.h>
+
 #include <atalk/adouble.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
+#include <atalk/ea.h>
+#include <atalk/logger.h>
+#include <atalk/util.h>
+
+ssize_t adf_pread(struct ad_fd *ad_fd, void *buf, size_t count, off_t offset)
+{
+    ssize_t     cc;
 
-#ifndef MIN
-#define MIN(a,b)       ((a)<(b)?(a):(b))
-#endif /* ! MIN */
+#ifndef  HAVE_PREAD
+    if ( ad_fd->adf_off != offset ) {
+        if ( lseek( ad_fd->adf_fd, offset, SEEK_SET ) < 0 ) {
+            return -1;
+        }
+        ad_fd->adf_off = offset;
+    }
+    if (( cc = read( ad_fd->adf_fd, buf, count )) < 0 ) {
+        return -1;
+    }
+    ad_fd->adf_off += cc;
+#else
+    cc = pread(ad_fd->adf_fd, buf, count, offset );
+#endif
+    return cc;
+}
 
-/* XXX: this would probably benefit from pread. 
- *      locks have to be checked before each stream of consecutive 
+/* XXX: locks have to be checked before each stream of consecutive
  *      ad_reads to prevent a denial in the middle from causing
  *      problems. */
-ssize_t ad_read( ad, eid, off, buf, buflen)
-    struct adouble     *ad;
-    const u_int32_t    eid;
-    off_t               off;
-    char               *buf;
-    const size_t       buflen;
+ssize_t ad_read( struct adouble *ad, const uint32_t eid, off_t off, char *buf, const size_t buflen)
 {
-    ssize_t            cc;
+    ssize_t     cc;
+    off_t r_off = 0;
 
     /* We're either reading the data fork (and thus the data file)
      * or we're reading anything else (and thus the header file). */
     if ( eid == ADEID_DFORK ) {
-       if ( ad->ad_df.adf_off != off ) {
-           if ( lseek( ad->ad_df.adf_fd, (off_t) off, SEEK_SET ) < 0 ) {
-               return( -1 );
-           }
-           ad->ad_df.adf_off = off;
-       }
-       if (( cc = read( ad->ad_df.adf_fd, buf, buflen )) < 0 ) {
-           return( -1 );
-       }
-       ad->ad_df.adf_off += cc;
+        if (ad->ad_data_fork.adf_syml !=0 ) {
+            /* It's a symlink, we already have the target in adf_syml */
+            cc = strlen(ad->ad_data_fork.adf_syml);
+            if (buflen < cc)
+                /* Request buffersize is too small, force AFPERR_PARAM */
+                return -1;
+            memcpy(buf, ad->ad_data_fork.adf_syml, cc);
+        } else {
+            cc = adf_pread(&ad->ad_data_fork, buf, buflen, off);
+        }
     } else {
-        cc = ad->ad_eid[eid].ade_off + off;
+        if (! AD_RSRC_OPEN(ad))
+            /* resource fork is not open ( cf etc/afp/fork.c) */
+            return 0;
+
+        if (ad->ad_vers == AD_VERSION_EA) {
+#ifdef HAVE_EAFD
+            r_off = off;
+#else
+            r_off = off + ADEDOFF_RFORK_OSX;
+#endif
+        } else {
+            r_off = ad_getentryoff(ad, eid) + off;
+        }
 
-#ifdef USE_MMAPPED_HEADERS
-       if (eid != ADEID_RFORK) {
-         memcpy(buf, ad->ad_data + cc, buflen);
-         cc = buflen;
-         goto ad_read_done;
-       }
-#endif /* USE_MMAPPED_HEADERS */       
-       if ( ad->ad_hf.adf_off != cc ) {
-         if ( lseek( ad->ad_hf.adf_fd, (off_t) cc, SEEK_SET ) < 0 ) {
-             return( -1 );
-         }
-         ad->ad_hf.adf_off = cc;
-       }
-         
-       if (( cc = read( ad->ad_hf.adf_fd, buf, buflen )) < 0 ) {
-         return( -1 );
-       }
-         
-#ifndef USE_MMAPPED_HEADERS
-       /*
-        * We've just read in bytes from the disk that we read earlier
-        * into ad_data. If we're going to write this buffer out later,
-        * we need to update ad_data.
-        */
-       if (ad->ad_hf.adf_off < ad_getentryoff(ad, ADEID_RFORK)) {
-           if ( ad->ad_hf.adf_flags & O_RDWR ) {
-             memcpy(buf, ad->ad_data + ad->ad_hf.adf_off,
-                    MIN(sizeof( ad->ad_data ) - ad->ad_hf.adf_off, cc));
-           } else {
-             memcpy(ad->ad_data + ad->ad_hf.adf_off, buf,
-                    MIN(sizeof( ad->ad_data ) - ad->ad_hf.adf_off, cc));
-           }
-       }
-       ad->ad_hf.adf_off += cc;
-#else /* ! USE_MMAPPED_HEADERS */
-ad_read_done:
-#endif /* ! USE_MMAPPED_HEADERS */
+        if (( cc = adf_pread( &ad->ad_resource_fork, buf, buflen, r_off )) < 0 )
+            return( -1 );
     }
 
     return( cc );