]> arthur.barton.de Git - netatalk.git/blob - libatalk/adouble/ad_read.c
Merge remote branch 'origin/master' into branch-allea
[netatalk.git] / libatalk / adouble / ad_read.c
1 /*
2  * Copyright (c) 1990,1991 Regents of The University of Michigan.
3  * All Rights Reserved.
4  *
5  * Permission to use, copy, modify, and distribute this software and
6  * its documentation for any purpose and without fee is hereby granted,
7  * provided that the above copyright notice appears in all copies and
8  * that both that copyright notice and this permission notice appear
9  * in supporting documentation, and that the name of The University
10  * of Michigan not be used in advertising or publicity pertaining to
11  * distribution of the software without specific, written prior
12  * permission. This software is supplied as is without expressed or
13  * implied warranties of any kind.
14  *
15  *  Research Systems Unix Group
16  *  The University of Michigan
17  *  c/o Mike Clark
18  *  535 W. William Street
19  *  Ann Arbor, Michigan
20  *  +1-313-763-0525
21  *  netatalk@itd.umich.edu
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif /* HAVE_CONFIG_H */
27
28 #include <string.h>
29 #include <sys/param.h>
30 #include <errno.h>
31 #include <stdlib.h>
32
33 #include <atalk/adouble.h>
34 #include <atalk/ea.h>
35 #include <atalk/logger.h>
36 #include <atalk/util.h>
37
38 ssize_t adf_pread(struct ad_fd *ad_fd, void *buf, size_t count, off_t offset)
39 {
40     ssize_t     cc;
41
42 #ifndef  HAVE_PREAD
43     if ( ad_fd->adf_off != offset ) {
44         if ( lseek( ad_fd->adf_fd, offset, SEEK_SET ) < 0 ) {
45             return -1;
46         }
47         ad_fd->adf_off = offset;
48     }
49     if (( cc = read( ad_fd->adf_fd, buf, count )) < 0 ) {
50         return -1;
51     }
52     ad_fd->adf_off += cc;
53 #else
54     cc = pread(ad_fd->adf_fd, buf, count, offset );
55 #endif
56     return cc;
57 }
58
59 /* XXX: locks have to be checked before each stream of consecutive
60  *      ad_reads to prevent a denial in the middle from causing
61  *      problems. */
62 ssize_t ad_read( struct adouble *ad, const uint32_t eid, off_t off, char *buf, const size_t buflen)
63 {
64     ssize_t     cc;
65     ssize_t     rlen;
66     off_t r_off;
67
68     /* We're either reading the data fork (and thus the data file)
69      * or we're reading anything else (and thus the header file). */
70     if ( eid == ADEID_DFORK ) {
71         if (ad->ad_data_fork.adf_syml !=0 ) {
72             /* It's a symlink, we already have the target in adf_syml */
73             cc = strlen(ad->ad_data_fork.adf_syml);
74             if (buflen < cc)
75                 /* Request buffersize is too small, force AFPERR_PARAM */
76                 return -1;
77             memcpy(buf, ad->ad_data_fork.adf_syml, cc);
78         } else {
79             cc = adf_pread(&ad->ad_data_fork, buf, buflen, off);
80         }
81     } else {
82         if (! AD_RSRC_OPEN(ad))
83             /* resource fork is not open ( cf etc/afp/fork.c) */
84             return 0;
85
86         switch (ad->ad_vers) {
87         case AD_VERSION2:
88             r_off = ad_getentryoff(ad, eid) + off;
89             if (( cc = adf_pread( &ad->ad_resource_fork, buf, buflen, r_off )) < 0 )
90                 return( -1 );
91             /*
92              * We've just read in bytes from the disk that we read earlier
93              * into ad_data. If we're going to write this buffer out later,
94              * we need to update ad_data.
95              * FIXME : always false?
96              */
97             if (r_off < ad_getentryoff(ad, ADEID_RFORK)) {
98                 if ( ad->ad_resource_fork.adf_flags & O_RDWR ) {
99                     memcpy(buf, ad->ad_data + r_off,
100                            MIN(sizeof( ad->ad_data ) - r_off, cc));
101                 } else {
102                     memcpy(ad->ad_data + r_off, buf,
103                            MIN(sizeof( ad->ad_data ) - r_off, cc));
104                 }
105             }
106             break;
107
108         case AD_VERSION_EA:
109             if ((rlen = sys_fgetxattr(ad_data_fileno(ad), AD_EA_RESO, NULL, 0)) <= 0) {
110                 switch (errno) {
111                 case ENOATTR:
112                 case ENOENT:
113                     cc = ad->ad_rlen = 0;
114                     break;
115                 default:
116                     LOG(log_error, logtype_default, "ad_read: %s", strerror(errno));
117                     return -1;
118                 }
119             }
120             ad->ad_rlen = rlen;
121
122             if (off > ad->ad_rlen) {
123                 errno = ERANGE;
124                 return -1;
125             }
126
127             if (ad->ad_resforkbuf == NULL) {
128                 if ((ad->ad_resforkbuf = malloc(ad->ad_rlen)) == NULL) {
129                     ad->ad_rlen = 0;
130                     return -1;
131                 }
132             } else {
133                 if ((ad->ad_resforkbuf = realloc(ad->ad_resforkbuf, ad->ad_rlen)) == NULL) {
134                     ad->ad_rlen = 0;
135                     return -1;
136                 } 
137             }
138
139             if (sys_fgetxattr(ad_data_fileno(ad), AD_EA_RESO, ad->ad_resforkbuf, ad->ad_rlen) == -1) {
140                 ad->ad_rlen = 0;
141                 return -1;
142             }       
143
144             if ((off + buflen) > ad->ad_rlen)
145                 cc = ad->ad_rlen;
146             memcpy(buf, ad->ad_resforkbuf + off, cc);
147             break;
148         } /* switch (ad->ad_vers) */
149     }
150
151     return( cc );
152 }