]> arthur.barton.de Git - netatalk.git/blobdiff - libatalk/adouble/ad_read.c
Merge master
[netatalk.git] / libatalk / adouble / ad_read.c
index 19d6218f3e6ff28c0ef95c4423ce39b99e35491d..224c72d9fb381fe12470a27117a2aab52117545a 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: ad_read.c,v 1.9 2009-10-13 22:55:37 didg Exp $
- *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
  *
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#include <atalk/adouble.h>
 #include <string.h>
 #include <sys/param.h>
+#include <errno.h>
+
+#include <atalk/adouble.h>
+#include <atalk/ea.h>
 
 #ifndef MIN
 #define MIN(a,b)    ((a)<(b)?(a):(b))
@@ -59,40 +60,57 @@ ssize_t adf_pread(struct ad_fd *ad_fd, void *buf, size_t count, off_t offset)
 /* 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( 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;
 
     /* 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 ) {
-        cc = adf_pread(&ad->ad_data_fork, buf, buflen, off);
-    } else {
-        off_t r_off;
-
-        if ( ad_reso_fileno( ad ) == -1 ) {
-            /* resource fork is not open ( cf etc/afp/fork.c) */
-            return 0;
-        }
-        r_off = ad_getentryoff(ad, eid) + off;
-
-        if (( cc = adf_pread( &ad->ad_resource_fork, buf, buflen, r_off )) < 0 ) {
-            return( -1 );
+        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);
         }
-        /*
-         * 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.
-         * FIXME : always false?
-         */
-        if (r_off < ad_getentryoff(ad, ADEID_RFORK)) {
-            if ( ad->ad_resource_fork.adf_flags & O_RDWR ) {
-                memcpy(buf, ad->ad_data + r_off,
-                       MIN(sizeof( ad->ad_data ) - r_off, cc));
-            } else {
-                memcpy(ad->ad_data + r_off, buf,
-                       MIN(sizeof( ad->ad_data ) - r_off, cc));
+    } else {
+        if (ad->ad_flags != AD_VERSION_EA) {
+            off_t r_off;
+            if ( ad_reso_fileno( ad ) == -1 )
+                /* resource fork is not open ( cf etc/afp/fork.c) */
+                return 0;
+            r_off = ad_getentryoff(ad, eid) + off;
+            if (( cc = adf_pread( &ad->ad_resource_fork, buf, buflen, r_off )) < 0 )
+                return( -1 );
+            /*
+             * 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.
+             * FIXME : always false?
+             */
+            if (r_off < ad_getentryoff(ad, ADEID_RFORK)) {
+                if ( ad->ad_resource_fork.adf_flags & O_RDWR ) {
+                    memcpy(buf, ad->ad_data + r_off,
+                           MIN(sizeof( ad->ad_data ) - r_off, cc));
+                } else {
+                    memcpy(ad->ad_data + r_off, buf,
+                           MIN(sizeof( ad->ad_data ) - r_off, cc));
+                }
+            }
+        } else { /* AD_VERSION_EA */
+            if (off > ad->ad_rlen) {
+                errno = ERANGE;
+                return -1;
             }
+            if (ad->ad_rlen == 0)
+                return 0;
+            if ((off + buflen) > ad->ad_rlen)
+                cc = ad->ad_rlen;
+            memcpy(buf, ad->ad_resforkbuf + off, cc);
         }
     }