]> arthur.barton.de Git - netatalk.git/blob - libatalk/adouble/ad_read.c
Merge master
[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
32 #include <atalk/adouble.h>
33 #include <atalk/ea.h>
34
35 #ifndef MIN
36 #define MIN(a,b)    ((a)<(b)?(a):(b))
37 #endif /* ! MIN */
38
39 ssize_t adf_pread(struct ad_fd *ad_fd, void *buf, size_t count, off_t offset)
40 {
41     ssize_t     cc;
42
43 #ifndef  HAVE_PREAD
44     if ( ad_fd->adf_off != offset ) {
45         if ( lseek( ad_fd->adf_fd, offset, SEEK_SET ) < 0 ) {
46             return -1;
47         }
48         ad_fd->adf_off = offset;
49     }
50     if (( cc = read( ad_fd->adf_fd, buf, count )) < 0 ) {
51         return -1;
52     }
53     ad_fd->adf_off += cc;
54 #else
55     cc = pread(ad_fd->adf_fd, buf, count, offset );
56 #endif
57     return cc;
58 }
59
60 /* XXX: locks have to be checked before each stream of consecutive
61  *      ad_reads to prevent a denial in the middle from causing
62  *      problems. */
63 ssize_t ad_read( struct adouble *ad, const uint32_t eid, off_t off, char *buf, const size_t buflen)
64 {
65     ssize_t     cc;
66
67     /* We're either reading the data fork (and thus the data file)
68      * or we're reading anything else (and thus the header file). */
69     if ( eid == ADEID_DFORK ) {
70         if (ad->ad_data_fork.adf_syml !=0 ) {
71             /* It's a symlink, we already have the target in adf_syml */
72             cc = strlen(ad->ad_data_fork.adf_syml);
73             if (buflen < cc)
74                 /* Request buffersize is too small, force AFPERR_PARAM */
75                 return -1;
76             memcpy(buf, ad->ad_data_fork.adf_syml, cc);
77         } else {
78             cc = adf_pread(&ad->ad_data_fork, buf, buflen, off);
79         }
80     } else {
81         if (ad->ad_flags != AD_VERSION_EA) {
82             off_t r_off;
83             if ( ad_reso_fileno( ad ) == -1 )
84                 /* resource fork is not open ( cf etc/afp/fork.c) */
85                 return 0;
86             r_off = ad_getentryoff(ad, eid) + off;
87             if (( cc = adf_pread( &ad->ad_resource_fork, buf, buflen, r_off )) < 0 )
88                 return( -1 );
89             /*
90              * We've just read in bytes from the disk that we read earlier
91              * into ad_data. If we're going to write this buffer out later,
92              * we need to update ad_data.
93              * FIXME : always false?
94              */
95             if (r_off < ad_getentryoff(ad, ADEID_RFORK)) {
96                 if ( ad->ad_resource_fork.adf_flags & O_RDWR ) {
97                     memcpy(buf, ad->ad_data + r_off,
98                            MIN(sizeof( ad->ad_data ) - r_off, cc));
99                 } else {
100                     memcpy(ad->ad_data + r_off, buf,
101                            MIN(sizeof( ad->ad_data ) - r_off, cc));
102                 }
103             }
104         } else { /* AD_VERSION_EA */
105             if (off > ad->ad_rlen) {
106                 errno = ERANGE;
107                 return -1;
108             }
109             if (ad->ad_rlen == 0)
110                 return 0;
111             if ((off + buflen) > ad->ad_rlen)
112                 cc = ad->ad_rlen;
113             memcpy(buf, ad->ad_resforkbuf + off, cc);
114         }
115     }
116
117     return( cc );
118 }