2
* $Id: file.c,v 1.62.2.1 2003/06/09 14:53:15 srittau Exp $
4
* Copyright (c) 1990,1993 Regents of The University of Michigan.
5
* All Rights Reserved. See COPYRIGHT.
10
#endif /* HAVE_CONFIG_H */
16
#endif /* HAVE_UNISTD_H */
21
#else /* STDC_HEADERS */
25
#endif /* HAVE_STRCHR */
26
char *strchr (), *strrchr ();
28
#define memcpy(d,s,n) bcopy ((s), (d), (n))
29
#define memmove(d,s,n) bcopy ((s), (d), (n))
30
#endif /* ! HAVE_MEMCPY */
31
#endif /* STDC_HEADERS */
36
#endif /* HAVE_FCNTL_H */
41
#include <atalk/logger.h>
42
#include <sys/types.h>
44
#include <sys/param.h>
47
#include <netatalk/endian.h>
48
#include <atalk/adouble.h>
49
#include <atalk/afp.h>
50
#include <atalk/util.h>
52
#include <atalk/cnid.h>
54
#include "directory.h"
62
/* the format for the finderinfo fields (from IM: Toolbox Essentials):
63
* field bytes subfield bytes
66
* ioFlFndrInfo 16 -> type 4 type field
67
* creator 4 creator field
68
* flags 2 finder flags:
70
* location 4 location in window
71
* folder 2 window that contains file
73
* ioFlXFndrInfo 16 -> iconID 2 icon id
75
* script 1 script system
77
* commentID 2 comment id
78
* putawayID 4 home directory id
81
const u_char ufinderi[] = {
82
'T', 'E', 'X', 'T', 'U', 'N', 'I', 'X',
83
0, 0, 0, 0, 0, 0, 0, 0,
84
0, 0, 0, 0, 0, 0, 0, 0,
85
0, 0, 0, 0, 0, 0, 0, 0
88
int getmetadata(struct vol *vol,
90
char *path, struct dir *dir, struct stat *st,
91
char *buf, int *buflen, struct adouble *adp, int attrbits )
94
struct stat lst, *lstp;
95
#endif /* USE_LASTDID */
97
char *data, *nameoff = NULL, *upath;
101
u_char achar, fdType[4];
107
LOG(log_info, logtype_afpd, "begin getmetadata:");
110
upath = mtoupath(vol, path);
113
while ( bitmap != 0 ) {
114
while (( bitmap & 1 ) == 0 ) {
122
ad_getattr(adp, &ashort);
123
} else if (*upath == '.') {
124
ashort = htons(ATTRBIT_INVISIBLE);
128
/* FIXME do we want a visual clue if the file is read only
130
accessmode( ".", &ma, dir , NULL);
131
if ((ma.ma_user & AR_UWRITE)) {
132
accessmode( upath, &ma, dir , st);
133
if (!(ma.ma_user & AR_UWRITE)) {
134
attrbits |= ATTRBIT_NOWRITE;
139
ashort = htons(ntohs(ashort) | attrbits);
140
memcpy(data, &ashort, sizeof( ashort ));
141
data += sizeof( ashort );
145
memcpy(data, &dir->d_did, sizeof( u_int32_t ));
146
data += sizeof( u_int32_t );
150
if (!adp || (ad_getdate(adp, AD_DATE_CREATE, &aint) < 0))
151
aint = AD_DATE_FROM_UNIX(st->st_mtime);
152
memcpy(data, &aint, sizeof( aint ));
153
data += sizeof( aint );
157
if ( adp && (ad_getdate(adp, AD_DATE_MODIFY, &aint) == 0)) {
158
if ((st->st_mtime > AD_DATE_TO_UNIX(aint))) {
159
aint = AD_DATE_FROM_UNIX(st->st_mtime);
162
aint = AD_DATE_FROM_UNIX(st->st_mtime);
164
memcpy(data, &aint, sizeof( int ));
165
data += sizeof( int );
169
if (!adp || (ad_getdate(adp, AD_DATE_BACKUP, &aint) < 0))
170
aint = AD_DATE_START;
171
memcpy(data, &aint, sizeof( int ));
172
data += sizeof( int );
177
memcpy(data, ad_entry(adp, ADEID_FINDERI), 32);
179
memcpy(data, ufinderi, 32);
180
if (*upath == '.') { /* make it invisible */
181
ashort = htons(FINDERINFO_INVISIBLE);
182
memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
186
if ((!adp || !memcmp(ad_entry(adp, ADEID_FINDERI),ufinderi , 8 ))
187
&& (em = getextmap( path ))
189
memcpy(data, em->em_type, sizeof( em->em_type ));
190
memcpy(data + 4, em->em_creator, sizeof(em->em_creator));
197
data += sizeof( u_int16_t );
201
memset(data, 0, sizeof(u_int16_t));
202
data += sizeof( u_int16_t );
207
#if AD_VERSION > AD_VERSION1
208
/* look in AD v2 header */
210
memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint));
211
#endif /* AD_VERSION > AD_VERSION1 */
214
aint = cnid_add(vol->v_db, st, dir->d_did, upath,
215
strlen(upath), aint);
216
/* Throw errors if cnid_add fails. */
217
if (aint == CNID_INVALID) {
220
LOG(log_error, logtype_afpd, "getfilparams: Incorrect parameters passed to cnid_add");
221
return(AFPERR_PARAM);
223
return(AFPERR_PARAM);
233
* What a fucking mess. First thing: DID and FNUMs are
234
* in the same space for purposes of enumerate (and several
235
* other wierd places). While we consider this Apple's bug,
236
* this is the work-around: In order to maintain constant and
237
* unique DIDs and FNUMs, we monotonically generate the DIDs
238
* during the session, and derive the FNUMs from the filesystem.
239
* Since the DIDs are small, we insure that the FNUMs are fairly
240
* large by setting thier high bits to the device number.
242
* AFS already does something very similar to this for the
243
* inode number, so we don't repeat the procedure.
246
* due to complaints over did's being non-persistent,
247
* here's the current hack to provide semi-persistent
249
* 1) we reserve the first bit for file ids.
250
* 2) the next 7 bits are for the device.
251
* 3) the remaining 24 bits are for the inode.
253
* both the inode and device information are actually hashes
254
* that are then truncated to the requisite bit length.
256
* it should be okay to use lstat to deal with symlinks.
259
aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff));
260
#else /* USE_LASTDID */
261
lstp = lstat(upath, &lst) < 0 ? st : &lst;
262
aint = htonl(CNID(lstp, 1));
263
#endif /* USE_LASTDID */
266
memcpy(data, &aint, sizeof( aint ));
267
data += sizeof( aint );
271
aint = htonl( st->st_size );
272
memcpy(data, &aint, sizeof( aint ));
273
data += sizeof( aint );
278
aint = htonl( ad_getentrylen( adp, ADEID_RFORK ));
282
memcpy(data, &aint, sizeof( aint ));
283
data += sizeof( aint );
286
/* Current client needs ProDOS info block for this file.
287
Use simple heuristic and let the Mac "type" string tell
288
us what the PD file code should be. Everything gets a
289
subtype of 0x0000 unless the original value was hashed
290
to "pXYZ" when we created it. See IA, Ver 2.
292
case FILPBIT_PDINFO :
294
memcpy(fdType, ad_entry( adp, ADEID_FINDERI ), 4 );
296
if ( memcmp( fdType, "TEXT", 4 ) == 0 ) {
300
else if ( memcmp( fdType, "PSYS", 4 ) == 0 ) {
304
else if ( memcmp( fdType, "PS16", 4 ) == 0 ) {
308
else if ( memcmp( fdType, "BINA", 4 ) == 0 ) {
312
else if ( fdType[0] == 'p' ) {
314
ashort = (fdType[2] * 256) + fdType[3];
328
memcpy(data, &ashort, sizeof( ashort ));
329
data += sizeof( ashort );
330
memset(data, 0, sizeof( ashort ));
331
data += sizeof( ashort );
335
return( AFPERR_BITMAP );
341
ashort = htons( data - buf );
342
memcpy(nameoff, &ashort, sizeof( ashort ));
343
if ((aint = strlen( path )) > MACFILELEN)
346
memcpy(data, path, aint );
349
*buflen = data - buf;
353
/* ----------------------- */
354
int getfilparams(struct vol *vol,
356
char *path, struct dir *dir, struct stat *st,
357
char *buf, int *buflen )
359
struct adouble ad, *adp;
362
u_int16_t attrbits = 0;
365
LOG(log_info, logtype_afpd, "begin getfilparams:");
368
upath = mtoupath(vol, path);
369
if ((of = of_findname(upath, st))) {
371
attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
372
attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
375
memset(&ad, 0, sizeof(ad));
379
if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
385
we need to check if the file is open by another process.
386
it's slow so we only do it if we have to:
387
- bitmap is requested.
388
- we don't already have the answer!
390
if ((bitmap & (1 << FILPBIT_ATTR))) {
391
if (!(attrbits & ATTRBIT_ROPEN)) {
393
if (!(attrbits & ATTRBIT_DOPEN)) {
398
rc = getmetadata(vol, bitmap, path, dir, st, buf, buflen, adp, attrbits);
400
ad_close( adp, ADFLAGS_HF );
403
LOG(log_info, logtype_afpd, "end getfilparams:");
409
/* ----------------------------- */
410
int afp_createfile(obj, ibuf, ibuflen, rbuf, rbuflen )
413
int ibuflen, *rbuflen;
416
struct adouble ad, *adp;
419
struct ofork *of = NULL;
421
int creatf, did, openf, retvalue = AFP_OK;
425
LOG(log_info, logtype_afpd, "begin afp_createfile:");
430
creatf = (unsigned char) *ibuf++;
432
memcpy(&vid, ibuf, sizeof( vid ));
433
ibuf += sizeof( vid );
435
if (( vol = getvolbyvid( vid )) == NULL ) {
436
return( AFPERR_PARAM );
439
if (vol->v_flags & AFPVOL_RO)
442
memcpy(&did, ibuf, sizeof( did));
443
ibuf += sizeof( did );
445
if (( dir = dirlookup( vol, did )) == NULL ) {
446
return( AFPERR_NOOBJ );
449
if (( path = cname( vol, dir, &ibuf )) == NULL ) {
450
return( AFPERR_NOOBJ );
453
upath = mtoupath(vol, path);
454
if (0 != (ret = check_name(vol, upath)))
457
ret = stat(upath, &st);
458
/* if upath is deleted we already in trouble anyway */
459
if (!ret && (of = of_findname(upath, &st))) {
462
memset(&ad, 0, sizeof(ad));
466
/* on a hard create, fail if file exists and is open */
469
openf = O_RDWR|O_CREAT|O_TRUNC;
471
/* on a soft create, if the file is open then ad_open won't fail
472
because open syscall is not called
477
openf = O_RDWR|O_CREAT|O_EXCL;
480
if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF,
481
openf, 0666, adp) < 0 ) {
484
return( AFPERR_EXIST );
486
return( AFPERR_ACCESS );
488
/* on noadouble volumes, just creating the data fork is ok */
489
if (vol_noadouble(vol) && (stat(upath, &st) == 0))
490
goto createfile_done;
493
return( AFPERR_PARAM );
497
ad_setentrylen( adp, ADEID_NAME, strlen( path ));
498
memcpy(ad_entry( adp, ADEID_NAME ), path,
499
ad_getentrylen( adp, ADEID_NAME ));
500
ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
501
ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
506
if (vol->v_flags & AFPVOL_DROPBOX) {
507
retvalue = matchfile2dirperms(upath, vol, did);
509
#endif /* DROPKLUDGE */
511
setvoltime(obj, vol );
514
LOG(log_info, logtype_afpd, "end afp_createfile");
520
int afp_setfilparams(obj, ibuf, ibuflen, rbuf, rbuflen )
523
int ibuflen, *rbuflen;
529
u_int16_t vid, bitmap;
532
LOG(log_info, logtype_afpd, "begin afp_setfilparams:");
538
memcpy(&vid, ibuf, sizeof( vid ));
539
ibuf += sizeof( vid );
540
if (( vol = getvolbyvid( vid )) == NULL ) {
541
return( AFPERR_PARAM );
544
if (vol->v_flags & AFPVOL_RO)
547
memcpy(&did, ibuf, sizeof( did ));
548
ibuf += sizeof( did );
549
if (( dir = dirlookup( vol, did )) == NULL ) {
550
return( AFPERR_NOOBJ );
553
memcpy(&bitmap, ibuf, sizeof( bitmap ));
554
bitmap = ntohs( bitmap );
555
ibuf += sizeof( bitmap );
557
if (( path = cname( vol, dir, &ibuf )) == NULL ) {
558
return( AFPERR_NOOBJ );
561
if ( *path == '\0' ) {
562
return( AFPERR_BADTYPE ); /* it's a directory */
565
if ((u_long)ibuf & 1 ) {
569
if (( rc = setfilparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
570
setvoltime(obj, vol );
574
LOG(log_info, logtype_afpd, "end afp_setfilparams:");
581
* cf AFP3.0.pdf page 252 for change_mdate and change_parent_mdate logic
585
int setfilparams(struct vol *vol,
586
char *path, u_int16_t bitmap, char *buf )
588
struct adouble ad, *adp;
591
int bit = 0, isad = 1, err = AFP_OK;
593
u_char achar, *fdType, xyy[4];
594
u_int16_t ashort, bshort;
598
int change_mdate = 0;
599
int change_parent_mdate = 0;
605
LOG(log_info, logtype_afpd, "begin setfilparams:");
608
upath = mtoupath(vol, path);
609
if ((of = of_findname(upath, NULL))) {
612
memset(&ad, 0, sizeof(ad));
616
if (check_access(upath, OPENACC_WR ) < 0) {
617
return AFPERR_ACCESS;
620
if (ad_open( upath, vol_noadouble(vol) | ADFLAGS_HF,
621
O_RDWR|O_CREAT, 0666, adp) < 0) {
622
/* for some things, we don't need an adouble header */
623
if (bitmap & ~(1<<FILPBIT_MDATE)) {
624
return vol_noadouble(vol) ? AFP_OK : AFPERR_ACCESS;
627
} else if ((ad_getoflags( adp, ADFLAGS_HF ) & O_CREAT) ) {
628
ad_setentrylen( adp, ADEID_NAME, strlen( path ));
629
memcpy(ad_entry( adp, ADEID_NAME ), path,
630
ad_getentrylen( adp, ADEID_NAME ));
633
while ( bitmap != 0 ) {
634
while (( bitmap & 1 ) == 0 ) {
642
memcpy(&ashort, buf, sizeof( ashort ));
643
ad_getattr(adp, &bshort);
644
if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
645
bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
649
if ((ashort & htons(ATTRBIT_INVISIBLE)))
650
change_parent_mdate = 1;
651
ad_setattr(adp, bshort);
652
buf += sizeof( ashort );
657
memcpy(&aint, buf, sizeof(aint));
658
ad_setdate(adp, AD_DATE_CREATE, aint);
659
buf += sizeof( aint );
663
memcpy(&newdate, buf, sizeof( newdate ));
664
buf += sizeof( newdate );
669
memcpy(&aint, buf, sizeof(aint));
670
ad_setdate(adp, AD_DATE_BACKUP, aint);
671
buf += sizeof( aint );
677
if (!memcmp( ad_entry( adp, ADEID_FINDERI ), ufinderi, 8 )
679
((em = getextmap( path )) &&
680
!memcmp(buf, em->em_type, sizeof( em->em_type )) &&
681
!memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
682
|| ((em = getdefextmap()) &&
683
!memcmp(buf, em->em_type, sizeof( em->em_type )) &&
684
!memcmp(buf + 4, em->em_creator,sizeof( em->em_creator)))
686
memcpy(buf, ufinderi, 8 );
689
memcpy(ad_entry( adp, ADEID_FINDERI ), buf, 32 );
693
/* Client needs to set the ProDOS file info for this file.
694
Use defined strings for the simple cases, and convert
695
all else into pXYY per Inside Appletalk. Always set
696
the creator as "pdos". <shirsch@ibm.net> */
697
case FILPBIT_PDINFO :
700
memcpy(&ashort, buf, sizeof( ashort ));
701
ashort = ntohs( ashort );
704
switch ( (unsigned int) achar )
707
fdType = ( u_char *) "TEXT";
711
fdType = ( u_char *) "PSYS";
715
fdType = ( u_char *) "PS16";
719
fdType = ( u_char *) "BINA";
723
xyy[0] = ( u_char ) 'p';
725
xyy[2] = ( u_char ) ( ashort >> 8 ) & 0xff;
726
xyy[3] = ( u_char ) ashort & 0xff;
731
memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 );
732
memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 );
738
goto setfilparam_done;
746
if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
747
newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
751
ad_setdate(adp, AD_DATE_MODIFY, newdate);
752
ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
757
ad_flush( adp, ADFLAGS_HF );
758
ad_close( adp, ADFLAGS_HF );
762
if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
763
newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
764
bitmap = 1<<FILPBIT_MDATE;
765
setdirparams(vol, "", bitmap, (char *)&newdate);
769
LOG(log_info, logtype_afpd, "end setfilparams:");
775
* renamefile and copyfile take the old and new unix pathnames
776
* and the new mac name.
777
* NOTE: if we have to copy a file instead of renaming it, locks
778
* will break. Anyway it's an error because then we have 2 files.
780
* src the source path
781
* dst the dest filename in current dir
782
* newname the dest mac name
783
* adp adouble struct of src file, if open, or & zeroed one
786
int renamefile(src, dst, newname, noadouble, adp )
787
char *src, *dst, *newname;
791
char adsrc[ MAXPATHLEN + 1];
795
* Note that this is only checking the existance of the data file,
796
* not the header file. The thinking is that if the data file doesn't
797
* exist, but the header file does, the right thing to do is remove
798
* the data file silently.
801
/* existence check moved to afp_moveandrename */
804
LOG(log_info, logtype_afpd, "begin renamefile:");
807
if ( rename( src, dst ) < 0 ) {
810
return( AFPERR_NOOBJ );
813
return( AFPERR_ACCESS );
816
case EXDEV : /* Cross device move -- try copy */
817
if (( rc = copyfile(src, dst, newname, noadouble )) != AFP_OK ) {
818
deletefile( dst, 0 );
821
return deletefile( src, 0);
823
return( AFPERR_PARAM );
827
strcpy( adsrc, ad_path( src, 0 ));
830
if (rename( adsrc, ad_path( dst, 0 )) < 0 ) {
835
/* check for a source appledouble header. if it exists, make
836
* a dest appledouble directory and do the rename again. */
837
if (rc || stat(adsrc, &st) ||
838
(ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, adp) < 0))
841
ad_close(adp, ADFLAGS_HF);
845
return( AFPERR_ACCESS );
849
return( AFPERR_PARAM );
853
if ( ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp) < 0 ) {
856
return( AFPERR_NOOBJ );
858
return( AFPERR_ACCESS );
862
return( AFPERR_PARAM );
866
len = strlen( newname );
867
ad_setentrylen( adp, ADEID_NAME, len );
868
memcpy(ad_entry( adp, ADEID_NAME ), newname, len );
869
ad_flush( adp, ADFLAGS_HF );
870
ad_close( adp, ADFLAGS_HF );
873
LOG(log_info, logtype_afpd, "end renamefile:");
879
int afp_copyfile(obj, ibuf, ibuflen, rbuf, rbuflen )
882
int ibuflen, *rbuflen;
886
char *newname, *path, *p, *upath;
887
u_int32_t sdid, ddid;
888
int plen, err, retvalue = AFP_OK;
889
u_int16_t svid, dvid;
892
LOG(log_info, logtype_afpd, "begin afp_copyfile:");
898
memcpy(&svid, ibuf, sizeof( svid ));
899
ibuf += sizeof( svid );
900
if (( vol = getvolbyvid( svid )) == NULL ) {
901
return( AFPERR_PARAM );
904
memcpy(&sdid, ibuf, sizeof( sdid ));
905
ibuf += sizeof( sdid );
906
if (( dir = dirlookup( vol, sdid )) == NULL ) {
907
return( AFPERR_PARAM );
910
memcpy(&dvid, ibuf, sizeof( dvid ));
911
ibuf += sizeof( dvid );
912
memcpy(&ddid, ibuf, sizeof( ddid ));
913
ibuf += sizeof( ddid );
915
if (( path = cname( vol, dir, &ibuf )) == NULL ) {
916
return( AFPERR_NOOBJ );
918
if ( *path == '\0' ) {
919
return( AFPERR_BADTYPE );
922
/* don't allow copies when the file is open.
923
* XXX: the spec only calls for read/deny write access.
924
* however, copyfile doesn't have any of that info,
925
* and locks need to stay coherent. as a result,
926
* we just balk if the file is opened already. */
928
newname = obj->newtmp;
929
strcpy( newname, path );
931
upath = mtoupath(vol, newname );
932
if (of_findname(upath, NULL))
933
return AFPERR_DENYCONF;
935
p = ctoupath( vol, curdir, newname );
937
/* FIXME svid != dvid && dvid's user can't read svid */
939
if (( vol = getvolbyvid( dvid )) == NULL ) {
940
return( AFPERR_PARAM );
943
if (vol->v_flags & AFPVOL_RO)
946
if (( dir = dirlookup( vol, ddid )) == NULL ) {
947
return( AFPERR_PARAM );
950
if (( path = cname( vol, dir, &ibuf )) == NULL ) {
951
return( AFPERR_NOOBJ );
953
if ( *path != '\0' ) {
954
return( AFPERR_BADTYPE ); /* not a directory. AFPERR_PARAM? */
957
/* one of the handful of places that knows about the path type */
958
if ( *ibuf++ != 2 ) {
959
return( AFPERR_PARAM );
961
if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
962
strncpy( newname, ibuf, plen );
963
newname[ plen ] = '\0';
964
if (strlen(newname) != plen) {
965
/* there's \0 in newname, e.g. it's a pathname not
968
return( AFPERR_PARAM );
971
upath = mtoupath(vol, newname);
972
if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) {
977
if (vol->v_flags & AFPVOL_DROPBOX) {
978
retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
980
#endif /* DROPKLUDGE */
982
setvoltime(obj, vol );
985
LOG(log_info, logtype_afpd, "end afp_copyfile:");
992
static __inline__ int copy_all(const int dfd, const void *buf,
998
LOG(log_info, logtype_afpd, "begin copy_all:");
1001
while (buflen > 0) {
1002
if ((cc = write(dfd, buf, buflen)) < 0) {
1009
return AFPERR_DFULL;
1011
return AFPERR_VLOCK;
1013
return AFPERR_PARAM;
1020
LOG(log_info, logtype_afpd, "end copy_all:");
1026
/* XXX: this needs to use ad_open and ad_lock. so, we need to
1027
* pass in vol and path */
1028
int copyfile(src, dst, newname, noadouble )
1029
char *src, *dst, *newname;
1030
const int noadouble;
1035
int sfd, dfd, len, err = AFP_OK;
1037
char dpath[ MAXPATHLEN + 1];
1040
LOG(log_info, logtype_afpd, "begin copyfile:");
1043
strcpy(dpath, ad_path( dst, ADFLAGS_HF ));
1044
admode = ad_mode( dst, 0666 );
1046
if ((sfd = open( ad_path( src, ADFLAGS_HF ), O_RDONLY, 0 )) < 0 ) {
1049
break; /* just copy the data fork */
1051
return( AFPERR_ACCESS );
1053
return( AFPERR_PARAM );
1056
if (( dfd = open( dpath, O_WRONLY|O_CREAT,ad_hf_mode(admode))) < 0 ) {
1060
return( AFPERR_NOOBJ );
1062
return( AFPERR_ACCESS );
1064
return AFPERR_VLOCK;
1066
return( AFPERR_PARAM );
1071
#ifdef SENDFILE_FLAVOR_LINUX
1072
if (fstat(sfd, &st) == 0) {
1073
if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1087
goto copyheader_done;
1089
#endif /* SENDFILE_FLAVOR_LINUX */
1091
if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) {
1098
if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0))
1112
/* data fork copying */
1113
if (( sfd = open( src, O_RDONLY, 0 )) < 0 ) {
1116
return( AFPERR_NOOBJ );
1118
return( AFPERR_ACCESS );
1120
return( AFPERR_PARAM );
1124
if (( dfd = open( dst, O_WRONLY|O_CREAT, admode)) < 0 ) {
1128
return( AFPERR_NOOBJ );
1130
return( AFPERR_ACCESS );
1132
return AFPERR_VLOCK;
1134
return( AFPERR_PARAM );
1138
#ifdef SENDFILE_FLAVOR_LINUX
1139
if (fstat(sfd, &st) == 0) {
1140
if ((cc = sendfile(dfd, sfd, NULL, st.st_size)) < 0) {
1153
#endif /* SENDFILE_FLAVOR_LINUX */
1156
if ((cc = read( sfd, filebuf, sizeof( filebuf ))) < 0) {
1164
if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) {
1179
memset(&ad, 0, sizeof(ad));
1180
if ( ad_open( dst, noadouble | ADFLAGS_HF, O_RDWR|O_CREAT,
1184
return noadouble ? AFP_OK : AFPERR_NOOBJ;
1186
return( AFPERR_ACCESS );
1188
return AFPERR_VLOCK;
1190
return( AFPERR_PARAM );
1194
len = strlen( newname );
1195
ad_setentrylen( &ad, ADEID_NAME, len );
1196
memcpy(ad_entry( &ad, ADEID_NAME ), newname, len );
1197
ad_flush( &ad, ADFLAGS_HF );
1198
ad_close( &ad, ADFLAGS_HF );
1202
LOG(log_info, logtype_afpd, "end copyfile:");
1209
/* -----------------------------------
1210
checkAttrib: 1 check kFPDeleteInhibitBit
1211
ie deletfile called by afp_delete
1213
when deletefile is called we don't have lock on it, file is closed (for us)
1214
untrue if called by renamefile
1216
int deletefile( file, checkAttrib )
1221
int adflags, err = AFP_OK;
1222
int locktype = ADLOCK_WR;
1223
int openmode = O_RDWR;
1226
LOG(log_info, logtype_afpd, "begin deletefile:");
1231
* If can't open read/write then try again read-only. If it's open
1232
* read-only, we must do a read lock instead of a write lock.
1234
/* try to open both at once */
1235
adflags = ADFLAGS_DF|ADFLAGS_HF;
1236
memset(&ad, 0, sizeof(ad));
1237
if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1240
adflags = ADFLAGS_DF;
1241
/* that failed. now try to open just the data fork */
1242
memset(&ad, 0, sizeof(ad));
1243
if ( ad_open( file, adflags, openmode, 0, &ad ) < 0 ) {
1246
return AFPERR_NOOBJ;
1248
if(openmode == O_RDWR) {
1249
openmode = O_RDONLY;
1250
locktype = ADLOCK_RD;
1253
return AFPERR_ACCESS;
1256
return AFPERR_VLOCK;
1258
return AFPERR_PARAM;
1264
if(openmode == O_RDWR) {
1265
openmode = O_RDONLY;
1266
locktype = ADLOCK_RD;
1269
return AFPERR_ACCESS;
1272
return AFPERR_VLOCK;
1274
return( AFPERR_PARAM );
1277
break; /* from the while */
1280
* Does kFPDeleteInhibitBit (bit 8) set?
1282
if (checkAttrib && (adflags & ADFLAGS_HF)) {
1285
ad_getattr(&ad, &bshort);
1286
if ((bshort & htons(ATTRBIT_NODELETE))) {
1287
ad_close( &ad, adflags );
1288
return(AFPERR_OLOCK);
1292
if ((adflags & ADFLAGS_HF) ) {
1293
/* FIXME we have a pb here because we want to know if a file is open
1294
* there's a 'priority inversion' if you can't open the ressource fork RW
1295
* you can delete it if it's open because you can't get a write lock.
1297
* ADLOCK_FILELOCK means the whole ressource fork, not only after the
1300
* FIXME it doesn't for RFORK open read only and fork open without deny mode
1302
if (ad_tmplock(&ad, ADEID_RFORK, locktype |ADLOCK_FILELOCK, 0, 0) < 0 ) {
1303
ad_close( &ad, adflags );
1304
return( AFPERR_BUSY );
1308
if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0 ) < 0) {
1313
if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
1317
err = AFPERR_ACCESS;
1330
if ( unlink( file ) < 0 ) {
1334
err = AFPERR_ACCESS;
1348
if (adflags & ADFLAGS_HF)
1349
ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0);
1350
ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0);
1351
ad_close( &ad, adflags );
1354
LOG(log_info, logtype_afpd, "end deletefile:");
1362
/* return a file id */
1363
int afp_createid(obj, ibuf, ibuflen, rbuf, rbuflen )
1366
int ibuflen, *rbuflen;
1369
#if AD_VERSION > AD_VERSION1
1380
LOG(log_info, logtype_afpd, "begin afp_createid:");
1386
memcpy(&vid, ibuf, sizeof(vid));
1387
ibuf += sizeof(vid);
1389
if (( vol = getvolbyvid( vid )) == NULL ) {
1390
return( AFPERR_PARAM);
1393
if (vol->v_flags & AFPVOL_RO)
1394
return AFPERR_VLOCK;
1396
memcpy(&did, ibuf, sizeof( did ));
1397
ibuf += sizeof(did);
1399
if (( dir = dirlookup( vol, did )) == NULL ) {
1400
return( AFPERR_PARAM );
1403
if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1404
return( AFPERR_PARAM );
1407
if ( *path == '\0' ) {
1408
return( AFPERR_BADTYPE );
1411
upath = mtoupath(vol, path);
1412
if (stat(upath, &st) < 0) {
1416
return AFPERR_ACCESS;
1418
return AFPERR_NOOBJ;
1420
return AFPERR_PARAM;
1424
if ((id = cnid_lookup(vol->v_db, &st, did, upath, len = strlen(upath)))) {
1425
memcpy(rbuf, &id, sizeof(id));
1426
*rbuflen = sizeof(id);
1427
return AFPERR_EXISTID;
1430
#if AD_VERSION > AD_VERSION1
1431
memset(&ad, 0, sizeof(ad));
1432
if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) {
1433
memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id));
1434
ad_close(&ad, ADFLAGS_HF);
1436
#endif /* AD_VERSION > AD_VERSION1 */
1438
if ((id = cnid_add(vol->v_db, &st, did, upath, len, id)) != CNID_INVALID) {
1439
memcpy(rbuf, &id, sizeof(id));
1440
*rbuflen = sizeof(id);
1445
LOG(log_info, logtype_afpd, "ending afp_createid...:");
1450
return AFPERR_VLOCK;
1454
return AFPERR_ACCESS;
1457
LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno));
1458
return AFPERR_PARAM;
1462
/* resolve a file id */
1463
int afp_resolveid(obj, ibuf, ibuflen, rbuf, rbuflen )
1466
int ibuflen, *rbuflen;
1474
u_int16_t vid, bitmap;
1476
static char buffer[12 + MAXPATHLEN + 1];
1477
int len = 12 + MAXPATHLEN + 1;
1480
LOG(log_info, logtype_afpd, "begin afp_resolveid:");
1486
memcpy(&vid, ibuf, sizeof(vid));
1487
ibuf += sizeof(vid);
1489
if (( vol = getvolbyvid( vid )) == NULL ) {
1490
return( AFPERR_PARAM);
1493
memcpy(&id, ibuf, sizeof( id ));
1496
if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1497
return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */
1500
if (( dir = dirlookup( vol, id )) == NULL ) {
1501
return AFPERR_NOID; /* idem AFPERR_PARAM */
1504
if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1508
return AFPERR_ACCESS;
1512
return AFPERR_PARAM;
1516
/* directories are bad */
1517
if (S_ISDIR(st.st_mode))
1518
return AFPERR_BADTYPE;
1520
memcpy(&bitmap, ibuf, sizeof(bitmap));
1521
bitmap = ntohs( bitmap );
1523
if ((err = getfilparams(vol, bitmap, utompath(vol, upath), curdir, &st,
1524
rbuf + sizeof(bitmap), &buflen)) != AFP_OK)
1527
*rbuflen = buflen + sizeof(bitmap);
1528
memcpy(rbuf, ibuf, sizeof(bitmap));
1531
LOG(log_info, logtype_afpd, "end afp_resolveid:");
1537
int afp_deleteid(obj, ibuf, ibuflen, rbuf, rbuflen )
1540
int ibuflen, *rbuflen;
1550
static char buffer[12 + MAXPATHLEN + 1];
1551
int len = 12 + MAXPATHLEN + 1;
1554
LOG(log_info, logtype_afpd, "begin afp_deleteid:");
1560
memcpy(&vid, ibuf, sizeof(vid));
1561
ibuf += sizeof(vid);
1563
if (( vol = getvolbyvid( vid )) == NULL ) {
1564
return( AFPERR_PARAM);
1567
if (vol->v_flags & AFPVOL_RO)
1568
return AFPERR_VLOCK;
1570
memcpy(&id, ibuf, sizeof( id ));
1574
if ((upath = cnid_resolve(vol->v_db, &id, buffer, len)) == NULL) {
1578
if (( dir = dirlookup( vol, id )) == NULL ) {
1579
return( AFPERR_PARAM );
1583
if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) {
1587
return AFPERR_ACCESS;
1589
/* still try to delete the id */
1593
return AFPERR_PARAM;
1597
/* directories are bad */
1598
if (S_ISDIR(st.st_mode))
1599
return AFPERR_BADTYPE;
1601
if (cnid_delete(vol->v_db, fileid)) {
1604
return AFPERR_VLOCK;
1607
return AFPERR_ACCESS;
1609
return AFPERR_PARAM;
1614
LOG(log_info, logtype_afpd, "end afp_deleteid:");
1619
#endif /* CNID_DB */
1621
#define APPLETEMP ".AppleTempXXXXXX"
1623
int afp_exchangefiles(obj, ibuf, ibuflen, rbuf, rbuflen )
1626
int ibuflen, *rbuflen;
1628
struct stat srcst, destst;
1630
struct dir *dir, *sdir;
1631
char *spath, temp[17], *path, *p;
1632
char *supath, *upath;
1636
struct adouble *adsp;
1637
struct adouble *addp;
1643
#endif /* CNID_DB */
1648
LOG(log_info, logtype_afpd, "begin afp_exchangefiles:");
1654
memcpy(&vid, ibuf, sizeof(vid));
1655
ibuf += sizeof(vid);
1657
if (( vol = getvolbyvid( vid )) == NULL ) {
1658
return( AFPERR_PARAM);
1661
if (vol->v_flags & AFPVOL_RO)
1662
return AFPERR_VLOCK;
1664
/* source and destination dids */
1665
memcpy(&sid, ibuf, sizeof(sid));
1666
ibuf += sizeof(sid);
1667
memcpy(&did, ibuf, sizeof(did));
1668
ibuf += sizeof(did);
1671
if ((dir = dirlookup( vol, sid )) == NULL ) {
1672
return( AFPERR_PARAM );
1675
if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1676
return( AFPERR_PARAM );
1679
if ( *path == '\0' ) {
1680
return( AFPERR_BADTYPE ); /* it's a dir */
1683
upath = mtoupath(vol, path);
1684
if (stat(upath, &srcst) < 0) {
1690
return AFPERR_ACCESS;
1692
return AFPERR_PARAM;
1695
memset(&ads, 0, sizeof(ads));
1697
if ((s_of = of_findname(upath, &srcst))) {
1698
/* reuse struct adouble so it won't break locks */
1701
/* save some stuff */
1703
spath = obj->oldtmp;
1704
supath = obj->newtmp;
1705
strcpy(spath, path);
1706
strcpy(supath, upath); /* this is for the cnid changing */
1707
p = ctoupath( vol, sdir, spath);
1709
/* look for the source cnid. if it doesn't exist, don't worry about
1712
sid = cnid_lookup(vol->v_db, &srcst, sdir->d_did, supath,
1713
slen = strlen(supath));
1714
#endif /* CNID_DB */
1716
if (( dir = dirlookup( vol, did )) == NULL ) {
1717
return( AFPERR_PARAM );
1720
if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1721
return( AFPERR_PARAM );
1724
if ( *path == '\0' ) {
1725
return( AFPERR_BADTYPE );
1728
/* FPExchangeFiles is the only call that can return the SameObj
1730
if ((curdir == sdir) && strcmp(spath, path) == 0)
1731
return AFPERR_SAMEOBJ;
1733
upath = mtoupath(vol, path);
1734
if (stat(upath, &destst) < 0) {
1740
return AFPERR_ACCESS;
1742
return AFPERR_PARAM;
1745
memset(&add, 0, sizeof(add));
1747
if ((d_of = of_findname( upath, &destst))) {
1748
/* reuse struct adouble so it won't break locks */
1752
/* they are not on the same device and at least one is open
1754
if ((d_of || s_of) && srcst.st_dev != destst.st_dev)
1758
/* look for destination id. */
1759
did = cnid_lookup(vol->v_db, &destst, curdir->d_did, upath,
1760
dlen = strlen(upath));
1761
#endif /* CNID_DB */
1763
/* construct a temp name.
1764
* NOTE: the temp file will be in the dest file's directory. it
1765
* will also be inaccessible from AFP. */
1766
memcpy(temp, APPLETEMP, sizeof(APPLETEMP));
1770
/* now, quickly rename the file. we error if we can't. */
1771
if ((err = renamefile(p, temp, temp, vol_noadouble(vol), adsp)) < 0)
1772
goto err_exchangefile;
1773
of_rename(vol, s_of, sdir, spath, curdir, temp);
1775
/* rename destination to source */
1776
if ((err = renamefile(upath, p, spath, vol_noadouble(vol), addp)) < 0)
1777
goto err_src_to_tmp;
1778
of_rename(vol, d_of, curdir, path, sdir, spath);
1780
/* rename temp to destination */
1781
if ((err = renamefile(temp, upath, path, vol_noadouble(vol), adsp)) < 0)
1782
goto err_dest_to_src;
1783
of_rename(vol, s_of, curdir, temp, curdir, path);
1786
/* id's need switching. src -> dest and dest -> src. */
1787
if (sid && (cnid_update(vol->v_db, sid, &destst, curdir->d_did,
1788
upath, dlen) < 0)) {
1792
err = AFPERR_ACCESS;
1797
goto err_temp_to_dest;
1800
if (did && (cnid_update(vol->v_db, did, &srcst, sdir->d_did,
1801
supath, slen) < 0)) {
1805
err = AFPERR_ACCESS;
1812
cnid_update(vol->v_db, sid, &srcst, sdir->d_did, supath, slen);
1813
goto err_temp_to_dest;
1815
#endif /* CNID_DB */
1818
LOG(log_info, logtype_afpd, "ending afp_exchangefiles:");
1824
/* all this stuff is so that we can unwind a failed operation
1829
/* rename dest to temp */
1830
renamefile(upath, temp, temp, vol_noadouble(vol), adsp);
1831
of_rename(vol, s_of, curdir, upath, curdir, temp);
1834
/* rename source back to dest */
1835
renamefile(p, upath, path, vol_noadouble(vol), addp);
1836
of_rename(vol, d_of, sdir, spath, curdir, path);
1839
/* rename temp back to source */
1840
renamefile(temp, p, spath, vol_noadouble(vol), adsp);
1841
of_rename(vol, s_of, curdir, temp, sdir, spath);