gwenhywfar 4.0.3
|
00001 /*************************************************************************** 00002 $RCSfile$ 00003 ------------------- 00004 cvs : $Id$ 00005 begin : Sun Nov 23 2003 00006 copyright : (C) 2003 by Martin Preuss 00007 email : martin@libchipcard.de 00008 00009 *************************************************************************** 00010 * * 00011 * This library is free software; you can redistribute it and/or * 00012 * modify it under the terms of the GNU Lesser General Public * 00013 * License as published by the Free Software Foundation; either * 00014 * version 2.1 of the License, or (at your option) any later version. * 00015 * * 00016 * This library is distributed in the hope that it will be useful, * 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 00019 * Lesser General Public License for more details. * 00020 * * 00021 * You should have received a copy of the GNU Lesser General Public * 00022 * License along with this library; if not, write to the Free Software * 00023 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * 00024 * MA 02111-1307 USA * 00025 * * 00026 ***************************************************************************/ 00027 00028 00029 #ifdef HAVE_CONFIG_H 00030 # include <config.h> 00031 #endif 00032 00033 00034 #include <gwenhywfar/directory.h> 00035 #include <gwenhywfar/debug.h> 00036 #include <gwenhywfar/path.h> 00037 #include <gwenhywfar/buffer.h> 00038 #include <gwenhywfar/text.h> 00039 00040 #ifdef HAVE_UNISTD_H 00041 # include <unistd.h> 00042 #endif 00043 #ifdef HAVE_SYS_STAT_H 00044 # include <sys/stat.h> 00045 #endif 00046 #include <sys/types.h> 00047 #ifdef HAVE_FCNTL_H 00048 # include <fcntl.h> 00049 #endif 00050 #include <string.h> 00051 #include <errno.h> 00052 #include <assert.h> 00053 #include <stdlib.h> 00054 #include <ctype.h> 00055 00056 #ifdef OS_WIN32 00057 # define DIRSEP "\\" 00058 #else 00059 # define DIRSEP "/" 00060 #endif 00061 00062 00063 00064 void *GWEN_Directory_HandlePathElement(const char *entry, 00065 void *data, 00066 unsigned int flags){ 00067 char *p; 00068 struct stat st; 00069 int exists; 00070 int withDrive; 00071 GWEN_BUFFER *buf; 00072 GWEN_BUFFER *ebuf = 0; 00073 const char *origEntry; 00074 00075 withDrive=0; 00076 origEntry=entry; 00077 00078 #ifdef OS_WIN32 00079 if (entry && isalpha(*entry)) { 00080 int len; 00081 00082 /* append backslash if entry only consists of a drive specification */ 00083 len=strlen(entry); 00084 if ( (len==2) && (entry[1] == ':') ) { 00085 ebuf=GWEN_Buffer_new(0, len+2, 0, 1); 00086 GWEN_Buffer_AppendString(ebuf, entry); 00087 GWEN_Buffer_AppendByte(ebuf, '\\'); 00088 withDrive=1; 00089 entry=GWEN_Buffer_GetStart(ebuf); 00090 } 00091 } 00092 #endif /* OS_WIN32 */ 00093 00094 if (strcasecmp(entry, "..")==0) { 00095 DBG_ERROR(GWEN_LOGDOMAIN, "\"..\" detected"); 00096 GWEN_Buffer_free(ebuf); 00097 return 0; 00098 } 00099 00100 buf=(GWEN_BUFFER*)data; 00101 if (GWEN_Buffer_GetUsedBytes(buf) && !withDrive) { 00102 char c; 00103 00104 c=GWEN_Buffer_GetStart(buf)[GWEN_Buffer_GetUsedBytes(buf)-1]; 00105 #ifdef OS_WIN32 00106 if (c!='\\') 00107 GWEN_Buffer_AppendByte(buf, '\\'); 00108 #else 00109 if (c!='/') 00110 GWEN_Buffer_AppendByte(buf, '/'); 00111 #endif /* OS_WIN32 */ 00112 } 00113 GWEN_Buffer_AppendString(buf, entry); 00114 00115 /* check for existence of the file/folder */ 00116 p=GWEN_Buffer_GetStart(buf); 00117 DBG_DEBUG(GWEN_LOGDOMAIN, "Checking path \"%s\"", p); 00118 if (stat(p, &st)) { 00119 exists=0; 00120 DBG_DEBUG(GWEN_LOGDOMAIN, "stat: %s (%s)", strerror(errno), p); 00121 if ((flags & GWEN_PATH_FLAGS_PATHMUSTEXIST) || 00122 ((flags & GWEN_PATH_FLAGS_LAST) && 00123 (flags & GWEN_PATH_FLAGS_NAMEMUSTEXIST))) { 00124 DBG_INFO(GWEN_LOGDOMAIN, "Path \"%s\" does not exist (it should)", p); 00125 GWEN_Buffer_free(ebuf); 00126 return 0; 00127 } 00128 } 00129 else { 00130 DBG_DEBUG(GWEN_LOGDOMAIN, "Checking for type"); 00131 exists=1; 00132 if (flags & GWEN_PATH_FLAGS_VARIABLE) { 00133 if (!S_ISREG(st.st_mode)) { 00134 DBG_INFO(GWEN_LOGDOMAIN, "%s not a regular file", p); 00135 GWEN_Buffer_free(ebuf); 00136 return 0; 00137 } 00138 } 00139 else { 00140 if (!S_ISDIR(st.st_mode)) { 00141 DBG_INFO(GWEN_LOGDOMAIN, "%s not a direcory", p); 00142 GWEN_Buffer_free(ebuf); 00143 return 0; 00144 } 00145 } 00146 if ((flags & GWEN_PATH_FLAGS_PATHMUSTNOTEXIST) || 00147 ((flags & GWEN_PATH_FLAGS_LAST) && 00148 (flags & GWEN_PATH_FLAGS_NAMEMUSTNOTEXIST))) { 00149 DBG_INFO(GWEN_LOGDOMAIN, "Path \"%s\" exists (it should not)", p); 00150 GWEN_Buffer_free(ebuf); 00151 return 0; 00152 } 00153 } /* if stat is ok */ 00154 00155 if (!exists) { 00156 int isPublic; 00157 00158 DBG_DEBUG(GWEN_LOGDOMAIN, "Entry \"%s\" does not exist", p); 00159 00160 isPublic=( 00161 ((flags & GWEN_PATH_FLAGS_LAST) && 00162 (flags & GWEN_DIR_FLAGS_PUBLIC_NAME)) || 00163 (!(flags & GWEN_PATH_FLAGS_LAST) && 00164 (flags & GWEN_DIR_FLAGS_PUBLIC_PATH)) 00165 ); 00166 00167 if (flags & GWEN_PATH_FLAGS_VARIABLE) { 00168 /* create file */ 00169 int fd; 00170 00171 DBG_DEBUG(GWEN_LOGDOMAIN, "Creating file \"%s\"", p); 00172 if (isPublic) 00173 fd=open(p, O_RDWR | O_CREAT | O_TRUNC, 00174 S_IRUSR | S_IWUSR 00175 #ifdef S_IRGRP 00176 | S_IRGRP 00177 #endif 00178 #ifdef S_IROTH 00179 | S_IROTH 00180 #endif 00181 ); 00182 else 00183 fd=open(p, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); 00184 if (fd==-1) { 00185 DBG_ERROR(GWEN_LOGDOMAIN, "open: %s (%s)", strerror(errno), p); 00186 GWEN_Buffer_free(ebuf); 00187 return 0; 00188 } 00189 close(fd); 00190 DBG_DEBUG(GWEN_LOGDOMAIN, "Sucessfully created"); 00191 } 00192 else { 00193 /* create dir */ 00194 DBG_DEBUG(GWEN_LOGDOMAIN, "Creating folder \"%s\"", p); 00195 00196 if (isPublic) { 00197 if (GWEN_Directory_CreatePublic(p)) { 00198 DBG_ERROR(GWEN_LOGDOMAIN, "Could not create directory \"%s\"", p); 00199 GWEN_Buffer_free(ebuf); 00200 return 0; 00201 } 00202 } 00203 else { 00204 if (GWEN_Directory_Create(p)) { 00205 DBG_ERROR(GWEN_LOGDOMAIN, "Could not create directory \"%s\"", p); 00206 GWEN_Buffer_free(ebuf); 00207 return 0; 00208 } 00209 } 00210 } 00211 } /* if exists */ 00212 else { 00213 DBG_DEBUG(GWEN_LOGDOMAIN, "Entry \"%s\" exists", p); 00214 } 00215 DBG_DEBUG(GWEN_LOGDOMAIN, "Returning this: %s", p); 00216 GWEN_Buffer_free(ebuf); 00217 return buf; 00218 } 00219 00220 00221 00222 int GWEN_Directory_GetPath(const char *path, 00223 unsigned int flags) { 00224 GWEN_BUFFER *buf; 00225 void *p; 00226 00227 assert(path); 00228 buf=GWEN_Buffer_new(0, strlen(path)+10, 0, 1); 00229 p=GWEN_Path_Handle(path, buf, 00230 flags | GWEN_PATH_FLAGS_CHECKROOT, 00231 GWEN_Directory_HandlePathElement); 00232 if (!p) { 00233 DBG_INFO(GWEN_LOGDOMAIN, "Path so far: \"%s\"", GWEN_Buffer_GetStart(buf)); 00234 GWEN_Buffer_free(buf); 00235 return -1; 00236 } 00237 GWEN_Buffer_free(buf); 00238 return 0; 00239 } 00240 00241 00242 00243 int GWEN_Directory_OsifyPath(const char *path, GWEN_BUFFER *pbuf, 00244 int transformDriveElement){ 00245 int len; 00246 const char *p; 00247 00248 len=strlen(path); 00249 p=path; 00250 00251 /* handle drive letters (only check for normal slashes here) */ 00252 #ifdef OS_WIN32 00253 if (transformDriveElement) { 00254 if (*p=='/') 00255 if (isalpha(p[1])) 00256 if (p[2]=='/' || p[2]==0) { 00257 GWEN_Buffer_AppendByte(pbuf, p[0]); 00258 GWEN_Buffer_AppendByte(pbuf, ':'); 00259 p+=2; 00260 } 00261 } 00262 #endif 00263 00264 while(*p) { 00265 if (*p=='/' || *p=='\\') { 00266 while (*p=='/' || *p=='\\') 00267 p++; 00268 #ifdef OS_WIN32 00269 GWEN_Buffer_AppendByte(pbuf, '\\'); 00270 #else 00271 GWEN_Buffer_AppendByte(pbuf, '/'); 00272 #endif 00273 } 00274 else { 00275 GWEN_Buffer_AppendByte(pbuf, *p); 00276 p++; 00277 } 00278 } 00279 00280 return 0; 00281 } 00282 00283 00284 00285 int GWEN_Directory_FindFileInPaths(const GWEN_STRINGLIST *paths, 00286 const char *filePath, 00287 GWEN_BUFFER *fbuf) { 00288 GWEN_STRINGLISTENTRY *se; 00289 00290 se=GWEN_StringList_FirstEntry(paths); 00291 while(se) { 00292 GWEN_BUFFER *tbuf; 00293 FILE *f; 00294 00295 tbuf=GWEN_Buffer_new(0, 256, 0, 1); 00296 GWEN_Buffer_AppendString(tbuf, GWEN_StringListEntry_Data(se)); 00297 GWEN_Buffer_AppendString(tbuf, DIRSEP); 00298 GWEN_Buffer_AppendString(tbuf, filePath); 00299 DBG_DEBUG(GWEN_LOGDOMAIN, "Trying \"%s\"", 00300 GWEN_Buffer_GetStart(tbuf)); 00301 f=fopen(GWEN_Buffer_GetStart(tbuf), "r"); 00302 if (f) { 00303 fclose(f); 00304 DBG_DEBUG(GWEN_LOGDOMAIN, 00305 "File \"%s\" found in folder \"%s\"", 00306 filePath, 00307 GWEN_StringListEntry_Data(se)); 00308 GWEN_Buffer_AppendBuffer(fbuf, tbuf); 00309 GWEN_Buffer_free(tbuf); 00310 return 0; 00311 } 00312 GWEN_Buffer_free(tbuf); 00313 00314 se=GWEN_StringListEntry_Next(se); 00315 } 00316 00317 DBG_INFO(GWEN_LOGDOMAIN, "File \"%s\" not found", filePath); 00318 return GWEN_ERROR_NOT_FOUND; 00319 } 00320 00321 00322 00323 int GWEN_Directory_FindPathForFile(const GWEN_STRINGLIST *paths, 00324 const char *filePath, 00325 GWEN_BUFFER *fbuf) { 00326 GWEN_STRINGLISTENTRY *se; 00327 00328 se=GWEN_StringList_FirstEntry(paths); 00329 while(se) { 00330 GWEN_BUFFER *tbuf; 00331 FILE *f; 00332 00333 tbuf=GWEN_Buffer_new(0, 256, 0, 1); 00334 GWEN_Buffer_AppendString(tbuf, GWEN_StringListEntry_Data(se)); 00335 GWEN_Buffer_AppendString(tbuf, DIRSEP); 00336 GWEN_Buffer_AppendString(tbuf, filePath); 00337 DBG_DEBUG(GWEN_LOGDOMAIN, "Trying \"%s\"", 00338 GWEN_Buffer_GetStart(tbuf)); 00339 f=fopen(GWEN_Buffer_GetStart(tbuf), "r"); 00340 if (f) { 00341 fclose(f); 00342 DBG_INFO(GWEN_LOGDOMAIN, 00343 "File \"%s\" found in folder \"%s\"", 00344 filePath, 00345 GWEN_StringListEntry_Data(se)); 00346 GWEN_Buffer_AppendString(fbuf, GWEN_StringListEntry_Data(se)); 00347 GWEN_Buffer_free(tbuf); 00348 return 0; 00349 } 00350 GWEN_Buffer_free(tbuf); 00351 00352 se=GWEN_StringListEntry_Next(se); 00353 } 00354 00355 DBG_INFO(GWEN_LOGDOMAIN, "File \"%s\" not found", filePath); 00356 return GWEN_ERROR_NOT_FOUND; 00357 } 00358 00359 00360 00361 int GWEN_Directory_GetTmpDirectory(char *buffer, unsigned int size) 00362 { 00363 const char *tmp_dir; 00364 assert(buffer); 00365 00366 /* Copied from http://svn.gnome.org/viewcvs/glib/trunk/glib/gutils.c */ 00367 tmp_dir = getenv ("TMPDIR"); 00368 if (!tmp_dir) 00369 tmp_dir = getenv ("TMP"); 00370 if (!tmp_dir) 00371 tmp_dir = getenv ("TEMP"); 00372 00373 if (!tmp_dir) 00374 { 00375 #ifdef OS_WIN32 00376 tmp_dir = "C:\\"; 00377 #else 00378 tmp_dir = "/tmp"; 00379 #endif /* !OS_WIN32 */ 00380 } 00381 00382 strncpy (buffer, tmp_dir, size); 00383 return 0; 00384 } 00385 00386 00387 00388 int GWEN_Directory_GetAllEntries(const char *folder, 00389 GWEN_STRINGLIST *sl, 00390 const char *mask) { 00391 GWEN_DIRECTORY *d; 00392 int rv; 00393 char buffer[256]; 00394 00395 d=GWEN_Directory_new(); 00396 rv=GWEN_Directory_Open(d, folder); 00397 if (rv<0) { 00398 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00399 GWEN_Directory_free(d); 00400 return rv; 00401 } 00402 00403 while(0==GWEN_Directory_Read(d, buffer, sizeof(buffer))) { 00404 if (strcmp(buffer, ".")!=0 && 00405 strcmp(buffer, "..")!=0 && 00406 (mask==NULL || 00407 GWEN_Text_ComparePattern(buffer+1, mask, 0)!=-1)) 00408 GWEN_StringList_AppendString(sl, buffer, 0, 1); 00409 } 00410 00411 GWEN_Directory_Close(d); 00412 GWEN_Directory_free(d); 00413 return 0; 00414 } 00415 00416 00417 00418 int GWEN_Directory_GetFileEntriesWithType(const char *folder, 00419 GWEN_STRINGLIST *sl, 00420 const char *mask) { 00421 GWEN_DIRECTORY *d; 00422 int rv; 00423 char buffer[256]; 00424 GWEN_BUFFER *pbuf; 00425 uint32_t pos; 00426 00427 d=GWEN_Directory_new(); 00428 rv=GWEN_Directory_Open(d, folder); 00429 if (rv<0) { 00430 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00431 GWEN_Directory_free(d); 00432 return rv; 00433 } 00434 00435 pbuf=GWEN_Buffer_new(0, 256, 0, 1); 00436 GWEN_Buffer_AppendString(pbuf, folder); 00437 GWEN_Buffer_AppendString(pbuf, GWEN_DIR_SEPARATOR_S); 00438 pos=GWEN_Buffer_GetPos(pbuf); 00439 00440 while(0==GWEN_Directory_Read(d, buffer+1, sizeof(buffer)-2)) { 00441 if (strcmp(buffer, ".")!=0 && 00442 strcmp(buffer, "..")!=0 && 00443 (mask==NULL || 00444 GWEN_Text_ComparePattern(buffer+1, mask, 0)!=-1)) { 00445 struct stat st; 00446 00447 GWEN_Buffer_AppendString(pbuf, buffer+1); 00448 if (stat(GWEN_Buffer_GetStart(pbuf), &st)==0) { 00449 if (S_ISREG(st.st_mode)) 00450 buffer[0]='f'; 00451 else if (S_ISDIR(st.st_mode)) 00452 buffer[0]='d'; 00453 else 00454 buffer[0]='?'; 00455 GWEN_StringList_AppendString(sl, buffer, 0, 1); 00456 } 00457 GWEN_Buffer_Crop(pbuf, 0, pos); 00458 } 00459 } 00460 00461 GWEN_Directory_Close(d); 00462 GWEN_Directory_free(d); 00463 return 0; 00464 } 00465 00466 00467 00468 00469 int GWEN_Directory_GetFileEntries(const char *folder, GWEN_STRINGLIST *sl, 00470 const char *mask) { 00471 GWEN_DIRECTORY *d; 00472 int rv; 00473 char buffer[256]; 00474 GWEN_BUFFER *pbuf; 00475 uint32_t pos; 00476 00477 d=GWEN_Directory_new(); 00478 rv=GWEN_Directory_Open(d, folder); 00479 if (rv<0) { 00480 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00481 GWEN_Directory_free(d); 00482 return rv; 00483 } 00484 00485 pbuf=GWEN_Buffer_new(0, 256, 0, 1); 00486 GWEN_Buffer_AppendString(pbuf, folder); 00487 GWEN_Buffer_AppendString(pbuf, GWEN_DIR_SEPARATOR_S); 00488 pos=GWEN_Buffer_GetPos(pbuf); 00489 00490 while(0==GWEN_Directory_Read(d, buffer, sizeof(buffer))) { 00491 if (strcmp(buffer, ".")!=0 && 00492 strcmp(buffer, "..")!=0 && 00493 (mask==NULL || 00494 GWEN_Text_ComparePattern(buffer+1, mask, 0)!=-1)) { 00495 struct stat st; 00496 00497 GWEN_Buffer_AppendString(pbuf, buffer); 00498 if (stat(GWEN_Buffer_GetStart(pbuf), &st)==0) { 00499 if (S_ISREG(st.st_mode)) 00500 GWEN_StringList_AppendString(sl, buffer, 0, 1); 00501 } 00502 GWEN_Buffer_Crop(pbuf, 0, pos); 00503 } 00504 } 00505 00506 GWEN_Buffer_free(pbuf); 00507 GWEN_Directory_Close(d); 00508 GWEN_Directory_free(d); 00509 return 0; 00510 } 00511 00512 00513 00514 int GWEN_Directory_GetDirEntries(const char *folder, GWEN_STRINGLIST *sl, 00515 const char *mask) { 00516 GWEN_DIRECTORY *d; 00517 int rv; 00518 char buffer[256]; 00519 GWEN_BUFFER *pbuf; 00520 uint32_t pos; 00521 00522 d=GWEN_Directory_new(); 00523 rv=GWEN_Directory_Open(d, folder); 00524 if (rv<0) { 00525 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00526 GWEN_Directory_free(d); 00527 return rv; 00528 } 00529 00530 pbuf=GWEN_Buffer_new(0, 256, 0, 1); 00531 GWEN_Buffer_AppendString(pbuf, folder); 00532 GWEN_Buffer_AppendString(pbuf, GWEN_DIR_SEPARATOR_S); 00533 pos=GWEN_Buffer_GetPos(pbuf); 00534 00535 while(0==GWEN_Directory_Read(d, buffer, sizeof(buffer))) { 00536 if (strcmp(buffer, ".")!=0 && 00537 strcmp(buffer, "..")!=0 && 00538 (mask==NULL || 00539 GWEN_Text_ComparePattern(buffer+1, mask, 0)!=-1)) { 00540 struct stat st; 00541 00542 GWEN_Buffer_AppendString(pbuf, buffer); 00543 if (stat(GWEN_Buffer_GetStart(pbuf), &st)==0) { 00544 if (S_ISDIR(st.st_mode)) 00545 GWEN_StringList_AppendString(sl, buffer, 0, 1); 00546 } 00547 GWEN_Buffer_Crop(pbuf, 0, pos); 00548 } 00549 } 00550 00551 GWEN_Directory_Close(d); 00552 GWEN_Directory_free(d); 00553 return 0; 00554 } 00555 00556 00557 00558 int GWEN_Directory_GetMatchingFilesRecursively(const char *folder, 00559 GWEN_STRINGLIST *sl, 00560 const char *mask) { 00561 GWEN_DIRECTORY *d; 00562 int rv; 00563 char buffer[256]; 00564 GWEN_BUFFER *pbuf; 00565 uint32_t pos; 00566 GWEN_STRINGLIST *folderList; 00567 00568 folderList=GWEN_StringList_new(); 00569 00570 d=GWEN_Directory_new(); 00571 rv=GWEN_Directory_Open(d, folder); 00572 if (rv<0) { 00573 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00574 GWEN_Directory_free(d); 00575 GWEN_StringList_free(folderList); 00576 return rv; 00577 } 00578 00579 pbuf=GWEN_Buffer_new(0, 256, 0, 1); 00580 GWEN_Buffer_AppendString(pbuf, folder); 00581 GWEN_Buffer_AppendString(pbuf, GWEN_DIR_SEPARATOR_S); 00582 pos=GWEN_Buffer_GetPos(pbuf); 00583 00584 while(0==GWEN_Directory_Read(d, buffer, sizeof(buffer)-2)) { 00585 if (strcmp(buffer, ".")!=0 && 00586 strcmp(buffer, "..")!=0 && 00587 (mask==NULL || 00588 GWEN_Text_ComparePattern(buffer, mask, 0)!=-1)) { 00589 struct stat st; 00590 00591 GWEN_Buffer_AppendString(pbuf, buffer); 00592 if (stat(GWEN_Buffer_GetStart(pbuf), &st)==0) { 00593 if (S_ISDIR(st.st_mode)) 00594 /* add folders to the folder list */ 00595 GWEN_StringList_AppendString(folderList, GWEN_Buffer_GetStart(pbuf), 0, 1); 00596 else 00597 GWEN_StringList_AppendString(sl, GWEN_Buffer_GetStart(pbuf), 0, 1); 00598 } 00599 GWEN_Buffer_Crop(pbuf, 0, pos); 00600 } 00601 } 00602 00603 GWEN_Directory_Close(d); 00604 GWEN_Directory_free(d); 00605 00606 if (GWEN_StringList_Count(folderList)) { 00607 GWEN_STRINGLISTENTRY *se; 00608 00609 se=GWEN_StringList_FirstEntry(folderList); 00610 while(se) { 00611 const char *s; 00612 00613 s=GWEN_StringListEntry_Data(se); 00614 if (s && *s) 00615 GWEN_Directory_GetMatchingFilesRecursively(s, sl, mask); 00616 se=GWEN_StringListEntry_Next(se); 00617 } 00618 } 00619 GWEN_StringList_free(folderList); 00620 GWEN_Buffer_free(pbuf); 00621 00622 return 0; 00623 } 00624 00625 00626 00627 00628