]> arthur.barton.de Git - netatalk.git/blob - libatalk/adouble/ad_write.c
Initial revision
[netatalk.git] / libatalk / adouble / ad_write.c
1 /*
2  * Copyright (c) 1990,1995 Regents of The University of Michigan.
3  * All Rights Reserved.  See COPYRIGHT.
4  */
5
6 #include <string.h>
7 #include <sys/types.h>
8 #include <sys/param.h>
9 #include <sys/stat.h>
10 #include <unistd.h>
11 #include <fcntl.h>
12 #include <errno.h>
13
14 #include <atalk/adouble.h>
15
16 #ifndef MIN
17 #define MIN(a,b)        ((a)<(b)?(a):(b))
18 #endif
19
20 /* XXX: this would benefit from pwrite. 
21  *      locking has to be checked before each stream of consecutive
22  *      ad_writes to prevent a lock in the middle from causing problems. 
23  */
24 ssize_t ad_write( ad, eid, off, end, buf, buflen )
25     struct adouble      *ad;
26     const u_int32_t     eid;
27     off_t               off;
28     const int           end;
29     const char          *buf;
30     const size_t        buflen;
31 {
32     struct stat         st;
33     ssize_t             cc;
34
35     if ( eid == ADEID_DFORK ) {
36         if ( end ) {
37             if ( fstat( ad->ad_df.adf_fd, &st ) < 0 ) {
38                 return( -1 );
39             }
40             off = st.st_size - off;
41         }
42
43         if ( ad->ad_df.adf_off != off ) {
44             if ( lseek( ad->ad_df.adf_fd, (off_t) off, SEEK_SET ) < 0 ) {
45                 return( -1 );
46             }
47             ad->ad_df.adf_off = off;
48         }
49         cc = write( ad->ad_df.adf_fd, buf, buflen );
50         if ( cc < 0 ) {
51             return( -1 );
52         }
53         ad->ad_df.adf_off += cc;
54     } else {
55         if ( end ) {
56             off = ad->ad_eid[ eid ].ade_len - off;
57         }
58         cc = ad->ad_eid[eid].ade_off + off;
59
60 #ifdef USE_MMAPPED_HEADERS
61         if (eid != ADEID_RFORK) {
62           memcpy(ad->ad_data + cc, buf, buflen);
63           cc = buflen;
64           goto ad_write_done;
65         }         
66 #endif
67
68         if ( ad->ad_hf.adf_off != cc ) {
69           if ( lseek( ad->ad_hf.adf_fd, (off_t) cc, SEEK_SET ) < 0 ) {
70               return( -1 );
71           }
72           ad->ad_hf.adf_off = cc;
73         }
74           
75         if ((cc = write( ad->ad_hf.adf_fd, buf, buflen )) < 0)
76           return( -1 );
77         ad->ad_hf.adf_off += cc;
78         
79 #ifndef USE_MMAPPED_HEADERS
80         /* sync up our internal buffer */
81         if (ad->ad_hf.adf_off < ad_getentryoff(ad, ADEID_RFORK))
82           memcpy(ad->ad_data + ad->ad_hf.adf_off, buf,
83                  MIN(sizeof(ad->ad_data) - ad->ad_hf.adf_off, cc));
84 #else     
85 ad_write_done:
86 #endif
87           if ( ad->ad_eid[ eid ].ade_len < off + cc ) {
88             ad->ad_eid[ eid ].ade_len = off + cc;
89           }
90     }
91
92     return( cc );
93 }
94
95 /* set locks here */
96 int ad_rtruncate( ad, size )
97     struct adouble      *ad;
98     const size_t        size;
99 {
100     int err;
101
102     if (ad_tmplock(ad, ADEID_RFORK, ADLOCK_WR, 0, 0) < 0)
103       return -2;
104
105     if ( ftruncate( ad->ad_hf.adf_fd,
106             size + ad->ad_eid[ ADEID_RFORK ].ade_off ) < 0 ) {
107         err = errno;
108         ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
109         errno = err;
110         return( -1 );
111     }
112
113     ad->ad_eid[ ADEID_RFORK ].ade_len = size;
114     if ( lseek( ad->ad_hf.adf_fd, ad->ad_eid[ADEID_RFORK].ade_off, 
115                 SEEK_SET ) < 0 ) {
116         err = errno;
117         ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
118         errno = err;
119         return( -1 );
120     }
121
122     ad->ad_hf.adf_off = ad->ad_eid[ADEID_RFORK].ade_off;
123     ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0);
124     return( 0 );
125 }
126
127 int ad_dtruncate(ad, size)
128     struct adouble      *ad;
129     const size_t        size;
130 {
131     int err;
132
133     if (ad_tmplock(ad, ADEID_DFORK, ADLOCK_WR, 0, 0) < 0)
134       return -2;
135
136     if (ftruncate(ad->ad_df.adf_fd, size) < 0) {
137       err = errno;
138       ad_tmplock(ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
139       errno = err;
140     } else 
141       ad_tmplock(ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
142
143     return 0;
144 }