@@ -31,7 +31,7 @@ static void ResetUnloggedRelationsInDbspaceDir(const char *dbspacedirname,
31
31
32
32
typedef struct
33
33
{
34
- Oid reloid ; /* hash key */
34
+ RelFileNumber relnumber ; /* hash key */
35
35
} unlogged_relation_entry ;
36
36
37
37
/*
@@ -195,23 +195,22 @@ ResetUnloggedRelationsInDbspaceDir(const char *dbspacedirname, int op)
195
195
while ((de = ReadDir (dbspace_dir , dbspacedirname )) != NULL )
196
196
{
197
197
ForkNumber forkNum ;
198
- int relnumchars ;
198
+ unsigned segno ;
199
199
unlogged_relation_entry ent ;
200
200
201
201
/* Skip anything that doesn't look like a relation data file. */
202
- if (!parse_filename_for_nontemp_relation (de -> d_name , & relnumchars ,
203
- & forkNum ))
202
+ if (!parse_filename_for_nontemp_relation (de -> d_name ,
203
+ & ent .relnumber ,
204
+ & forkNum , & segno ))
204
205
continue ;
205
206
206
207
/* Also skip it unless this is the init fork. */
207
208
if (forkNum != INIT_FORKNUM )
208
209
continue ;
209
210
210
211
/*
211
- * Put the OID portion of the name into the hash table, if it
212
- * isn't already.
212
+ * Put the RelFileNumber into the hash table, if it isn't already.
213
213
*/
214
- ent .reloid = atooid (de -> d_name );
215
214
(void ) hash_search (hash , & ent , HASH_ENTER , NULL );
216
215
}
217
216
@@ -235,12 +234,13 @@ ResetUnloggedRelationsInDbspaceDir(const char *dbspacedirname, int op)
235
234
while ((de = ReadDir (dbspace_dir , dbspacedirname )) != NULL )
236
235
{
237
236
ForkNumber forkNum ;
238
- int relnumchars ;
237
+ unsigned segno ;
239
238
unlogged_relation_entry ent ;
240
239
241
240
/* Skip anything that doesn't look like a relation data file. */
242
- if (!parse_filename_for_nontemp_relation (de -> d_name , & relnumchars ,
243
- & forkNum ))
241
+ if (!parse_filename_for_nontemp_relation (de -> d_name ,
242
+ & ent .relnumber ,
243
+ & forkNum , & segno ))
244
244
continue ;
245
245
246
246
/* We never remove the init fork. */
@@ -251,7 +251,6 @@ ResetUnloggedRelationsInDbspaceDir(const char *dbspacedirname, int op)
251
251
* See whether the OID portion of the name shows up in the hash
252
252
* table. If so, nuke it!
253
253
*/
254
- ent .reloid = atooid (de -> d_name );
255
254
if (hash_search (hash , & ent , HASH_FIND , NULL ))
256
255
{
257
256
snprintf (rm_path , sizeof (rm_path ), "%s/%s" ,
@@ -285,14 +284,14 @@ ResetUnloggedRelationsInDbspaceDir(const char *dbspacedirname, int op)
285
284
while ((de = ReadDir (dbspace_dir , dbspacedirname )) != NULL )
286
285
{
287
286
ForkNumber forkNum ;
288
- int relnumchars ;
289
- char relnumbuf [ OIDCHARS + 1 ] ;
287
+ RelFileNumber relNumber ;
288
+ unsigned segno ;
290
289
char srcpath [MAXPGPATH * 2 ];
291
290
char dstpath [MAXPGPATH ];
292
291
293
292
/* Skip anything that doesn't look like a relation data file. */
294
- if (!parse_filename_for_nontemp_relation (de -> d_name , & relnumchars ,
295
- & forkNum ))
293
+ if (!parse_filename_for_nontemp_relation (de -> d_name , & relNumber ,
294
+ & forkNum , & segno ))
296
295
continue ;
297
296
298
297
/* Also skip it unless this is the init fork. */
@@ -304,11 +303,12 @@ ResetUnloggedRelationsInDbspaceDir(const char *dbspacedirname, int op)
304
303
dbspacedirname , de -> d_name );
305
304
306
305
/* Construct destination pathname. */
307
- memcpy (relnumbuf , de -> d_name , relnumchars );
308
- relnumbuf [relnumchars ] = '\0' ;
309
- snprintf (dstpath , sizeof (dstpath ), "%s/%s%s" ,
310
- dbspacedirname , relnumbuf , de -> d_name + relnumchars + 1 +
311
- strlen (forkNames [INIT_FORKNUM ]));
306
+ if (segno == 0 )
307
+ snprintf (dstpath , sizeof (dstpath ), "%s/%u" ,
308
+ dbspacedirname , relNumber );
309
+ else
310
+ snprintf (dstpath , sizeof (dstpath ), "%s/%u.%u" ,
311
+ dbspacedirname , relNumber , segno );
312
312
313
313
/* OK, we're ready to perform the actual copy. */
314
314
elog (DEBUG2 , "copying %s to %s" , srcpath , dstpath );
@@ -327,26 +327,27 @@ ResetUnloggedRelationsInDbspaceDir(const char *dbspacedirname, int op)
327
327
dbspace_dir = AllocateDir (dbspacedirname );
328
328
while ((de = ReadDir (dbspace_dir , dbspacedirname )) != NULL )
329
329
{
330
+ RelFileNumber relNumber ;
330
331
ForkNumber forkNum ;
331
- int relnumchars ;
332
- char relnumbuf [OIDCHARS + 1 ];
332
+ unsigned segno ;
333
333
char mainpath [MAXPGPATH ];
334
334
335
335
/* Skip anything that doesn't look like a relation data file. */
336
- if (!parse_filename_for_nontemp_relation (de -> d_name , & relnumchars ,
337
- & forkNum ))
336
+ if (!parse_filename_for_nontemp_relation (de -> d_name , & relNumber ,
337
+ & forkNum , & segno ))
338
338
continue ;
339
339
340
340
/* Also skip it unless this is the init fork. */
341
341
if (forkNum != INIT_FORKNUM )
342
342
continue ;
343
343
344
344
/* Construct main fork pathname. */
345
- memcpy (relnumbuf , de -> d_name , relnumchars );
346
- relnumbuf [relnumchars ] = '\0' ;
347
- snprintf (mainpath , sizeof (mainpath ), "%s/%s%s" ,
348
- dbspacedirname , relnumbuf , de -> d_name + relnumchars + 1 +
349
- strlen (forkNames [INIT_FORKNUM ]));
345
+ if (segno == 0 )
346
+ snprintf (mainpath , sizeof (mainpath ), "%s/%u" ,
347
+ dbspacedirname , relNumber );
348
+ else
349
+ snprintf (mainpath , sizeof (mainpath ), "%s/%u.%u" ,
350
+ dbspacedirname , relNumber , segno );
350
351
351
352
fsync_fname (mainpath , false);
352
353
}
@@ -371,52 +372,82 @@ ResetUnloggedRelationsInDbspaceDir(const char *dbspacedirname, int op)
371
372
* This function returns true if the file appears to be in the correct format
372
373
* for a non-temporary relation and false otherwise.
373
374
*
374
- * NB: If this function returns true, the caller is entitled to assume that
375
- * *relnumchars has been set to a value no more than OIDCHARS, and thus
376
- * that a buffer of OIDCHARS+1 characters is sufficient to hold the
377
- * RelFileNumber portion of the filename. This is critical to protect against
378
- * a possible buffer overrun.
375
+ * If it returns true, it sets *relnumber, *fork, and *segno to the values
376
+ * extracted from the filename. If it returns false, these values are set to
377
+ * InvalidRelFileNumber, InvalidForkNumber, and 0, respectively.
379
378
*/
380
379
bool
381
- parse_filename_for_nontemp_relation (const char * name , int * relnumchars ,
382
- ForkNumber * fork )
380
+ parse_filename_for_nontemp_relation (const char * name , RelFileNumber * relnumber ,
381
+ ForkNumber * fork , unsigned * segno )
383
382
{
384
- int pos ;
383
+ unsigned long n ,
384
+ s ;
385
+ ForkNumber f ;
386
+ char * endp ;
385
387
386
- /* Look for a non-empty string of digits (that isn't too long). */
387
- for (pos = 0 ; isdigit ((unsigned char ) name [pos ]); ++ pos )
388
- ;
389
- if (pos == 0 || pos > OIDCHARS )
388
+ * relnumber = InvalidRelFileNumber ;
389
+ * fork = InvalidForkNumber ;
390
+ * segno = 0 ;
391
+
392
+ /*
393
+ * Relation filenames should begin with a digit that is not a zero. By
394
+ * rejecting cases involving leading zeroes, the caller can assume that
395
+ * there's only one possible string of characters that could have produced
396
+ * any given value for *relnumber.
397
+ *
398
+ * (To be clear, we don't expect files with names like 0017.3 to exist at
399
+ * all -- but if 0017.3 does exist, it's a non-relation file, not part of
400
+ * the main fork for relfilenode 17.)
401
+ */
402
+ if (name [0 ] < '1' || name [0 ] > '9' )
403
+ return false;
404
+
405
+ /*
406
+ * Parse the leading digit string. If the value is out of range, we
407
+ * conclude that this isn't a relation file at all.
408
+ */
409
+ errno = 0 ;
410
+ n = strtoul (name , & endp , 10 );
411
+ if (errno || name == endp || n <= 0 || n > PG_UINT32_MAX )
390
412
return false;
391
- * relnumchars = pos ;
413
+ name = endp ;
392
414
393
415
/* Check for a fork name. */
394
- if (name [ pos ] != '_' )
395
- * fork = MAIN_FORKNUM ;
416
+ if (* name != '_' )
417
+ f = MAIN_FORKNUM ;
396
418
else
397
419
{
398
420
int forkchar ;
399
421
400
- forkchar = forkname_chars (& name [ pos + 1 ], fork );
422
+ forkchar = forkname_chars (name + 1 , & f );
401
423
if (forkchar <= 0 )
402
424
return false;
403
- pos += forkchar + 1 ;
425
+ name += forkchar + 1 ;
404
426
}
405
427
406
428
/* Check for a segment number. */
407
- if (name [pos ] == '.' )
429
+ if (* name != '.' )
430
+ s = 0 ;
431
+ else
408
432
{
409
- int segchar ;
433
+ /* Reject leading zeroes, just like we do for RelFileNumber. */
434
+ if (name [0 ] < '1' || name [0 ] > '9' )
435
+ return false;
410
436
411
- for ( segchar = 1 ; isdigit (( unsigned char ) name [ pos + segchar ]); ++ segchar )
412
- ;
413
- if (segchar <= 1 )
437
+ errno = 0 ;
438
+ s = strtoul ( name + 1 , & endp , 10 ) ;
439
+ if (errno || name + 1 == endp || s <= 0 || s > PG_UINT32_MAX )
414
440
return false;
415
- pos += segchar ;
441
+ name = endp ;
416
442
}
417
443
418
444
/* Now we should be at the end. */
419
- if (name [ pos ] != '\0' )
445
+ if (* name != '\0' )
420
446
return false;
447
+
448
+ /* Set out parameters and return. */
449
+ * relnumber = (RelFileNumber ) n ;
450
+ * fork = f ;
451
+ * segno = (unsigned ) s ;
421
452
return true;
422
453
}
0 commit comments