Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F120840273
dlist.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
14 KB
Referenced Files
None
Subscribers
None
dlist.c
View Options
/* dlist.c - list protocol for dump and sync
*
* Copyright (c) 1994-2008 Carnegie Mellon University. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The name "Carnegie Mellon University" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For permission or any legal
* details, please contact
* Carnegie Mellon University
* Center for Technology Transfer and Enterprise Creation
* 4615 Forbes Avenue
* Suite 302
* Pittsburgh, PA 15213
* (412) 268-7393, fax: (412) 268-7395
* innovation@andrew.cmu.edu
*
* 4. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Computing Services
* at Carnegie Mellon University (http://www.cmu.edu/computing/)."
*
* CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: sync_support.c,v 1.25 2010/01/06 17:01:41 murch Exp $
*/
#include
<config.h>
#ifdef HAVE_UNISTD_H
#include
<unistd.h>
#endif
#include
<stdlib.h>
#include
<stdio.h>
#include
<time.h>
#include
<sys/stat.h>
#include
<sys/types.h>
#include
<fcntl.h>
#include
<syslog.h>
#include
<string.h>
#include
<sys/wait.h>
#include
<errno.h>
#include
<ctype.h>
#include
<dirent.h>
#include
<utime.h>
#include
"global.h"
#include
"assert.h"
#include
"mboxlist.h"
#include
"exitcodes.h"
#include
"imap_err.h"
#include
"mailbox.h"
#include
"quota.h"
#include
"xmalloc.h"
#include
"xstrlcat.h"
#include
"xstrlcpy.h"
#include
"acl.h"
#include
"seen.h"
#include
"mboxname.h"
#include
"map.h"
#include
"imapd.h"
#include
"imparse.h"
#include
"message.h"
#include
"util.h"
#include
"retry.h"
#include
"cyr_lock.h"
#include
"prot.h"
#include
"dlist.h"
/* Parse routines */
const
char
*
lastkey
=
NULL
;
static
void
printfile
(
struct
protstream
*
out
,
struct
dlist
*
dl
)
{
char
buf
[
4096
];
struct
stat
sbuf
;
FILE
*
f
;
unsigned
long
size
;
f
=
fopen
(
dl
->
sval
,
"r"
);
if
(
!
f
)
{
syslog
(
LOG_ERR
,
"IOERROR: Failed to read file %s"
,
dl
->
sval
);
prot_printf
(
out
,
"NIL"
);
return
;
}
if
(
fstat
(
fileno
(
f
),
&
sbuf
)
==
-1
)
{
syslog
(
LOG_ERR
,
"IOERROR: Failed to stat file %s"
,
dl
->
sval
);
prot_printf
(
out
,
"NIL"
);
fclose
(
f
);
return
;
}
size
=
sbuf
.
st_size
;
if
(
size
!=
dl
->
nval
)
{
syslog
(
LOG_ERR
,
"IOERROR: Size mismatch %s (%lu != "
MODSEQ_FMT
")"
,
dl
->
sval
,
size
,
dl
->
nval
);
prot_printf
(
out
,
"NIL"
);
fclose
(
f
);
return
;
}
prot_printf
(
out
,
"%%{"
);
prot_printastring
(
out
,
dl
->
part
);
prot_printf
(
out
,
" "
);
prot_printastring
(
out
,
message_guid_encode
(
&
dl
->
gval
));
prot_printf
(
out
,
" %lu}
\r\n
"
,
size
);
while
(
size
)
{
int
n
=
fread
(
buf
,
1
,
(
size
>
4096
?
4096
:
size
),
f
);
if
(
n
<=
0
)
break
;
prot_write
(
out
,
buf
,
n
);
size
-=
n
;
}
fclose
(
f
);
if
(
size
)
fatal
(
"failed to finish reading file!"
,
EC_IOERR
);
}
/* XXX - these two functions should be out in append.c or reserve.c
* or something more general */
const
char
*
dlist_reserve_path
(
const
char
*
part
,
struct
message_guid
*
guid
)
{
static
char
buf
[
MAX_MAILBOX_PATH
];
snprintf
(
buf
,
MAX_MAILBOX_PATH
,
"%s/sync./%lu/%s"
,
config_partitiondir
(
part
),
(
unsigned
long
)
getpid
(),
message_guid_encode
(
guid
));
cyrus_mkdir
(
buf
,
0755
);
return
buf
;
}
static
int
reservefile
(
struct
protstream
*
in
,
const
char
*
part
,
struct
message_guid
*
guid
,
unsigned
long
size
,
const
char
**
fname
)
{
FILE
*
file
;
char
buf
[
8192
+
1
];
int
r
=
0
,
n
;
/* XXX - write to a temporary file then move in to place! */
*
fname
=
dlist_reserve_path
(
part
,
guid
);
file
=
fopen
(
*
fname
,
"w+"
);
if
(
!
file
)
{
syslog
(
LOG_ERR
,
"Failed to upload file %s"
,
message_guid_encode
(
guid
));
r
=
IMAP_IOERROR
;
}
/* XXX - calculate sha1 on the fly? */
while
(
size
)
{
n
=
prot_read
(
in
,
buf
,
size
>
8192
?
8192
:
size
);
if
(
!
n
)
{
syslog
(
LOG_ERR
,
"IOERROR: reading message: unexpected end of file"
);
r
=
IMAP_IOERROR
;
break
;
}
size
-=
n
;
if
(
!
r
)
fwrite
(
buf
,
1
,
n
,
file
);
}
if
(
r
)
return
r
;
/* Make sure that message flushed to disk just incase mmap has problems */
fflush
(
file
);
if
(
ferror
(
file
))
{
fclose
(
file
);
return
IMAP_IOERROR
;
}
if
(
fsync
(
fileno
(
file
))
<
0
)
{
fclose
(
file
);
return
IMAP_IOERROR
;
}
fclose
(
file
);
return
0
;
}
/* DLIST STUFF */
void
dlist_stitch
(
struct
dlist
*
dl
,
struct
dlist
*
child
)
{
if
(
dl
->
tail
)
dl
->
tail
=
dl
->
tail
->
next
=
child
;
else
dl
->
head
=
dl
->
tail
=
child
;
}
static
struct
dlist
*
dlist_child
(
struct
dlist
*
dl
,
const
char
*
name
)
{
struct
dlist
*
i
=
xzmalloc
(
sizeof
(
struct
dlist
));
i
->
name
=
xstrdup
(
name
);
i
->
type
=
DL_NIL
;
if
(
dl
)
dlist_stitch
(
dl
,
i
);
return
i
;
}
struct
dlist
*
dlist_atom
(
struct
dlist
*
dl
,
const
char
*
name
,
const
char
*
val
)
{
struct
dlist
*
i
=
dlist_child
(
dl
,
name
);
i
->
type
=
DL_ATOM
;
i
->
sval
=
xstrdup
(
val
);
return
i
;
}
struct
dlist
*
dlist_flag
(
struct
dlist
*
dl
,
const
char
*
name
,
const
char
*
val
)
{
struct
dlist
*
i
=
dlist_child
(
dl
,
name
);
i
->
type
=
DL_FLAG
;
i
->
sval
=
xstrdup
(
val
);
return
i
;
}
struct
dlist
*
dlist_num
(
struct
dlist
*
dl
,
const
char
*
name
,
unsigned
long
val
)
{
struct
dlist
*
i
=
dlist_child
(
dl
,
name
);
i
->
type
=
DL_NUM
;
i
->
nval
=
(
modseq_t
)
val
;
return
i
;
}
struct
dlist
*
dlist_date
(
struct
dlist
*
dl
,
const
char
*
name
,
time_t
val
)
{
struct
dlist
*
i
=
dlist_child
(
dl
,
name
);
i
->
type
=
DL_DATE
;
i
->
nval
=
(
modseq_t
)
val
;
return
i
;
}
struct
dlist
*
dlist_modseq
(
struct
dlist
*
dl
,
const
char
*
name
,
modseq_t
val
)
{
struct
dlist
*
i
=
dlist_child
(
dl
,
name
);
i
->
type
=
DL_MODSEQ
;
i
->
nval
=
val
;
return
i
;
}
struct
dlist
*
dlist_guid
(
struct
dlist
*
dl
,
const
char
*
name
,
struct
message_guid
*
guid
)
{
struct
dlist
*
i
=
dlist_child
(
dl
,
name
);
i
->
type
=
DL_GUID
,
message_guid_copy
(
&
i
->
gval
,
guid
);
return
i
;
}
struct
dlist
*
dlist_file
(
struct
dlist
*
dl
,
const
char
*
name
,
const
char
*
part
,
struct
message_guid
*
guid
,
unsigned
long
size
,
const
char
*
fname
)
{
struct
dlist
*
i
=
dlist_child
(
dl
,
name
);
i
->
type
=
DL_FILE
;
message_guid_copy
(
&
i
->
gval
,
guid
);
i
->
sval
=
xstrdup
(
fname
);
i
->
nval
=
size
;
i
->
part
=
xstrdup
(
part
);
return
i
;
}
struct
dlist
*
dlist_buf
(
struct
dlist
*
dl
,
const
char
*
name
,
char
*
val
,
size_t
len
)
{
struct
dlist
*
i
=
dlist_child
(
dl
,
name
);
i
->
type
=
DL_BUF
;
i
->
sval
=
xmalloc
(
len
+
1
);
memcpy
(
i
->
sval
,
val
,
len
);
i
->
sval
[
len
]
=
'\0'
;
/* make it string safe too */
i
->
nval
=
len
;
return
i
;
}
struct
dlist
*
dlist_kvlist
(
struct
dlist
*
dl
,
const
char
*
name
)
{
struct
dlist
*
i
=
dlist_child
(
dl
,
name
);
i
->
type
=
DL_KVLIST
;
return
i
;
}
struct
dlist
*
dlist_list
(
struct
dlist
*
dl
,
const
char
*
name
)
{
struct
dlist
*
i
=
dlist_child
(
dl
,
name
);
i
->
type
=
DL_ATOMLIST
;
return
i
;
}
struct
dlist
*
dlist_new
(
const
char
*
name
)
{
return
dlist_kvlist
(
NULL
,
name
);
}
void
dlist_print_helper
(
struct
dlist
*
dl
,
int
printkeys
,
struct
protstream
*
out
,
int
level
)
{
struct
dlist
*
di
;
int
i
;
if
(
printkeys
)
prot_printf
(
out
,
"%s "
,
dl
->
name
);
switch
(
dl
->
type
)
{
case
DL_ATOM
:
prot_printastring
(
out
,
dl
->
sval
);
break
;
case
DL_FLAG
:
prot_printf
(
out
,
"%s"
,
dl
->
sval
);
break
;
case
DL_NUM
:
case
DL_DATE
:
/* for now, we will format it later */
case
DL_MODSEQ
:
prot_printf
(
out
,
MODSEQ_FMT
,
dl
->
nval
);
break
;
case
DL_FILE
:
printfile
(
out
,
dl
);
break
;
case
DL_BUF
:
prot_printliteral
(
out
,
dl
->
sval
,
dl
->
nval
);
break
;
case
DL_KVLIST
:
if
(
level
)
{
prot_printf
(
out
,
"
\r\n
"
);
for
(
i
=
0
;
i
<=
level
;
i
++
)
prot_printf
(
out
,
" "
);
}
prot_printf
(
out
,
"%%("
);
for
(
di
=
dl
->
head
;
di
;
di
=
di
->
next
)
{
dlist_print_helper
(
di
,
1
,
out
,
level
);
if
(
di
->
next
)
{
prot_printf
(
out
,
" "
);
}
}
prot_printf
(
out
,
")"
);
break
;
case
DL_ATOMLIST
:
prot_printf
(
out
,
"("
);
for
(
di
=
dl
->
head
;
di
;
di
=
di
->
next
)
{
dlist_print_helper
(
di
,
0
,
out
,
di
->
type
==
DL_KVLIST
?
level
+
1
:
level
);
if
(
di
->
next
)
prot_printf
(
out
,
" "
);
}
prot_printf
(
out
,
")"
);
break
;
}
}
void
dlist_print
(
struct
dlist
*
dl
,
int
printkeys
,
struct
protstream
*
out
)
{
dlist_print_helper
(
dl
,
printkeys
,
out
,
0
);
}
void
dlist_free
(
struct
dlist
**
dlp
)
{
struct
dlist
*
i
,
*
next
;
if
(
!*
dlp
)
return
;
i
=
(
*
dlp
)
->
head
;
while
(
i
)
{
free
(
i
->
name
);
next
=
i
->
next
;
switch
(
i
->
type
)
{
case
DL_KVLIST
:
case
DL_ATOMLIST
:
dlist_free
(
&
i
);
break
;
case
DL_FILE
:
free
(
i
->
part
);
/* drop through */
default
:
free
(
i
->
sval
);
}
free
(
i
);
i
=
next
;
}
free
(
*
dlp
);
*
dlp
=
NULL
;
}
static
char
next_nonspace
(
struct
protstream
*
in
,
char
c
)
{
while
(
Uisspace
(
c
))
{
c
=
prot_getc
(
in
);
}
return
c
;
}
char
dlist_parse
(
struct
dlist
**
dlp
,
int
parsekey
,
struct
protstream
*
in
)
{
struct
dlist
*
dl
=
NULL
;
static
struct
buf
kbuf
;
static
struct
buf
vbuf
;
char
c
;
/* handle the key if wanted */
if
(
parsekey
)
{
c
=
getword
(
in
,
&
kbuf
);
c
=
next_nonspace
(
in
,
c
);
}
else
{
buf_setcstr
(
&
kbuf
,
""
);
c
=
prot_getc
(
in
);
}
/* connection dropped? */
if
(
c
==
EOF
)
goto
fail
;
/* check what sort of value we have */
if
(
c
==
'('
)
{
dl
=
dlist_list
(
NULL
,
kbuf
.
s
);
c
=
next_nonspace
(
in
,
' '
);
while
(
c
!=
')'
)
{
struct
dlist
*
di
=
NULL
;
prot_ungetc
(
c
,
in
);
c
=
dlist_parse
(
&
di
,
0
,
in
);
if
(
di
)
dlist_stitch
(
dl
,
di
);
c
=
next_nonspace
(
in
,
c
);
if
(
c
==
EOF
)
goto
fail
;
}
c
=
prot_getc
(
in
);
}
else
if
(
c
==
'%'
)
{
/* no whitespace allowed here */
c
=
prot_getc
(
in
);
if
(
c
==
'('
)
{
dl
=
dlist_list
(
NULL
,
kbuf
.
s
);
c
=
next_nonspace
(
in
,
' '
);
while
(
c
!=
')'
)
{
struct
dlist
*
di
=
NULL
;
prot_ungetc
(
c
,
in
);
c
=
dlist_parse
(
&
di
,
1
,
in
);
if
(
di
)
dlist_stitch
(
dl
,
di
);
c
=
next_nonspace
(
in
,
c
);
if
(
c
==
EOF
)
goto
fail
;
}
}
else
if
(
c
==
'{'
)
{
struct
message_guid
tmp_guid
;
static
struct
buf
pbuf
,
gbuf
;
unsigned
size
=
0
;
const
char
*
fname
;
c
=
getastring
(
in
,
NULL
,
&
pbuf
);
if
(
c
!=
' '
)
goto
fail
;
c
=
getastring
(
in
,
NULL
,
&
gbuf
);
if
(
c
!=
' '
)
goto
fail
;
c
=
getuint32
(
in
,
&
size
);
if
(
c
!=
'}'
)
goto
fail
;
c
=
prot_getc
(
in
);
if
(
c
==
'\r'
)
c
=
prot_getc
(
in
);
if
(
c
!=
'\n'
)
goto
fail
;
if
(
!
message_guid_decode
(
&
tmp_guid
,
gbuf
.
s
))
goto
fail
;
if
(
reservefile
(
in
,
pbuf
.
s
,
&
tmp_guid
,
size
,
&
fname
))
goto
fail
;
dl
=
dlist_file
(
NULL
,
kbuf
.
s
,
pbuf
.
s
,
&
tmp_guid
,
size
,
fname
);
/* file literal */
}
else
{
/* unknown percent type */
goto
fail
;
}
c
=
prot_getc
(
in
);
}
else
if
(
c
==
'{'
)
{
prot_ungetc
(
c
,
in
);
/* could be binary in a literal */
c
=
getbastring
(
in
,
NULL
,
&
vbuf
);
dl
=
dlist_buf
(
NULL
,
kbuf
.
s
,
vbuf
.
s
,
vbuf
.
len
);
}
else
{
prot_ungetc
(
c
,
in
);
c
=
getastring
(
in
,
NULL
,
&
vbuf
);
dl
=
dlist_atom
(
NULL
,
kbuf
.
s
,
vbuf
.
s
);
if
(
imparse_isnumber
(
vbuf
.
s
))
dl
->
nval
=
atomodseq_t
(
vbuf
.
s
);
}
/* success */
*
dlp
=
dl
;
return
c
;
fail
:
dlist_free
(
&
dl
);
return
EOF
;
}
static
struct
dlist
*
dlist_getchild
(
struct
dlist
*
dl
,
const
char
*
name
)
{
struct
dlist
*
i
;
for
(
i
=
dl
->
head
;
i
;
i
=
i
->
next
)
{
if
(
!
strcmp
(
name
,
i
->
name
))
return
i
;
}
lastkey
=
name
;
return
NULL
;
}
/* XXX - type coercion logic here */
int
dlist_getatom
(
struct
dlist
*
dl
,
const
char
*
name
,
const
char
**
val
)
{
struct
dlist
*
i
=
dlist_getchild
(
dl
,
name
);
if
(
!
i
)
return
0
;
*
val
=
i
->
sval
;
return
1
;
}
int
dlist_getbuf
(
struct
dlist
*
dl
,
const
char
*
name
,
const
char
**
val
,
size_t
*
len
)
{
struct
dlist
*
i
=
dlist_getchild
(
dl
,
name
);
if
(
!
i
)
return
0
;
*
val
=
i
->
sval
;
*
len
=
(
size_t
)
i
->
nval
;
return
1
;
}
int
dlist_getnum
(
struct
dlist
*
dl
,
const
char
*
name
,
uint32_t
*
val
)
{
struct
dlist
*
i
=
dlist_getchild
(
dl
,
name
);
if
(
!
i
)
return
0
;
*
val
=
(
uint32_t
)
i
->
nval
;
return
1
;
}
int
dlist_getdate
(
struct
dlist
*
dl
,
const
char
*
name
,
time_t
*
val
)
{
struct
dlist
*
i
=
dlist_getchild
(
dl
,
name
);
if
(
!
i
)
return
0
;
/* XXX: string parse when the date format changes */
*
val
=
(
time_t
)
i
->
nval
;
return
1
;
}
int
dlist_getmodseq
(
struct
dlist
*
dl
,
const
char
*
name
,
modseq_t
*
val
)
{
struct
dlist
*
i
=
dlist_getchild
(
dl
,
name
);
if
(
!
i
)
return
0
;
*
val
=
(
modseq_t
)
i
->
nval
;
return
1
;
}
int
dlist_getguid
(
struct
dlist
*
dl
,
const
char
*
name
,
struct
message_guid
**
val
)
{
struct
dlist
*
i
=
dlist_getchild
(
dl
,
name
);
if
(
!
i
)
return
0
;
/* XXX - maybe malloc like strings? would save some in the general case */
if
(
!
message_guid_decode
(
&
i
->
gval
,
i
->
sval
))
return
0
;
*
val
=
&
i
->
gval
;
return
1
;
}
int
dlist_getfile
(
struct
dlist
*
dl
,
const
char
*
name
,
const
char
**
part
,
struct
message_guid
**
guid
,
unsigned
long
*
size
,
const
char
**
fname
)
{
struct
dlist
*
i
=
dlist_getchild
(
dl
,
name
);
if
(
!
i
)
return
0
;
if
(
!
message_guid_decode
(
&
i
->
gval
,
i
->
sval
))
return
0
;
*
guid
=
&
i
->
gval
;
*
size
=
i
->
nval
;
*
fname
=
i
->
sval
;
*
part
=
i
->
part
;
return
1
;
}
int
dlist_getlist
(
struct
dlist
*
dl
,
const
char
*
name
,
struct
dlist
**
val
)
{
struct
dlist
*
i
=
dlist_getchild
(
dl
,
name
);
if
(
!
i
)
return
0
;
*
val
=
i
;
return
1
;
}
const
char
*
dlist_lastkey
()
{
return
lastkey
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Fri, Apr 24, 2:24 PM (1 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18781191
Default Alt Text
dlist.c (14 KB)
Attached To
Mode
R111 cyrus-imapd
Attached
Detach File
Event Timeline